From b3d4898d9e8452ea0b8d848c048e712d43b8d9a3 Mon Sep 17 00:00:00 2001 From: Michael Lando Date: Sun, 11 Jun 2017 14:22:02 +0300 Subject: [PATCH] [SDC-29] rebase continue work to align source Change-Id: I218f1c5ee23fb2c8314f1c70921d3ad8682c10f4 Signed-off-by: Michael Lando --- asdc-tests/pom.xml | 2 +- .../java/org/openecomp/sdc/ci/tests/api/Urls.java | 2 +- .../attribute/ComponentInstanceAttributeTest.java | 8 +- .../execute/devCI/ValidateConformanceLevel.java | 29 +- .../FilteredDataByParamsComponentServletTest.java | 124 + .../execute/imports/ImportCsarResourceTest.java | 21 +- .../execute/imports/ImportNewResourceCITest.java | 7 +- .../execute/imports/ImportToscaResourceTest.java | 15 +- .../sdc/ci/tests/utils/rest/ResourceRestUtils.java | 46 + .../main/resources/ci/conf/attsdc-packages.yaml | 3 +- .../src/main/resources/ci/testSuites/ciFull.xml | 49 +- .../src/main/resources/ci/testSuites/resource.xml | 40 - .../src/main/resources/ci/testSuites/sanity.xml | 47 - .../normativeTypes/network/images/network.png | Bin 159707 -> 4214 bytes .../webApplication/images/network.png | Bin 159707 -> 4214 bytes .../CI/csars/vmmc_relate_by_cap_name.csar | Bin 35467 -> 35471 bytes asdctool/pom.xml | 22 + .../impl/EsToCassandraDataMigrationConfig.java | 7 +- .../sdc/asdctool/impl/TitanGraphInitializer.java | 268 +- .../{Migration.java => Migration1707Task.java} | 6 +- .../asdctool/impl/migration/v1604/AppConfig.java | 57 +- .../impl/migration/v1702/Migration1702.java | 2 - .../migration/v1707/DistributionStatusUpdate.java | 140 + .../impl/migration/v1707/Migration1707.java | 15 +- .../impl/migration/v1707/Migration1707Config.java | 101 +- .../migration/v1707/Migration1707RelationsFix.java | 131 + .../impl/migration/v1707/Migration1707VnfFix.java | 100 + .../migration/v1707/RenameGraphPropertyKeys.java | 6 +- .../impl/migration/v1707/ToscaNamesUpdate.java | 4 +- .../migration/v1707/ToscaTemplateRegeneration.java | 66 +- .../migration/v1707/VfModulesPropertiesAdding.java | 108 +- .../v1707/jsonmodel/ComponentMigration.java | 39 +- .../v1707/jsonmodel/ConsumersMigration.java | 47 + .../v1707/jsonmodel/InvariantUUIDResolver.java | 41 + .../v1707/jsonmodel/JsonModelMigration.java | 20 +- .../v1707/jsonmodel/NormativesMigration.java | 34 +- .../jsonmodel/ResourcesCategoriesMigration.java | 33 +- .../jsonmodel/ServiceCategoriesMigration.java | 11 +- .../v1707/jsonmodel/ServicesMigration.java | 121 +- .../v1707/jsonmodel/UserStatesMigration.java | 16 +- .../migration/v1707/jsonmodel/UsersMigration.java | 12 +- .../v1707/jsonmodel/VFResourcesMigration.java | 2 +- .../v1707/jsonmodel/VersionMigration.java | 40 +- .../openecomp/sdc/asdctool/main/MigrationMenu.java | 76 +- .../sdc/asdctool/main/SdcSchemaFileImport.java | 84 + .../src/main/resources/config/configuration.yaml | 4 +- asdctool/src/main/resources/config/groupTypes.yml | 15 +- asdctool/src/main/resources/config/logback.xml | 28 +- .../main/resources/scripts/dataMigration1707.sh | 2 +- .../scripts/distributionStatusUpdate1707.sh | 35 + .../resources/scripts/migration1707RelationsFix.sh | 33 + .../main/resources/scripts/retrieve_schema_file.sh | 20 + .../src/main/resources/scripts/vfmoduleFix1707.sh | 35 + catalog-be/pom.xml | 4 +- .../sdc/be/components/ArtifactsResolver.java | 27 + .../engine/JsonContainerResourceInstance.java | 7 + .../distribution/engine/NotificationDataImpl.java | 4 +- .../engine/VfModuleArtifactPayload.java | 2 + .../be/components/impl/ArtifactResolverImpl.java | 62 + .../be/components/impl/ArtifactsBusinessLogic.java | 109 +- .../be/components/impl/AttributeBusinessLogic.java | 32 +- .../be/components/impl/ComponentBusinessLogic.java | 93 +- .../impl/ComponentInstanceBusinessLogic.java | 42 +- .../be/components/impl/CsarValidationUtils.java | 2 +- .../be/components/impl/ElementBusinessLogic.java | 6 +- .../sdc/be/components/impl/GroupBusinessLogic.java | 1860 +++++------ .../sdc/be/components/impl/ImportUtils.java | 27 +- .../be/components/impl/InputsBusinessLogic.java | 21 +- .../be/components/impl/ResourceBusinessLogic.java | 85 +- .../be/components/impl/ResourceImportManager.java | 33 +- .../be/components/impl/ServiceBusinessLogic.java | 31 +- .../components/lifecycle/CheckoutTransition.java | 12 +- .../datamodel/utils/UiComponentDataConverter.java | 17 + .../org/openecomp/sdc/be/ecomp/EcompIntImpl.java | 27 +- .../converters}/AssetMetadataConverter.java | 3 +- .../be/externalapi/servlet/AssetsDataServlet.java | 1 + .../org/openecomp/sdc/be/impl/ComponentsUtils.java | 27 + .../sdc/be/listen/BEAppContextListener.java | 34 +- .../be/servlets/AbstractValidationsServlet.java | 2 +- .../sdc/be/servlets/AttributeServlet.java | 22 +- .../sdc/be/servlets/BeGenericServlet.java | 2 +- .../sdc/be/servlets/ComponentInstanceServlet.java | 8 +- .../sdc/be/servlets/ComponentServlet.java | 6 +- .../sdc/be/servlets/LifecycleServlet.java | 5 +- .../sdc/be/servlets/UserAdminServlet.java | 38 - .../java/org/openecomp/sdc/be/tosca/CsarUtils.java | 154 +- .../openecomp/sdc/be/tosca/ToscaExportHandler.java | 7 +- .../openecomp/sdc/be/user/IUserBusinessLogic.java | 4 - .../openecomp/sdc/be/user/UserBusinessLogic.java | 108 +- .../src/main/resources/application-context.xml | 2 +- catalog-be/src/main/resources/config/SDC.zip | Bin 29236 -> 30057 bytes .../main/resources/config/error-configuration.yaml | 10 +- catalog-be/src/main/resources/config/logback.xml | 4 +- .../import/tosca/data-types/dataTypes.yml | 13 + .../import/tosca/data-types/dataTypes.zip | Bin 5243 -> 5277 bytes .../components/impl/ArtifactBusinessLogicTest.java | 4 +- .../be/components/impl/ArtifactResolverTest.java | 91 + .../sdc/be/components/impl/ImportUtilsTest.java | 7 +- .../externalapi/servlet/AssetsDataServletTest.java | 1 + .../org/openecomp/sdc/be/dao/api/ActionStatus.java | 2 +- .../be/dao/cassandra/SdcSchemaFilesAccessor.java | 4 +- .../dao/cassandra/SdcSchemaFilesCassandraDao.java | 36 +- .../sdc/be/dao/jsongraph/types/VertexTypeEnum.java | 4 +- .../be/dao/neo4j/GraphPropertiesDictionary.java | 1 + .../sdc/be/resources/data/AttributeData.java | 12 +- .../be/resources/data/ComponentMetadataData.java | 2 + ...chemaFilesData.java => SdcSchemaFilesData.java} | 26 +- catalog-fe/pom.xml | 2 +- .../openecomp/sdc/fe/servlets/PortalServlet.java | 24 +- catalog-fe/src/main/resources/config/logback.xml | 4 +- .../CI/originalResources/images/network.png | Bin 159707 -> 4214 bytes .../java/org/openecomp/sdc/be/model/Component.java | 6 +- .../sdc/be/model/ComponentInstanceAttribute.java | 78 - .../sdc/be/model/ComponentInstanceInput.java | 18 +- .../sdc/be/model/ComponentInstanceProperty.java | 8 + .../openecomp/sdc/be/model/PropertyDefinition.java | 30 +- .../java/org/openecomp/sdc/be/model/Resource.java | 6 +- .../sdc/be/model/jsontitan/datamodel/NodeType.java | 8 +- .../jsontitan/datamodel/TopologyTemplate.java | 9 +- .../jsontitan/operations/ArtifactsOperations.java | 16 +- .../model/jsontitan/operations/BaseOperation.java | 50 +- .../operations/NodeTemplateOperation.java | 67 +- .../jsontitan/operations/NodeTypeOperation.java | 135 +- .../operations/TopologyTemplateOperation.java | 40 +- .../operations/ToscaElementLifecycleOperation.java | 906 +++-- .../operations/ToscaElementOperation.java | 204 +- .../jsontitan/operations/ToscaOperationFacade.java | 217 +- .../be/model/jsontitan/utils/ModelConverter.java | 28 +- .../model/operations/api/IAttributeOperation.java | 26 +- .../api/IComponentInstanceOperation.java | 7 +- .../model/operations/api/IConsumerOperation.java | 8 + .../model/operations/api/IResourceOperation.java | 5 - .../model/operations/api/IUserAdminOperation.java | 2 +- .../model/operations/impl/AttributeOperation.java | 96 +- .../impl/ComponentInstanceOperation.java | 41 +- .../model/operations/impl/ConsumerOperation.java | 16 +- .../model/operations/impl/ResourceOperation.java | 124 +- .../model/operations/impl/UserAdminOperation.java | 14 +- ...rmer.java => MigrationMalformedDataLogger.java} | 13 +- .../sdc/be/model/tosca/ToscaPropertyType.java | 2 + .../tosca/converters/ToscaMapValueConverter.java | 2 +- .../sdc/be/ui/model/UiComponentDataTransfer.java | 10 +- .../sdc/be/ui/model/UiComponentMetadata.java | 1 + .../sdc/be/ui/model/UiResourceDataTransfer.java | 9 +- .../sdc/be/ui/model/UiResourceMetadata.java | 3 + .../composition-graph.directive.ts | 3 +- .../property-types/type-map/type-map-directive.ts | 10 +- catalog-ui/src/app/models.ts | 3 + catalog-ui/src/app/models/components/component.ts | 16 +- .../app/models/graph/graph-links/links-factory.ts | 27 +- .../properties-inputs/derived-fe-property.ts | 75 +- .../app/models/properties-inputs/input-be-model.ts | 49 + .../app/models/properties-inputs/input-fe-model.ts | 24 +- .../models/properties-inputs/property-be-model.ts | 25 +- .../models/properties-inputs/property-fe-model.ts | 115 +- .../properties-inputs/simple-flat-property.ts | 15 + catalog-ui/src/app/models/property-fe-model.ts | 78 - catalog-ui/src/app/modules/view-model-module.ts | 2 +- catalog-ui/src/app/ng2/app.module.ts | 4 +- .../dynamic-element/dynamic-element.component.ts | 21 +- .../dynamic-element/dynamic-element.module.ts | 4 +- .../checkbox/ui-element-checkbox.component.html | 2 +- .../dropdown/ui-element-dropdown.component.html | 2 +- .../dropdown/ui-element-dropdown.component.ts | 3 +- .../input/ui-element-input.component.html | 2 + .../input/ui-element-input.component.ts | 3 +- .../ui-element-integer-input.component.html | 15 + .../ui-element-integer-input.component.less | 17 + .../ui-element-integer-input.component.ts | 21 + .../ui-element-popover-input.component.html | 4 +- .../ui-element-popover-input.component.ts | 3 +- .../elements-ui/ui-element-base.component.ts | 1 + .../filter-properties-assignment.component.less | 10 +- .../confirmation-delete-input.component.html | 3 + .../confirmation-delete-input.component.ts | 38 + .../inputs-table/inputs-table.component.html | 51 +- .../inputs-table/inputs-table.component.less | 178 + .../inputs-table/inputs-table.component.ts | 22 +- .../ng2/components/loader/loader.component.html | 5 + .../ng2/components/loader/loader.component.less | 75 + .../app/ng2/components/loader/loader.component.ts | 92 + .../app/ng2/components/modal/modal.component.html | 18 + .../app/ng2/components/modal/modal.component.less | 115 + .../app/ng2/components/modal/modal.component.ts | 46 + .../derived-property.component.html | 24 - .../derived-property.component.less | 35 - .../derived-property/derived-property.component.ts | 46 - .../dynamic-property.component.html | 73 +- .../dynamic-property.component.less | 46 +- .../dynamic-property/dynamic-property.component.ts | 164 +- .../list-property/list-property.component.html | 33 - .../list-property/list-property.component.less | 3 - .../list-property/list-property.component.ts | 85 - .../map-property/map-property.component.html | 38 - .../map-property/map-property.component.ts | 121 - .../properties-table.component.html | 121 +- .../properties-table.component.less | 127 +- .../properties-table/properties-table.component.ts | 16 +- .../properties-value-inner-table.component.html | 41 - .../properties-value-inner-table.component.less | 71 - .../properties-value-inner-table.component.ts | 37 - .../properties-assignment.module.ts | 22 +- .../properties-assignment.page.component.html | 51 +- .../properties-assignment.page.component.less | 6 + .../properties-assignment.page.component.ts | 345 +- .../properties-assignment/properties.utils.ts | 168 +- catalog-ui/src/app/ng2/pipes/searchFilter.pipe.ts | 5 +- .../src/app/ng2/services/component-mode.service.ts | 29 + .../services/component-services/service.service.ts | 2 +- .../src/app/ng2/services/data-type.service.ts | 12 +- .../src/app/ng2/services/hierarchy-nav.service.ts | 63 + .../src/app/ng2/services/properties.service.ts | 199 +- .../src/app/ng2/shared/tabs/tabs.component.less | 3 +- .../src/app/ng2/utils/ng1-upgraded-provider.ts | 22 + .../app/services/components/component-service.ts | 9 +- catalog-ui/src/app/utils/component-factory.ts | 1 + catalog-ui/src/app/utils/constants.ts | 5 +- catalog-ui/src/app/utils/modals-handler.ts | 2 +- .../forms/attribute-form/attribute-form-view.html | 4 +- .../property-form-view-model.ts | 2 +- .../conformance-level-modal-view-model.ts | 0 .../conformance-level-modal-view.html | 0 .../conformance-level-modal.less | 0 .../onboarding-modal/onboarding-modal-view.html | 12 +- .../tabs/composition/composition-view-model.ts | 4 + .../tabs/artifacts/artifacts-view-model.ts | 2 +- .../composition/tabs/artifacts/artifacts-view.html | 2 +- .../composition/tabs/details/details-view-model.ts | 5 +- .../properties-view-model.ts | 4 +- .../deployment-artifacts-view.html | 2 +- .../view-models/workspace/workspace-view-model.ts | 17 +- .../org/openecomp/sdc/be/config/Configuration.java | 9 + .../ComponentMetadataDataDefinition.java | 8 + .../elements/AttributeDataDefinition.java | 209 -- .../elements/ListCapabilityDataDefinition.java | 6 - .../be/datatypes/elements/ListDataDefinition.java | 18 +- .../elements/ListRequirementDataDefinition.java | 10 +- .../elements/MapAttributesDataDefinition.java | 45 - .../datatypes/elements/PropertyDataDefinition.java | 56 +- .../be/datatypes/enums/JsonPresentationFields.java | 33 +- .../be/datatypes/tosca/ToscaDataDefinition.java | 41 + .../dependency-reduced-pom.xml | 67 - .../sdc/generator/aai/AaiArtifactGenerator.java | 1 + .../generator/ArtifactGenerationServiceTest.java | 2 +- .../main/resources/globalTypes/openecomp/nodes.yml | 18 +- .../sdcrests/vsp/rest/VendorSoftwareProducts.java | 2 +- .../rest/services/VendorSoftwareProductsImpl.java | 280 +- .../impl/VendorLicenseManagerImpl.java | 27 +- .../VSPPackage.zip | Bin 33617 -> 0 bytes ...trationTemplateCandidateManagerFactoryImpl.java | 8 + .../OrchestrationTemplateCandidateManagerImpl.java | 166 +- .../impl/VendorSoftwareProductManagerImpl.java | 15 +- .../org/openecomp/sdc/common/errors/Messages.java | 2 +- .../openecomp-zusammen-api/pom.xml | 2 +- .../openecomp-zusammen-core/pom.xml | 8 +- .../openecomp-zusammen-plugin/pom.xml | 8 +- .../sdc/healing/healers/CompositionDataHealer.java | 4 +- .../artifact/ExternalArtifactEnricher.java | 6 +- .../external/artifact/ProcessArtifactEnricher.java | 5 +- .../tosca/AbstractSubstituteToscaEnricher.java | 1 + .../artifact/ProcessArtifactEnricherTest.java | 19 +- .../datatypes/heattotosca/TranslationContext.java | 27 + .../services/heattotosca/ConfigConstants.java | 3 + .../heattotosca/ConsolidationDataUtil.java | 27 +- .../heattotosca/UnifiedCompositionService.java | 240 +- .../FunctionTranslationGetAttrImpl.java | 2 +- .../main/resources/config-heatToToscaMapping.json | 2 +- .../resources/config-mandatory-unifiedModel.json | 11 + ...fiedCompositionNestedSingleComputeFullTest.java | 13 + .../OCS-fw2_service_instance1ServiceTemplate.yaml | 22 +- .../OCS-fw2_service_instance3ServiceTemplate.yaml | 22 +- .../OCS-fw3_service_instance4ServiceTemplate.yaml | 22 +- .../OCS-fw_service_instance1ServiceTemplate.yaml | 22 +- .../OCS-fw_service_instance2ServiceTemplate.yaml | 22 +- .../expectedoutputfiles/MainServiceTemplate.yaml | 76 +- .../OCS-fw2_service_instance1ServiceTemplate.yaml | 22 +- .../OCS-fw2_service_instance3ServiceTemplate.yaml | 22 +- .../OCS-fw3_service_instance4ServiceTemplate.yaml | 22 +- .../OCS-fw_service_instance1ServiceTemplate.yaml | 22 +- .../OCS-fw_service_instance2ServiceTemplate.yaml | 22 +- .../inputfiles/addOn.yml | 2 +- .../inputfiles/base.yml | 2 +- .../OCS-fw_service_instance_1ServiceTemplate.yaml | 22 +- .../OCS-fw_service_instance_2ServiceTemplate.yaml | 22 +- ....oam-fw_si_service_instanceServiceTemplate.yaml | 22 +- .../OCS-fw_service_instance_1ServiceTemplate.yaml | 22 +- .../OCS-fw_service_instance_2ServiceTemplate.yaml | 22 +- .../OCS-fw_service_instanceServiceTemplate.yaml | 22 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 174 +- .../out/MainServiceTemplate.yaml | 48 +- .../out/Nested_pd_server_0ServiceTemplate.yaml | 76 +- .../out/Nested_pd_server_1ServiceTemplate.yaml | 76 +- .../out/Nested_pd_server_2ServiceTemplate.yaml | 76 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 168 +- .../out/MainServiceTemplate.yaml | 64 +- .../out/Nested_pd_server_0ServiceTemplate.yaml | 69 +- .../out/Nested_pd_server_1ServiceTemplate.yaml | 69 +- .../out/Nested_pd_server_2ServiceTemplate.yaml | 69 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 174 +- .../out/MainServiceTemplate.yaml | 48 +- .../out/Nested_pd_server_0ServiceTemplate.yaml | 76 +- .../out/Nested_pd_server_1ServiceTemplate.yaml | 76 +- .../out/Nested_pd_server_2ServiceTemplate.yaml | 76 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 674 +++- .../out/MainServiceTemplate.yaml | 196 +- ...ested_1c1_scalling_instanceServiceTemplate.yaml | 141 +- ...sted_1c2_catalog_instance_0ServiceTemplate.yaml | 121 +- ...sted_1c2_catalog_instance_1ServiceTemplate.yaml | 119 +- .../out/Nested_a_single_1aServiceTemplate.yaml | 127 +- .../out/Nested_b_single_1b_0ServiceTemplate.yaml | 126 +- .../out/Nested_b_single_1b_1ServiceTemplate.yaml | 119 +- .../out/nested-pcm_v0.1ServiceTemplate.yaml | 150 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 632 +++- .../out/MainServiceTemplate.yaml | 182 +- ...ested_1c1_scalling_instanceServiceTemplate.yaml | 139 +- ...sted_1c2_catalog_instance_0ServiceTemplate.yaml | 119 +- ...sted_1c2_catalog_instance_1ServiceTemplate.yaml | 119 +- .../out/Nested_a_single_1aServiceTemplate.yaml | 127 +- .../out/Nested_b_single_1b_0ServiceTemplate.yaml | 130 +- .../out/Nested_b_single_1b_1ServiceTemplate.yaml | 119 +- .../out/nested-pcm_v0.1ServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 632 +++- .../out/MainServiceTemplate.yaml | 182 +- ...ested_1c1_scalling_instanceServiceTemplate.yaml | 139 +- ...sted_1c2_catalog_instance_0ServiceTemplate.yaml | 119 +- ...sted_1c2_catalog_instance_1ServiceTemplate.yaml | 119 +- .../out/Nested_a_single_1aServiceTemplate.yaml | 127 +- .../out/Nested_b_single_1b_0ServiceTemplate.yaml | 130 +- .../out/Nested_b_single_1b_1ServiceTemplate.yaml | 119 +- .../out/nested-pcm_v0.1ServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 1120 ++++++- .../out/MainServiceTemplate.yaml | 280 +- ...sted_1c11_scalling_instanceServiceTemplate.yaml | 76 +- ...sted_1c12_scalling_instanceServiceTemplate.yaml | 72 +- ...sted_1c2_catalog_instance_0ServiceTemplate.yaml | 121 +- ...sted_1c2_catalog_instance_1ServiceTemplate.yaml | 119 +- ...sted_1c2_catalog_instance_2ServiceTemplate.yaml | 119 +- ...sted_1c2_catalog_instance_3ServiceTemplate.yaml | 119 +- .../out/Nested_a_single_1aServiceTemplate.yaml | 127 +- .../out/Nested_a_single_2aServiceTemplate.yaml | 74 +- .../out/Nested_b_single_1b_0ServiceTemplate.yaml | 119 +- .../out/Nested_b_single_1b_1ServiceTemplate.yaml | 126 +- .../out/Nested_b_single_2b_0ServiceTemplate.yaml | 123 +- .../out/Nested_b_single_2b_1ServiceTemplate.yaml | 136 +- .../out/nested-pcm_v0.1ServiceTemplate.yaml | 150 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 120 + .../out/nested-pcm_v0.1ServiceTemplate.yaml | 90 + .../out/nested-pcm_v0.2ServiceTemplate.yaml | 90 + .../out/Nested_jsaServiceTemplate.yaml | 171 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 188 +- .../out/nested-oam_v0.1ServiceTemplate.yaml | 138 +- .../out/nested-pcm_v0.1ServiceTemplate.yaml | 138 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 152 +- .../out/nested-oam_v0.1ServiceTemplate.yaml | 90 + .../out/nested-pcm_v0.1ServiceTemplate.yaml | 138 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 152 +- .../out/nested-oam_v0.1ServiceTemplate.yaml | 90 + .../out/nested-pcm_v0.1ServiceTemplate.yaml | 138 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 + .../out/nested-pcm_v0.1ServiceTemplate.yaml | 90 + .../in/MANIFEST.json | 21 + .../in/hot-nimbus-pcm_v0.4.env | 14 + .../in/hot-nimbus-pcm_v0.4.yaml | 103 + .../in/nested-pcm_v0.1.yaml | 101 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 855 +++++ .../out/MainServiceTemplate.yaml | 243 ++ .../out/Nested_computeServiceTemplate.yaml | 203 ++ .../out/nested-pcm_v0.1ServiceTemplate.yaml | 470 +++ .../in/hot-nimbus-pcm_v0.4.yaml | 4 +- .../in/nested-pcm_v0.1.yaml | 8 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 328 +- .../out/MainServiceTemplate.yaml | 54 +- .../out/nested-pcm_v0.1ServiceTemplate.yaml | 516 +-- .../GlobalSubstitutionTypesServiceTemplate.yaml | 180 + .../out/nested-pcm_v0.1ServiceTemplate.yaml | 90 + .../out/nested-pcm_v0.2ServiceTemplate.yaml | 90 + .../out/nested-pcm_v0.3ServiceTemplate.yaml | 92 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 120 + .../out/nested-pcm_v0.1ServiceTemplate.yaml | 90 + .../out/nested-pcm_v0.2ServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 + .../out/nested-pcm_v0.1ServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 +- .../out/MainServiceTemplate.yaml | 30 +- .../out/Nested_pd_serverServiceTemplate.yaml | 78 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 +- .../out/MainServiceTemplate.yaml | 30 +- .../out/Nested_pd_serverServiceTemplate.yaml | 78 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 +- .../out/MainServiceTemplate.yaml | 34 +- .../out/Nested_pd_serverServiceTemplate.yaml | 78 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 58 +- .../out/MainServiceTemplate.yaml | 24 +- .../out/Nested_pd_serverServiceTemplate.yaml | 76 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 66 +- .../out/MainServiceTemplate.yaml | 36 +- .../out/Nested_pd_serverServiceTemplate.yaml | 82 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 +- .../out/MainServiceTemplate.yaml | 30 +- .../out/Nested_pd_serverServiceTemplate.yaml | 78 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 64 +- .../out/MainServiceTemplate.yaml | 36 +- .../out/Nested_pd_serverServiceTemplate.yaml | 82 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 +- .../out/MainServiceTemplate.yaml | 30 +- .../out/Nested_pd_serverServiceTemplate.yaml | 78 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 106 +- .../out/MainServiceTemplate.yaml | 38 +- .../out/Nested_pd_serverServiceTemplate.yaml | 78 +- .../out/Nested_ps_serverServiceTemplate.yaml | 64 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 106 +- .../out/MainServiceTemplate.yaml | 38 +- .../out/Nested_pd_serverServiceTemplate.yaml | 78 +- .../out/Nested_ps_serverServiceTemplate.yaml | 64 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 + .../out/Nested_pd_serverServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 58 +- .../out/MainServiceTemplate.yaml | 20 +- .../out/Nested_smpServiceTemplate.yaml | 74 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 102 +- .../out/MainServiceTemplate.yaml | 14 +- .../out/Nested_pd_serverServiceTemplate.yaml | 128 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 104 +- .../out/MainServiceTemplate.yaml | 10 +- .../out/Nested_pd_serverServiceTemplate.yaml | 136 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 98 +- .../out/MainServiceTemplate.yaml | 26 +- .../out/Nested_pd_serverServiceTemplate.yaml | 124 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 98 +- .../out/MainServiceTemplate.yaml | 22 +- .../out/Nested_pd_serverServiceTemplate.yaml | 132 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 152 +- .../out/Nested_pd_serverServiceTemplate.yaml | 90 + .../out/nested-pcm_v0.1ServiceTemplate.yaml | 138 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 + .../out/Nested_pd_serverServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 + .../out/Nested_pd_serverServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 1376 ++++++-- .../generalVf/out/MainServiceTemplate.yaml | 282 +- .../generalVf/out/Nested_FSB1ServiceTemplate.yaml | 181 +- .../generalVf/out/Nested_FSB2ServiceTemplate.yaml | 185 +- .../generalVf/out/Nested_GPB1ServiceTemplate.yaml | 144 +- .../generalVf/out/Nested_GPB2ServiceTemplate.yaml | 124 +- .../generalVf/out/Nested_NCB1ServiceTemplate.yaml | 134 +- .../generalVf/out/Nested_NCB2ServiceTemplate.yaml | 134 +- .../generalVf/out/Nested_VLC1ServiceTemplate.yaml | 361 +- .../generalVf/out/Nested_VLC2ServiceTemplate.yaml | 341 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 + .../out/Nested_pd_serverServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 66 + .../out/Nested_pd_serverServiceTemplate.yaml | 99 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 66 + .../out/Nested_pd_serverServiceTemplate.yaml | 99 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 + .../out/Nested_pd_serverServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 60 + .../out/Nested_pd_serverServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 196 +- .../out/MainServiceTemplate.yaml | 60 +- .../out/Nested_oam_serverServiceTemplate.yaml | 67 +- .../out/Nested_pd_serverServiceTemplate.yaml | 79 +- .../out/Nested_ps_serverServiceTemplate.yaml | 90 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 176 +- .../out/MainServiceTemplate.yaml | 46 +- .../out/Nested_oam_serverServiceTemplate.yaml | 63 +- .../out/Nested_pd_serverServiceTemplate.yaml | 69 +- .../out/Nested_ps_serverServiceTemplate.yaml | 88 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 172 +- .../out/MainServiceTemplate.yaml | 48 +- .../out/Nested_pd_server_0ServiceTemplate.yaml | 76 +- .../out/Nested_pd_server_1ServiceTemplate.yaml | 76 +- .../out/Nested_pd_server_2ServiceTemplate.yaml | 69 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 174 +- .../out/MainServiceTemplate.yaml | 40 +- .../out/Nested_pd_server_0ServiceTemplate.yaml | 69 +- .../out/Nested_pd_server_1ServiceTemplate.yaml | 76 +- .../out/Nested_pd_server_2ServiceTemplate.yaml | 90 + .../GlobalSubstitutionTypesServiceTemplate.yaml | 98 +- .../out/MainServiceTemplate.yaml | 28 +- .../out/Nested_pd_serverServiceTemplate.yaml | 69 +- .../out/Nested_ps_serverServiceTemplate.yaml | 55 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 98 +- .../twoSetsOfSingle/out/MainServiceTemplate.yaml | 24 +- .../out/Nested_pd_serverServiceTemplate.yaml | 69 +- .../out/Nested_ps_serverServiceTemplate.yaml | 55 +- .../expectedoutputfiles/MainServiceTemplate.yaml | 2 +- .../FEAdd_On_Module_QRouterTemplate.yaml | 8 +- .../inputfiles/FEBase_Module.yaml | 2 +- ...d_On_Module_QRouterTemplateServiceTemplate.yaml | 360 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 218 +- .../out/MainServiceTemplate.yaml | 176 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 212 +- .../out/SubstitutionServiceTemplate.yaml | 306 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 2 +- .../NoPorts/out/SubstitutionServiceTemplate.yaml | 2 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 160 +- .../WithIndex/out/SubstitutionServiceTemplate.yaml | 232 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 108 +- .../out/SubstitutionServiceTemplate.yaml | 154 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 160 +- .../out/SubstitutionServiceTemplate.yaml | 232 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 104 +- .../out/SubstitutionServiceTemplate.yaml | 152 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 158 +- .../out/SubstitutionServiceTemplate.yaml | 230 +- .../out/MainServiceTemplate.yaml | 14 +- .../out/MainServiceTemplate.yaml | 14 +- .../out/MainServiceTemplate.yaml | 18 +- .../noConsolidation/out/MainServiceTemplate.yaml | 6 +- .../consolidation/out/MainServiceTemplate.yaml | 18 +- .../noConsolidation/out/MainServiceTemplate.yaml | 18 +- .../consolidation/out/MainServiceTemplate.yaml | 18 +- .../noConsolidation/out/MainServiceTemplate.yaml | 8 +- .../consolidation/out/MainServiceTemplate.yaml | 18 +- .../noConsolidation/out/MainServiceTemplate.yaml | 14 +- .../consolidation/out/MainServiceTemplate.yaml | 18 +- .../noConsolidation/out/MainServiceTemplate.yaml | 14 +- .../nested_with_inner_vol/inputfiles/main.yml | 2 +- .../nested_with_inner_vol/inputfiles/nested.yml | 4 +- .../GlobalSubstitutionTypesServiceTemplate.yaml | 152 +- .../out/MainServiceTemplate.yaml | 4 +- .../out/nestedServiceTemplate.yaml | 262 +- .../impl/zusammen/FeatureGroupDaoZusammenImpl.java | 15 +- .../zusammen/LicenseAgreementDaoZusammenImpl.java | 9 +- .../sdc/vendorsoftwareproduct/dao/MibDao.java | 2 + .../dao/impl/zusammen/MibDaoZusammenImpl.java | 32 + .../OrchestrationTemplateDaoZusammenImpl.java | 6 +- .../dao/impl/zusammen/ProcessDaoZusammenImpl.java | 3 + .../impl/TxtInformationArtifactGeneratorImpl.java | 2 +- .../sdc/tosca/services/ToscaAnalyzerService.java | 4 + .../services/impl/ToscaAnalyzerServiceImpl.java | 4 +- .../schemaTemplates/questionnaire/component.ftl | 1 - .../tools/migration/1702_to_1707_zusammen/pom.xml | 2 +- .../openecomp/core/migration/MigrationMain.java | 5 +- .../scss/components/_sequenceDiagram.scss | 17 +- .../resources/scss/modules/_workflows.scss | 16 - .../src/nfvo-components/input/validation/Form.jsx | 14 + .../sdc-app/onboarding/OnboardingActionHelper.js | 8 +- .../featureGroups/FeatureGroupEditorView.jsx | 14 +- .../LicenseAgreementEditorView.jsx | 24 +- .../attachments/SoftwareProductAttachments.js | 4 +- .../attachments/SoftwareProductAttachmentsView.jsx | 2 +- .../SoftwareProductComponentEditorReducer.js | 1 + .../SoftwareProductComponentsActionHelper.js | 10 +- .../dependencies/SoftwareProductDependencies.js | 2 +- pom.xml | 1 + sdc-os-chef/pom.xml | 4 +- .../cookbooks/sdc-catalog-be/attributes/default.rb | 4 +- .../cookbooks/sdc-catalog-be/files/default/user.py | 25 +- .../files/default/titan.properties | 6 - .../templates/default/create_dox_keyspace.sh.erb | 28 +- test-apis-ci/.gitignore | 4 + test-apis-ci/pom.xml | 381 +++ .../org/openecomp/sdc/ci/tests/api/AttSdcTest.java | 200 ++ .../sdc/ci/tests/api/ComponentBaseTest.java | 607 ++++ .../ci/tests/api/ComponentInstanceBaseTest.java | 764 +++++ .../openecomp/sdc/ci/tests/api/ExtentManager.java | 72 + .../sdc/ci/tests/api/ExtentTestManager.java | 56 + .../java/org/openecomp/sdc/ci/tests/api/Urls.java | 368 ++ .../org/openecomp/sdc/ci/tests/config/Config.java | 696 ++++ .../sdc/ci/tests/config/InvokedMethodListener.java | 63 + .../ci/tests/datatypes/ArtifactAssetStructure.java | 135 + .../sdc/ci/tests/datatypes/ArtifactReqDetails.java | 243 ++ .../sdc/ci/tests/datatypes/AssetStructure.java | 122 + .../datatypes/ComponentInstanceReqDetails.java | 121 + .../ci/tests/datatypes/ComponentReqDetails.java | 272 ++ .../sdc/ci/tests/datatypes/CsarArtifacts.java | 59 + .../tests/datatypes/GroupHeatMetaDefinition.java | 86 + .../datatypes/HeatMetaFirstLevelDefinition.java | 76 + .../sdc/ci/tests/datatypes/ImportReqDetails.java | 335 ++ .../sdc/ci/tests/datatypes/ProductReqDetails.java | 88 + .../datatypes/PropertyHeatMetaDefinition.java | 63 + .../sdc/ci/tests/datatypes/PropertyReqDetails.java | 145 + .../ci/tests/datatypes/ResourceAssetStructure.java | 76 + .../datatypes/ResourceDetailedAssetStructure.java | 71 + .../datatypes/ResourceExternalReqDetails.java | 105 + .../datatypes/ResourceInstanceAssetStructure.java | 116 + .../sdc/ci/tests/datatypes/ResourceReqDetails.java | 220 ++ .../ci/tests/datatypes/ResourceRespJavaObject.java | 369 ++ .../ci/tests/datatypes/ServiceAssetStructure.java | 49 + .../datatypes/ServiceDetailedAssetStructure.java | 78 + .../tests/datatypes/ServiceDistributionStatus.java | 80 + .../sdc/ci/tests/datatypes/ServiceReqDetails.java | 91 + .../ci/tests/datatypes/ServiceRespJavaObject.java | 268 ++ .../ci/tests/datatypes/TypeHeatMetaDefinition.java | 57 + .../ci/tests/datatypes/enums/ArtifactTypeEnum.java | 77 + .../sdc/ci/tests/datatypes/enums/AssocType.java | 39 + .../sdc/ci/tests/datatypes/enums/AuditEnum.java | 39 + .../tests/datatypes/enums/AuditJsonKeysEnum.java | 40 + .../ci/tests/datatypes/enums/ComponentType.java | 37 + .../enums/DistributionNotificationStatusEnum.java | 52 + .../sdc/ci/tests/datatypes/enums/ErrorInfo.java | 93 + .../datatypes/enums/EsIndexTypeIdToDelete.java | 64 + .../tests/datatypes/enums/ExceptionEnumType.java | 36 + .../tests/datatypes/enums/ImportTestTypesEnum.java | 95 + .../tests/datatypes/enums/LifeCycleStatesEnum.java | 77 + .../enums/MandatoryResourceArtifactTypeEnum.java | 49 + .../enums/MandatoryServiceArtifactTypeEnum.java | 66 + .../tests/datatypes/enums/NormativeTypesEnum.java | 45 + .../ci/tests/datatypes/enums/OriginTypeEnum.java | 74 + .../ci/tests/datatypes/enums/PropertyTypeEnum.java | 107 + .../datatypes/enums/ResourceCategoryEnum.java | 57 + .../ci/tests/datatypes/enums/RespJsonKeysEnum.java | 40 + .../tests/datatypes/enums/SearchCriteriaEnum.java | 38 + .../datatypes/enums/ServiceApiArtifactEnum.java | 35 + .../datatypes/enums/ServiceCategoriesEnum.java | 37 + .../ci/tests/datatypes/enums/ToscaKeysEnum.java | 46 + .../sdc/ci/tests/datatypes/enums/UserRoleEnum.java | 77 + .../datatypes/expected/ExpectedArtifactAudit.java | 166 + .../expected/ExpectedAuthenticationAudit.java | 90 + .../datatypes/expected/ExpectedCategoryAudit.java | 151 + .../expected/ExpectedDistDownloadAudit.java | 79 + .../expected/ExpectedEcomConsumerAudit.java | 88 + .../datatypes/expected/ExpectedExternalAudit.java | 179 + .../expected/ExpectedGetUserListAudit.java | 88 + .../datatypes/expected/ExpectedGroupingAudit.java | 121 + .../datatypes/expected/ExpectedProductAudit.java | 142 + .../expected/ExpectedResourceAuditJavaObject.java | 311 ++ .../datatypes/expected/ExpectedUserCRUDAudit.java | 98 + .../sdc/ci/tests/datatypes/http/HeaderData.java | 114 + .../sdc/ci/tests/datatypes/http/HeaderValue.java | 38 + .../ci/tests/datatypes/http/HttpHeaderEnum.java | 58 + .../sdc/ci/tests/datatypes/http/HttpRequest.java | 889 +++++ .../sdc/ci/tests/datatypes/http/MustHeaders.java | 53 + .../sdc/ci/tests/datatypes/http/RestResponse.java | 84 + .../execute/TODO/ImportCapabilityTypeCITest.java | 135 + .../execute/artifacts/ArtifactServletTest.java | 658 ++++ .../sdc/ci/tests/execute/artifacts/CrudArt.java | 1799 ++++++++++ .../execute/artifacts/DownloadComponentArt.java | 665 ++++ .../tests/execute/artifacts/HeatEnvArtifact.java | 192 ++ .../execute/artifacts/PlaceHolderValidations.java | 704 ++++ .../execute/artifacts/ValidateArtResponse.java | 632 ++++ .../artifacts/ValidateHeatArtFieldsTypes.java | 177 + .../attribute/ComponentInstanceAttributeTest.java | 94 + .../tests/execute/category/CatalogDataApiTest.java | 236 ++ .../tests/execute/category/CategoriesBaseTest.java | 49 + .../ci/tests/execute/category/CategoriesTests.java | 2303 +++++++++++++ .../ci/tests/execute/category/ElementsApiTest.java | 148 + .../ci/tests/execute/category/GroupingTest.java | 2007 +++++++++++ .../tests/execute/category/SubCategoriesTest.java | 1908 +++++++++++ .../sdc/ci/tests/execute/devCI/AndreyTest.java | 104 + .../ci/tests/execute/devCI/ArtifactFromCsar.java | 301 ++ .../ci/tests/execute/devCI/ImportCsarUpdate.java | 362 ++ .../execute/devCI/ImportCsarValidateArtifacts.java | 108 + .../ci/tests/execute/devCI/ToscaGroupInsideVF.java | 580 ++++ .../sdc/ci/tests/execute/devCI/test1.java | 96 + .../execute/distribution/AuthanticationTests.java | 186 ++ .../DistributionDownloadArtifactTest.java | 537 +++ .../execute/externalapi/DownloadArtifactsTest.java | 385 +++ .../general/BasicHttpAuthenticationTest.java | 442 +++ .../sdc/ci/tests/execute/general/FeProxyTest.java | 53 + .../general/ManageEcompConsumerCredentials.java | 1420 ++++++++ .../sdc/ci/tests/execute/general/UuidTest.java | 104 + .../ci/tests/execute/imports/CsarUtilsTest.java | 460 +++ .../ci/tests/execute/imports/ExportToscaTest.java | 458 +++ .../execute/imports/ImportCsarResourceTest.java | 1751 ++++++++++ .../imports/ImportGenericResourceCITest.java | 600 ++++ .../execute/imports/ImportNewResourceCITest.java | 1529 +++++++++ .../ImportToscaCapabilitiesWithProperties.java | 416 +++ .../execute/imports/ImportToscaResourceTest.java | 2896 ++++++++++++++++ .../imports/ImportUpdateResourseCsarTest.java | 283 ++ .../ci/tests/execute/inputs/InputsApiTests.java | 225 ++ .../ci/tests/execute/lifecycle/LCSbaseTest.java | 274 ++ .../product/ChangeServiceInstanceVersionTest.java | 0 .../ci/tests/execute/product/ProductBaseTest.java | 0 .../tests/execute/product/ProductCheckinTest.java | 0 .../tests/execute/product/ProductCheckoutTest.java | 0 .../product/ProductComponentInstanceCRUDTest.java | 18 +- .../product/ProductCreateWithValidationsTest.java | 235 +- .../ci/tests/execute/product/ProductCrudTest.java | 1066 ++++-- .../execute/product/ProductGetFollowedTest.java | 0 .../execute/product/ProductLifecycleTest.java | 0 .../ci/tests/execute/product/ProductTestBase.java | 0 .../product/ProductToscaYamlGenerationTest.java | 0 .../execute/product/ProductUndoCheckoutTest.java | 0 .../property/AdditionalInformationServletTest.java | 2021 +++++++++++ .../property/ComponentInstancePropertyTest.java | 1263 +++++++ .../tests/execute/property/ComponentProperty.java | 1796 ++++++++++ .../tests/execute/property/PropertyApisTest.java | 384 +++ .../tests/execute/resource/CheckGetResource.java | 53 + .../resource/ComponentRelationshipInVfTest.java | 1408 ++++++++ .../execute/resource/CreateResourceApiTest.java | 2222 ++++++++++++ .../execute/resource/GetAllResourceVersions.java | 582 ++++ .../resource/GetResourceNotAbstractApiTest.java | 328 ++ .../ci/tests/execute/resource/ResourceApiTest.java | 372 +++ .../tests/execute/resource/SampleDataProvider.java | 41 + .../execute/resource/SimultaneousApiTest.java | 124 + .../resource/UpdateResourceMetadataTest.java | 2650 +++++++++++++++ .../resource/VFResourceInstanceNameCRUD.java | 481 +++ .../execute/resource/ValidateExtendedVfData.java | 319 ++ .../resource/VfComponentInstanceCRUDTest.java | 1792 ++++++++++ .../ChangeServiceDistributionStatusApiTest.java | 1012 ++++++ .../service/CreateServiceMetadataApiTest.java | 1304 ++++++++ .../execute/service/GetAllServiceVersions.java | 351 ++ .../execute/service/GetComponentAuditApiTest.java | 371 ++ .../service/GetServiceLatestVersionTest.java | 685 ++++ .../execute/service/ReqCapOccurrencesTest.java | 1191 +++++++ .../service/ServiceComponentInstanceCRUDTest.java | 1627 +++++++++ .../execute/service/UpdateServiceMetadataTest.java | 2158 ++++++++++++ .../execute/user/ActivateDeActivateDeleteUser.java | 756 +++++ .../ci/tests/execute/user/CreateUserApiTest.java | 1693 ++++++++++ .../execute/user/GovernorWorkspaceApiTest.java | 319 ++ .../distributionClient/ClientConfiguration.java | 141 + .../preRequisites/ComplexResourceBaseTest.java | 177 + .../preRequisites/DownloadArtifactBaseTest.java | 125 + .../preRequisites/SimpleOneRsrcOneServiceTest.java | 96 + .../sdc/ci/tests/rules/MyTestWatcher.java | 82 + .../org/openecomp/sdc/ci/tests/run/StartTest.java | 279 ++ .../sdc/ci/tests/run/StartTest2backup.java | 408 +++ .../org/openecomp/sdc/ci/tests/sanity/CrudE2E.java | 287 ++ .../ci/tests/sanity/MultipleResourceUpdate.java | 131 + .../tosca/datatypes/ParametersDefinition.java | 105 + .../ToscaCapabilitiesNodeTemplatesDefinition.java | 25 + .../ci/tests/tosca/datatypes/ToscaDefinition.java | 120 + .../datatypes/ToscaGroupsMetadataDefinition.java | 84 + .../ToscaGroupsTopologyTemplateDefinition.java | 126 + .../tosca/datatypes/ToscaImportsDefinition.java | 81 + .../ToscaInputsTopologyTemplateDefinition.java | 45 + ...scaNodeTemplatesTopologyTemplateDefinition.java | 174 + .../tosca/datatypes/ToscaNodeTypesDefinition.java | 141 + .../ToscaOutputsTopologyTemplateDefinition.java | 49 + .../ToscaPoliciesTopologyTemplateDefinition.java | 67 + ...ionshipTemplatesTopologyTemplateDefinition.java | 79 + .../ToscaRequirementsNodeTemplatesDefinition.java | 59 +- .../ToscaSubstitutionMappingsDefinition.java | 71 + .../datatypes/ToscaTopologyTemplateDefinition.java | 135 + .../ToscaTopologyTemplateDefinition2.java | 78 + .../ci/tests/users/AddUserAuditMessageInfo.java | 113 + .../sdc/ci/tests/users/UserAuditJavaObject.java | 133 + .../sdc/ci/tests/users/UserHeaderData.java | 59 + .../ci/tests/users/UserResponseMessageEnum.java | 39 + .../sdc/ci/tests/users/WebSealUserDetails.java | 74 + .../sdc/ci/tests/utils/ArtifactUtils.java | 43 + .../sdc/ci/tests/utils/CsarParserUtils.java | 174 + .../org/openecomp/sdc/ci/tests/utils/DbUtils.java | 293 ++ .../org/openecomp/sdc/ci/tests/utils/Decoder.java | 62 + .../sdc/ci/tests/utils/DistributionUtils.java | 144 + .../org/openecomp/sdc/ci/tests/utils/ReqCap.java | 630 ++++ .../sdc/ci/tests/utils/ToscaParserUtils.java | 361 ++ .../org/openecomp/sdc/ci/tests/utils/Utils.java | 689 ++++ .../ci/tests/utils/cassandra/CassandraUtils.java | 220 ++ .../ci/tests/utils/cassandra/CassandraUtils2.java | 166 + .../tests/utils/general/AtomicOperationUtils.java | 732 ++++ .../sdc/ci/tests/utils/general/Convertor.java | 344 ++ .../sdc/ci/tests/utils/general/ElementFactory.java | 997 ++++++ .../sdc/ci/tests/utils/general/FileUtils.java | 137 + .../sdc/ci/tests/utils/general/ImportUtils.java | 63 + .../sdc/ci/tests/utils/rest/ArtifactRestUtils.java | 934 ++++++ .../sdc/ci/tests/utils/rest/AssetRestUtils.java | 626 ++++ .../sdc/ci/tests/utils/rest/AutomationUtils.java | 110 + .../sdc/ci/tests/utils/rest/BaseRestUtils.java | 265 ++ .../sdc/ci/tests/utils/rest/CatalogRestUtils.java | 93 + .../sdc/ci/tests/utils/rest/CategoryRestUtils.java | 309 ++ .../utils/rest/ComponentInstanceRestUtils.java | 276 ++ .../ci/tests/utils/rest/ComponentRestUtils.java | 62 + .../sdc/ci/tests/utils/rest/ConsumerRestUtils.java | 245 ++ .../ci/tests/utils/rest/EcompUserRestUtils.java | 253 ++ .../sdc/ci/tests/utils/rest/GroupRestUtils.java | 61 + .../sdc/ci/tests/utils/rest/ImportRestUtils.java | 408 +++ .../sdc/ci/tests/utils/rest/InputsRestUtils.java | 122 + .../ci/tests/utils/rest/LifecycleRestUtils.java | 451 +++ .../sdc/ci/tests/utils/rest/ProductRestUtils.java | 196 ++ .../sdc/ci/tests/utils/rest/PropertyRestUtils.java | 310 ++ .../sdc/ci/tests/utils/rest/ResourceRestUtils.java | 679 ++++ .../utils/rest/ResourceRestUtilsExternalAPI.java | 64 + .../sdc/ci/tests/utils/rest/ResponseParser.java | 605 ++++ .../sdc/ci/tests/utils/rest/ServiceRestUtils.java | 296 ++ .../sdc/ci/tests/utils/rest/UserRestUtils.java | 299 ++ .../utils/validation/ArtifactValidationUtils.java | 226 ++ .../utils/validation/AuditValidationUtils.java | 1418 ++++++++ .../utils/validation/BaseValidationUtils.java | 117 + .../utils/validation/CategoryValidationUtils.java | 125 + .../utils/validation/CsarValidationUtils.java | 488 +++ .../validation/DistributionValidationUtils.java | 86 + .../utils/validation/ErrorValidationUtils.java | 120 + .../utils/validation/ProductValidationUtils.java | 239 ++ .../utils/validation/ResourceValidationUtils.java | 358 ++ .../utils/validation/ServiceValidationUtils.java | 130 + .../utils/validation/UserValidationUtils.java | 279 ++ .../sdc/ci/tests/webSealAccess/NeoJavaObject.java | 111 + .../openecomp/sdc/externalApis/AssetLifeCycle.java | 1146 +++++++ .../sdc/externalApis/CRUDExternalAPI.java | 3528 ++++++++++++++++++++ .../sdc/externalApis/DeploymentValiditaion.java | 428 +++ .../sdc/externalApis/GetAssetServlet.java | 343 ++ .../openecomp/sdc/externalApis/GetCSARofVF.java | 262 ++ .../sdc/externalApis/GetFilteredAssetServlet.java | 712 ++++ .../GetSpecificAssetMetadataServlet.java | 447 +++ .../SearchFilterCategoryExternalAPI.java | 329 ++ .../org/openecomp/sdc/externalApis/UserAPIs.java | 556 +++ .../sdc/externalApis/VFCMTExternalAPI.java | 396 +++ .../main/java/org/openecomp/sdc/post/Install.java | 70 + .../main/resources/ci/conf/attsdc-packages.yaml | 12 + .../src/main/resources/ci/conf/attsdc.yaml | 93 + .../src/main/resources/ci/conf/extent-config.xml | 51 + .../src/main/resources/ci/conf/log4j.properties | 34 + test-apis-ci/src/main/resources/ci/conf/log4j.xml | 32 + .../src/main/resources/ci/conf/testngLifeCycle.xml | 27 + .../src/main/resources/ci/conf/titan.properties | 8 + test-apis-ci/src/main/resources/ci/conf/truststore | Bin 0 -> 971 bytes .../resources/ci/scripts/addUsersFromList_new.sh | 75 + .../src/main/resources/ci/scripts/copyToStorage.sh | 66 + .../src/main/resources/ci/scripts/sendMail.sh | 46 + .../src/main/resources/ci/scripts/startTest.sh | 153 + .../src/main/resources/ci/scripts/userList.txt | 1 + .../main/resources/ci/testSuites/CRUDArtifacts.xml | 40 + .../resources/ci/testSuites/SearchExternalAPI.xml | 23 + .../src/main/resources/ci/testSuites/artifacts.xml | 19 + .../src/main/resources/ci/testSuites/category.xml | 11 + .../src/main/resources/ci/testSuites/ciFull.xml | 221 ++ .../main/resources/ci/testSuites/externalAPIs.xml | 31 + .../src/main/resources/ci/testSuites/general.xml | 11 + .../src/main/resources/ci/testSuites/imports.xml | 12 + .../src/main/resources/ci/testSuites/product.xml | 0 .../main/resources/ci/testSuites/productAPIs.xml | 20 + .../src/main/resources/ci/testSuites/property.xml | 11 + .../src/main/resources/ci/testSuites/resource.xml | 360 ++ .../src/main/resources/ci/testSuites/sanity.xml | 394 +++ .../src/main/resources/ci/testSuites/service.xml | 15 + .../resources/ci/testSuites/testngLifeCycle.xml | 27 + .../src/main/resources/ci/testSuites/user.xml | 18 + test-apis-ci/src/main/resources/log4j.properties | 34 + test-apis-ci/src/main/resources/log4j.xml | 32 + test-apis-ci/src/main/resources/logback.xml | 25 + .../resources/CI/ecomp-error-configuration.yaml | 383 +++ .../src/test/resources/CI/error-configuration.yaml | 1778 ++++++++++ .../CI/importTypesTest/categoryTypesTest.yml | 23 + .../CI/importTypesTest/categoryTypesTest.zip | Bin 0 -> 333 bytes .../importTypesTest/myHeatStack1/myHeatStack1.yml | 13 + .../importTypesTest/myHeatStack1/myHeatStack1.zip | Bin 0 -> 400 bytes .../importTypesTest/myHeatStack2/myHeatStack2.yml | 14 + .../importTypesTest/myHeatStack2/myHeatStack2.zip | Bin 0 -> 423 bytes .../src/test/resources/CI/other/mapping.json | 182 + .../addYangXmlArtifactToResource.xml | 32 + .../HeatDeploymentArtifacts/asc_heat 0 2.yaml | 787 +++++ .../tests/HeatDeploymentArtifacts/asc_heat 0 2.zip | Bin 0 -> 2420 bytes .../HeatDeploymentArtifacts/asc_heat_net 0 2.yaml | 787 +++++ .../tests/HeatDeploymentArtifacts/heatEnvfile.env | 787 +++++ .../HeatDeploymentArtifacts/heatInvalidFormat.yaml | 9 + .../tests/HeatDeploymentArtifacts/heat_mini.yaml | 13 + .../tests/HeatDeploymentArtifacts/invalidJson.json | 11 + .../HeatDeploymentArtifacts/invalidYamlFormat.yaml | 787 +++++ .../HeatDeploymentArtifacts/invalidYangXml.xml | 35 + .../HeatDeploymentArtifacts/jsonArtifact.json | 22 + .../CI/tests/HeatDeploymentArtifacts/other.txt | 3 + .../bluePrintSampleArtifact.xml | 3 + .../docSampleArtifact.docx | Bin 0 -> 11307 bytes .../emfSampleArtifact.emf | 2 + .../emfSampleArtifact.xml | 3 + .../eventSampleArtifact.xml | 3 + .../jsonSampleArtifact.json | 3 + .../toscaSampleArtifact.yml | 5 + .../asc_heat 0 2.yaml | 787 +++++ .../org.openstack.Rally.zip | Bin 0 -> 11590 bytes .../images/mysql.png | Bin 0 -> 63119 bytes .../getResourceArtifactFileContentTest/mysql.yml | 85 + .../scripts/install_mysql.sh | 28 + .../scripts/start_mysql.sh | 105 + .../getResourceArtifactListNoContentTest/mysql.yml | 85 + .../getResourceArtifactListTest/images/mysql.png | Bin 0 -> 63119 bytes .../CI/tests/getResourceArtifactListTest/mysql.yml | 85 + .../scripts/install_mysql.sh | 28 + .../scripts/start_mysql.sh | 105 + .../mysql.yml | 85 + .../images/mysql.png | Bin 0 -> 63119 bytes .../getResourceArtifactMetadataTest/mysql.yml | 85 + .../scripts/install_mysql.sh | 28 + .../scripts/start_mysql.sh | 105 + .../mysql.yml | 85 + .../resource1/images/mysql.png | Bin 0 -> 63119 bytes .../resource1/mysql.yml | 85 + .../resource1/scripts/install_mysql.sh | 28 + .../resource1/scripts/start_mysql.sh | 105 + .../resource2/images/mysql.png | Bin 0 -> 63119 bytes .../resource2/mysql.yml | 85 + .../resource2/scripts/install_mysql2.sh | 28 + .../resource2/scripts/start_mysql2.sh | 105 + .../topology.txt | 1 + .../topologyTemplate.txt | 2 + .../resource1/images/mysql.png | Bin 0 -> 63119 bytes .../resource1/mysql.yml | 85 + .../resource2/images/mysql.png | Bin 0 -> 63119 bytes .../resource2/mysql.yml | 85 + .../topology.txt | 1 + .../topologyTemplate.txt | 2 + .../resource1/images/mysql.png | Bin 0 -> 63119 bytes .../getServiceArtifactListTest/resource1/mysql.yml | 85 + .../resource1/scripts/install_mysql.sh | 28 + .../resource1/scripts/start_mysql.sh | 105 + .../resource2/images/mysql.png | Bin 0 -> 63119 bytes .../getServiceArtifactListTest/resource2/mysql.yml | 85 + .../resource2/scripts/install_mysql2.sh | 28 + .../resource2/scripts/start_mysql2.sh | 105 + .../tests/getServiceArtifactListTest/topology.txt | 1 + .../topologyTemplate.txt | 2 + .../Service1/resource1/images/mysql.png | Bin 0 -> 63119 bytes .../Service1/resource1/mysql.yml | 85 + .../Service1/resource1/scripts/install_mysql.sh | 28 + .../Service1/resource1/scripts/start_mysql.sh | 105 + .../Service1/resource2/images/mysql.png | Bin 0 -> 63119 bytes .../Service1/resource2/mysql.yml | 85 + .../Service1/resource2/scripts/install_mysql2.sh | 28 + .../Service1/resource2/scripts/start_mysql2.sh | 105 + .../tests/getServiceListTest/Service1/topology.txt | 1 + .../Service1/topologyTemplate.txt | 2 + .../Service2/resource1/images/mysql.png | Bin 0 -> 63119 bytes .../Service2/resource1/mysql.yml | 85 + .../Service2/resource2/images/mysql.png | Bin 0 -> 63119 bytes .../Service2/resource2/mysql.yml | 85 + .../tests/getServiceListTest/Service2/topology.txt | 1 + .../Service2/topologyTemplate.txt | 2 + .../heatWithParamsMissingDefault.yaml | 603 ++++ .../heatWithParamsMissingDesc.yaml | 603 ++++ .../heatWithParamsMissingType.yaml | 603 ++++ .../heatWithValidParams.yaml | 787 +++++ .../resources/CI/tests/heatEnv/artifact_1.yaml | 144 + .../resources/CI/tests/heatEnv/artifact_2.yaml | 469 +++ .../src/test/resources/CI/tests/heatEnv/yuli.yaml | 144 + .../BindingAsset.yml | 14 + .../CPHasNoReqCap.yml | 9 + .../CPHasNoReqCap_DerivedFromMyCompute1.yml | 9 + .../CPWithAttributes.yml | 56 + .../CaseInsensitiveCapTest_1.yml | 34 + .../CaseInsensitiveCapTest_2.yml | 34 + .../CaseInsensitiveReqTest_1.yml | 34 + .../CaseInsensitiveReqTest_2.yml | 34 + .../DerivedFromCPWithOwnReq.yml | 14 + .../DerivedFromWebApplication_HasNoReqType.yml | 27 + .../DifferentCapFromRoot.yml | 26 + .../DifferentReqAndCap.yml | 34 + .../DifferentReqCapFromCompute1.yml | 22 + .../DifferentReqCapFromCompute2.yml | 25 + .../DifferentReqFromCompute.yml | 32 + .../FatherHasNoReqCap.yml | 9 + .../ListPropertyFalure01.yml | 17 + .../ListPropertyFalure02.yml | 17 + .../ListPropertyFalure03.yml | 17 + .../ListPropertyFalure04.yml | 17 + .../ListPropertyFalure05.yml | 17 + .../ListPropertyFalure06.yml | 17 + .../ListPropertyFalure07.yml | 17 + .../ListPropertyFalure08.yml | 17 + .../ListPropertyFalure09.yml | 17 + .../ListPropertyFalure10.yml | 17 + .../ListPropertyFalure11.yml | 17 + .../ListPropertyFalure12.yml | 17 + .../ListPropertyFalure13.yml | 17 + .../ListPropertyFalure14.yml | 18 + .../ListPropertyFalure15.yml | 19 + .../ListPropertyFalure16.yml | 17 + .../MapPropertyFalure01.yml | 17 + .../MapPropertyFalure02.yml | 17 + .../MapPropertyFalure03.yml | 17 + .../MapPropertyFalure04.yml | 17 + .../MapPropertyFalure05.yml | 17 + .../MapPropertyFalure06.yml | 17 + .../MapPropertyFalure07.yml | 17 + .../MapPropertyFalure08.yml | 17 + .../MapPropertyFalure09.yml | 17 + .../MapPropertyFalure10.yml | 17 + .../MapPropertyFalure11.yml | 17 + .../MapPropertyFalure12.yml | 17 + .../MapPropertyFalure13.yml | 17 + .../MapPropertyFalure14.yml | 18 + .../MapPropertyFalure15.yml | 19 + .../MapPropertyFalure16.yml | 17 + .../MyFatherCompute_NoReqCap.yml | 17 + .../SameCapAsCompute.yml | 26 + .../SameReqAsCompute.yml | 23 + .../SameReqAsCompute_DerivedFromMyCompute1.yml | 23 + .../computeCap11.yml | 35 + .../computeCap1UNBOUNDED.yml | 35 + .../derivedFromMyCompute.yml | 35 + .../derivedFromWebAppDerivedReqCap.yml | 15 + .../importAttributeSuccessFlow.yml | 53 + .../importCapabilityNameExistsOnParent.yml | 35 + .../importDuplicateCapability.yml | 42 + .../importDuplicateRequirements.yml | 40 + .../importListPropertyBadDefault.yml | 17 + .../importListPropertyGoodDefault.yml | 17 + .../importListPropertySuccessFlow.yml | 198 ++ .../importMapPropertySuccessFlow.yml | 452 +++ .../importRequirementNameExistsOnParent.yml | 34 + ...entNameExistsOnParent_DerivedFromMyCompute1.yml | 34 + .../missingCapInCapDefinition.yml | 37 + .../missingCapInReqDefinition.yml | 25 + .../myChildCompute_NoReqCap.yml | 17 + .../myChildWebApp_DerivedFromContainer.yml | 15 + .../importToscaResourceByCreateUrl/myCompute.yml | 35 + .../myComputeDerivedFromNotExists.yml | 35 + .../myComputeIncorrectDefenitionVersionValue.yml | 35 + .../myComputeIncorrectNameSpaceFormat.yml | 35 + .../myComputeNoDefenitionVersion.yml | 34 + .../myComputeOccurencySuccess.yml | 77 + .../myComputeParssingFalure.yml | 35 + .../myComputeReqNameExistsOnDerived.yml | 34 + .../importToscaResourceByCreateUrl/myComputeVF.yml | 35 + .../myComputeWithNodeTypesTwice.yml | 42 + .../myComputeWithTopologyTemplate.yml | 44 + .../myFatherWebApp_derviedFromDocker.yml | 16 + .../importToscaResourceByCreateUrl/myLinkVL.yml | 35 + .../importToscaResourceByCreateUrl/myPortCP.yml | 35 + .../importToscaResourceByCreateUrl/noContent.yml | 0 .../occurencyFalure01.yml | 35 + .../occurencyFalure02.yml | 35 + .../occurencyFalure03.yml | 35 + .../occurencyFalure04.yml | 35 + .../occurencyFalure05.yml | 35 + .../occurencyFalure06.yml | 35 + .../occurencyFalure07.yml | 35 + .../occurencyFalure08.yml | 35 + .../occurencyFalure09.yml | 35 + .../occurencyFalure10.yml | 35 + .../occurencyFalure11.yml | 35 + .../occurencyFalure31.yml | 35 + .../occurencyFalure32.yml | 35 + .../occurencyFalure33.yml | 35 + .../occurencyFalure34.yml | 35 + .../occurencyFalure35.yml | 35 + .../occurencyFalure36.yml | 35 + .../occurencyFalure37.yml | 35 + .../occurencyFalure38.yml | 35 + .../occurencyFalure39.yml | 35 + .../occurencyFalure40.yml | 35 + .../occurencyFalure41.yml | 35 + .../softwareComponentReq11.yml | 17 + .../softwareComponentReq12.yml | 17 + .../resources/CI/tests/testCsarAPI/topology.txt | 1 + .../CI/tests/testCsarAPI/topologyTemplate.txt | 1 + .../tests/tmp/positive_artifact_bool10_false.yaml | 140 + .../tests/tmp/positive_artifact_bool11_false.yaml | 140 + .../tests/tmp/positive_artifact_bool12_false.yaml | 140 + .../CI/tests/tmp/positive_artifact_bool1_true.yaml | 140 + .../CI/tests/tmp/positive_artifact_bool2_true.yaml | 140 + .../CI/tests/tmp/positive_artifact_bool3_true.yaml | 140 + .../CI/tests/tmp/positive_artifact_bool4_true.yaml | 140 + .../CI/tests/tmp/positive_artifact_bool5_true.yaml | 140 + .../CI/tests/tmp/positive_artifact_bool6_true.yaml | 140 + .../tests/tmp/positive_artifact_bool7_false.yaml | 140 + .../tests/tmp/positive_artifact_bool8_false.yaml | 140 + .../tests/tmp/positive_artifact_bool9_false.yaml | 140 + .../CI/tests/tmp/positive_artifact_number1.yaml | 140 + .../CI/tests/tmp/positive_artifact_number2.yaml | 140 + .../CI/tests/uploadComponent/images/mysql.png | Bin 0 -> 63119 bytes .../resources/CI/tests/uploadComponent/mysql.yml | 85 + .../tests/uploadComponent/scripts/install_mysql.sh | 28 + .../tests/uploadComponent/scripts/start_mysql.sh | 105 + .../yamlFieldsValidation/artifact_unsupported.yaml | 140 + .../negative_artifact_bool1.yaml | 140 + .../negative_artifact_bool2.yaml | 140 + .../negative_artifact_number1.yaml | 140 + .../negative_artifact_number2.yaml | 140 + .../negative_artifact_string1.yaml | 140 + test-apis-ci/src/test/resources/config.json | 12 + test-apis-ci/src/test/resources/logback-test.xml | 13 + test-apis-ci/testng.xml | 15 + test-apis-ci/testngLifeCycle.xml | 27 + test-apis-ci/tmpCSAR | Bin 0 -> 1844 bytes ui-ci-dev/.gitignore | 2 + ui-ci-dev/pom.xml | 287 ++ .../sdc/uici/scripts/CreateVfsFromOnboarding.java | 67 + .../sdc/uici/tests/datatypes/CanvasElement.java | 33 + .../sdc/uici/tests/datatypes/CanvasManager.java | 206 ++ .../sdc/uici/tests/datatypes/CleanTypeEnum.java | 28 + .../datatypes/CreateAndImportButtonsEnum.java | 7 + .../tests/datatypes/CreateAndUpdateStepsEnum.java | 25 + .../sdc/uici/tests/datatypes/DataTestIdEnum.java | 477 +++ .../sdc/uici/tests/datatypes/MenuOptionsEnum.java | 17 + .../sdc/uici/tests/datatypes/UserCredentials.java | 29 + .../sdc/uici/tests/execute/base/SetupCDTest.java | 419 +++ .../tests/execute/generalTests/GeneralTests.java | 26 + .../tests/execute/service/ServiceBasicTests.java | 147 + .../tests/execute/service/ServiceInputsTests.java | 124 + .../sdc/uici/tests/execute/vf/VfBasicTests.java | 333 ++ .../sdc/uici/tests/execute/vf/VfCanvasTests.java | 80 + .../uici/tests/execute/vf/VfDeploymentTests.java | 340 ++ .../uici/tests/execute/vf/VfOnboardingTests.java | 63 + .../sdc/uici/tests/execute/vfc/VfcBasicTests.java | 270 ++ .../openecomp/sdc/uici/tests/run/StartTest.java | 252 ++ .../sdc/uici/tests/utilities/ArtifactUIUtils.java | 70 + .../sdc/uici/tests/utilities/FileHandling.java | 30 + .../sdc/uici/tests/utilities/GeneralUIUtils.java | 344 ++ .../tests/utilities/MethodManipulationUtils.java | 15 + .../sdc/uici/tests/utilities/OnboardUtility.java | 477 +++ .../sdc/uici/tests/utilities/ResourceUIUtils.java | 299 ++ .../sdc/uici/tests/utilities/RestCDUtils.java | 167 + .../sdc/uici/tests/utilities/ServiceUIUtils.java | 147 + .../uici/tests/verificator/ServiceVerificator.java | 55 + .../uici/tests/verificator/VerificatorUtil.java | 27 + .../sdc/uici/tests/verificator/VfVerificator.java | 143 + .../main/resources/ci/conf/attsdc-packages.yaml | 2 + ui-ci-dev/src/main/resources/ci/conf/attsdc.yaml | 80 + .../src/main/resources/ci/conf/credentials.yaml | 48 + .../src/main/resources/ci/conf/log4j.properties | 34 + .../src/main/resources/ci/conf/titan.properties | 7 + .../src/main/resources/ci/scripts/startTest.sh | 123 + .../src/main/resources/ci/testSuites/fullTests.xml | 26 + .../src/main/resources/ci/testSuites/sanity.xml | 55 + ui-ci-dev/src/main/resources/images/gizmorambo.jpg | Bin 0 -> 16605 bytes ui-ci-dev/src/test/Completetheform.js | 3 + ui-ci/.gitignore | 2 + ui-ci/hs_err_pid10052.log | 389 +++ ui-ci/pom.xml | 357 ++ .../US/AddComponentInstancesArtifactsInCsar.java | 415 +++ ...portUpdateInformationalDeploymentArtifacts.java | 343 ++ .../java/org/openecomp/sdc/ci/tests/US/Inputs.java | 226 ++ .../sdc/ci/tests/US/LocalGeneralUtilities.java | 99 + .../tests/US/MIBsArtifactsOnResourceInstance.java | 269 ++ .../org/openecomp/sdc/ci/tests/US/MobProxy.java | 144 + .../sdc/ci/tests/US/NewArtifactTypeGuide.java | 123 + .../US/RemoveRestrictionOfDeploymentArtifacts.java | 117 + .../sdc/ci/tests/US/Service_Tests_UI.java | 107 + .../org/openecomp/sdc/ci/tests/US/Testing.java | 125 + .../org/openecomp/sdc/ci/tests/US/VfModule.java | 156 + .../org/openecomp/sdc/ci/tests/US/Vf_Tests_UI.java | 94 + ...ndNode_TemplatePropertiesWithDefaultValues.java | 299 ++ .../tests/businesslogic/ArtifactBusinessLogic.java | 208 ++ .../sdc/ci/tests/datatypes/ArtifactInfo.java | 105 + .../sdc/ci/tests/datatypes/CanvasElement.java | 65 + .../sdc/ci/tests/datatypes/CanvasManager.java | 268 ++ .../tests/datatypes/CatalogFilterTitlesEnum.java | 37 + .../sdc/ci/tests/datatypes/CheckBoxStatusEnum.java | 50 + .../datatypes/CreateAndImportButtonsEnum.java | 27 + .../sdc/ci/tests/datatypes/DataTestIdEnum.java | 835 +++++ .../ci/tests/datatypes/ErrorMessageProperties.java | 53 + .../ci/tests/datatypes/GeneralCanvasItemsEnum.java | 38 + .../tests/datatypes/HeatAndHeatEnvNamesPair.java | 62 + .../datatypes/HeatWithParametersDefinition.java | 102 + .../sdc/ci/tests/datatypes/LifeCycleStateEnum.java | 47 + .../sdc/ci/tests/datatypes/MenuOptionsEnum.java | 37 + .../sdc/ci/tests/datatypes/PropertyInfo.java | 76 + .../datatypes/ResourceCategoriesNameEnum.java | 45 + .../tests/datatypes/ServiceCategoriesNameEnum.java | 36 + .../sdc/ci/tests/datatypes/TopMenuButtonsEnum.java | 38 + .../sdc/ci/tests/datatypes/TypesEnum.java | 36 + .../sdc/ci/tests/datatypes/UserCredentials.java | 58 + .../sdc/ci/tests/datatypes/UserManagementTab.java | 114 + .../sdc/ci/tests/datatypes/VFCArtifact.java | 71 + .../sdc/ci/tests/datatypes/environmentLocal | 10 + .../tests/execute/sanity/AdminUserManagment.java | 289 ++ .../tests/execute/sanity/CatalogLeftPanelTest.java | 236 ++ .../sdc/ci/tests/execute/sanity/Categories.java | 213 ++ .../ci/tests/execute/sanity/CustomizationUUID.java | 383 +++ .../tests/execute/sanity/DeploymentViewTests.java | 286 ++ .../sdc/ci/tests/execute/sanity/ImportDCAE.java | 678 ++++ .../ci/tests/execute/sanity/ImportVFCAsset.java | 353 ++ .../sdc/ci/tests/execute/sanity/Onboard.java | 355 ++ .../ci/tests/execute/sanity/OnboardViaApis.java | 303 ++ .../sdc/ci/tests/execute/sanity/Product.java | 93 + .../sdc/ci/tests/execute/sanity/Service.java | 698 ++++ .../sdc/ci/tests/execute/sanity/VFCArtifacts.java | 402 +++ .../openecomp/sdc/ci/tests/execute/sanity/Vf.java | 687 ++++ .../sdc/ci/tests/execute/sanity/VfArtifacts.java | 380 +++ .../sanity/VfDeploymentInformationalArtifacts.java | 862 +++++ .../execute/setup/ArtifactsCorrelationManager.java | 72 + .../sdc/ci/tests/execute/setup/AttFtpClient.java | 221 ++ .../sdc/ci/tests/execute/setup/DriverFactory.java | 125 + .../sdc/ci/tests/execute/setup/ExtentManager.java | 169 + .../ci/tests/execute/setup/ExtentTestActions.java | 114 + .../ci/tests/execute/setup/ExtentTestManager.java | 60 + .../sdc/ci/tests/execute/setup/MobProxy.java | 103 + .../ci/tests/execute/setup/OnboardCSVReport.java | 63 + .../execute/setup/ReportAfterTestManager.java | 129 + .../sdc/ci/tests/execute/setup/Retry.java | 44 + .../sdc/ci/tests/execute/setup/SetupCDTest.java | 573 ++++ .../sdc/ci/tests/execute/setup/TestFtp.java | 94 + .../ci/tests/execute/setup/WebDriverThread.java | 164 + .../sdc/ci/tests/execute/setup/WindowTest.java | 77 + .../ci/tests/execute/setup/WindowTestManager.java | 52 + .../sdc/ci/tests/pages/AdminGeneralPage.java | 132 + .../sdc/ci/tests/pages/ComponentLeftMenu.java | 25 + .../sdc/ci/tests/pages/CompositionPage.java | 197 ++ .../sdc/ci/tests/pages/DeploymentArtifactPage.java | 277 ++ .../sdc/ci/tests/pages/DeploymentPage.java | 239 ++ .../sdc/ci/tests/pages/GeneralPageElements.java | 160 + .../sdc/ci/tests/pages/GovernorOperationPage.java | 46 + .../org/openecomp/sdc/ci/tests/pages/HomePage.java | 109 + .../org/openecomp/sdc/ci/tests/pages/IconPage.java | 51 + .../ci/tests/pages/InformationalArtifactPage.java | 74 + .../openecomp/sdc/ci/tests/pages/InputsPage.java | 158 + .../sdc/ci/tests/pages/OpsOperationPage.java | 156 + .../sdc/ci/tests/pages/ProductGeneralPage.java | 119 + .../sdc/ci/tests/pages/ProductLeftMenu.java | 48 + .../sdc/ci/tests/pages/PropertiesPage.java | 74 + .../sdc/ci/tests/pages/PropertyPopup.java | 111 + .../sdc/ci/tests/pages/ResourceGeneralPage.java | 177 + .../sdc/ci/tests/pages/ResourceLeftMenu.java | 67 + .../sdc/ci/tests/pages/ServiceGeneralPage.java | 114 + .../sdc/ci/tests/pages/ServiceLeftMenu.java | 32 + .../sdc/ci/tests/pages/TesterOperationPage.java | 101 + .../sdc/ci/tests/pages/ToscaArtifactsPage.java | 54 + .../sdc/ci/tests/pages/UploadArtifactPopup.java | 126 + .../ci/tests/utilities/AdditionalConditions.java | 110 + .../tests/utilities/AdminWorkspaceUIUtilies.java | 57 + .../sdc/ci/tests/utilities/ArtifactUIUtils.java | 638 ++++ .../sdc/ci/tests/utilities/AuditCDUtils.java | 67 + .../sdc/ci/tests/utilities/CanvasElement.java | 54 + .../sdc/ci/tests/utilities/CanvasManager.java | 179 + .../sdc/ci/tests/utilities/CatalogUIUtilitis.java | 232 ++ .../sdc/ci/tests/utilities/DownloadManager.java | 115 + .../sdc/ci/tests/utilities/FileHandling.java | 505 +++ .../sdc/ci/tests/utilities/GeneralUIUtils.java | 790 +++++ .../sdc/ci/tests/utilities/HomeUtils.java | 117 + .../sdc/ci/tests/utilities/ImportAssetUIUtils.java | 57 + .../sdc/ci/tests/utilities/OnboardingUtils.java | 801 +++++ .../sdc/ci/tests/utilities/ProductUIUtils.java | 94 + .../sdc/ci/tests/utilities/PropertiesUIUtils.java | 108 + .../sdc/ci/tests/utilities/ResourceUIUtils.java | 1143 +++++++ .../sdc/ci/tests/utilities/RestCDUtils.java | 344 ++ .../sdc/ci/tests/utilities/ServiceUIUtils.java | 286 ++ .../ci/tests/verificator/CatalogVerificator.java | 168 + .../verificator/CustomizationUUIDVerificator.java | 27 + .../verificator/DeploymentViewVerificator.java | 328 ++ .../verificator/ErrorMessageUIVerificator.java | 64 + .../ci/tests/verificator/ServiceVerificator.java | 335 ++ .../verificator/UserManagementVerificator.java | 152 + .../tests/verificator/VFCArtifactVerificator.java | 347 ++ .../sdc/ci/tests/verificator/VFCverificator.java | 37 + .../ci/tests/verificator/VfModuleVerificator.java | 156 + .../sdc/ci/tests/verificator/VfVerificator.java | 245 ++ ui-ci/src/main/resources/Downloads/CP_WAN.yml | 23 + .../resources/Downloads/Fortigate02_vFW_VFC.yml | 63 + .../main/resources/ci/conf/attsdc-packages.yaml | 2 + ui-ci/src/main/resources/ci/conf/attsdc.yaml | 63 + ui-ci/src/main/resources/ci/conf/credentials.yaml | 48 + .../main/resources/ci/conf/credentials.yaml_prod | 48 + .../resources/ci/conf/credentials.yaml_webtest | 48 + ui-ci/src/main/resources/ci/conf/extent-config.xml | 51 + ui-ci/src/main/resources/ci/conf/log4j.properties | 34 + ui-ci/src/main/resources/ci/conf/titan.properties | 7 + .../src/main/resources/ci/drivers/chromedriver.exe | Bin 0 -> 7442432 bytes .../resources/ci/scripts/addUsersFromList_new.sh | 75 + .../src/main/resources/ci/scripts/copyToStorage.sh | 51 + ui-ci/src/main/resources/ci/scripts/sendMail.sh | 49 + ui-ci/src/main/resources/ci/scripts/startTest.sh | 155 + ui-ci/src/main/resources/ci/scripts/userList.txt | 1 + .../main/resources/ci/testSuites/andreyPara.xml | 10 + .../resources/ci/testSuites/devOnboardSanity.xml | 14 + .../src/main/resources/ci/testSuites/devSanity.xml | 20 + .../resources/ci/testSuites/extendedSanity.xml | 33 + ui-ci/src/main/resources/ci/testSuites/fullCI.xml | 34 + .../resources/ci/testSuites/onboardingVNFs.xml | 15 + ui-ci/src/main/resources/ci/testSuites/sanity.xml | 30 + ui-ci/src/main/resources/images/gizmorambo.jpg | Bin 0 -> 16605 bytes ui-ci/src/test/Completetheform.js | 3 + ui-ci/tarball.xml | 70 + .../org/openecomp/sdc/webseal/simulator/Login.java | 6 +- .../sdc/webseal/simulator/RequestsClient.java | 75 +- .../src/main/resources/webseal.conf | 18 +- 1249 files changed, 173954 insertions(+), 11023 deletions(-) create mode 100644 asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/FilteredDataByParamsComponentServletTest.java rename asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/{Migration.java => Migration1707Task.java} (63%) create mode 100644 asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/DistributionStatusUpdate.java create mode 100644 asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707RelationsFix.java create mode 100644 asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707VnfFix.java create mode 100644 asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ConsumersMigration.java create mode 100644 asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/InvariantUUIDResolver.java create mode 100644 asdctool/src/main/java/org/openecomp/sdc/asdctool/main/SdcSchemaFileImport.java create mode 100644 asdctool/src/main/resources/scripts/distributionStatusUpdate1707.sh create mode 100644 asdctool/src/main/resources/scripts/migration1707RelationsFix.sh create mode 100644 asdctool/src/main/resources/scripts/retrieve_schema_file.sh create mode 100644 asdctool/src/main/resources/scripts/vfmoduleFix1707.sh create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/components/ArtifactsResolver.java create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactResolverImpl.java rename catalog-be/src/main/java/org/openecomp/sdc/be/{externalapi/servlet => ecomp/converters}/AssetMetadataConverter.java (99%) create mode 100644 catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ArtifactResolverTest.java rename catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/{ESSdcSchemaFilesData.java => SdcSchemaFilesData.java} (73%) delete mode 100644 catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceAttribute.java rename catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/migration/{MigrationErrorInformer.java => MigrationMalformedDataLogger.java} (82%) create mode 100644 catalog-ui/src/app/models/properties-inputs/input-be-model.ts create mode 100644 catalog-ui/src/app/models/properties-inputs/simple-flat-property.ts delete mode 100644 catalog-ui/src/app/models/property-fe-model.ts create mode 100644 catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.html create mode 100644 catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.less create mode 100644 catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.ts create mode 100644 catalog-ui/src/app/ng2/components/inputs-table/confirmation-delete-input/confirmation-delete-input.component.html create mode 100644 catalog-ui/src/app/ng2/components/inputs-table/confirmation-delete-input/confirmation-delete-input.component.ts create mode 100644 catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less create mode 100644 catalog-ui/src/app/ng2/components/loader/loader.component.html create mode 100644 catalog-ui/src/app/ng2/components/loader/loader.component.less create mode 100644 catalog-ui/src/app/ng2/components/loader/loader.component.ts create mode 100644 catalog-ui/src/app/ng2/components/modal/modal.component.html create mode 100644 catalog-ui/src/app/ng2/components/modal/modal.component.less create mode 100644 catalog-ui/src/app/ng2/components/modal/modal.component.ts delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.html delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.less delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.ts delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.html delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.less delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.ts delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/map-property/map-property.component.html delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/map-property/map-property.component.ts delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.html delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.less delete mode 100644 catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.ts create mode 100644 catalog-ui/src/app/ng2/services/component-mode.service.ts create mode 100644 catalog-ui/src/app/ng2/services/hierarchy-nav.service.ts rename catalog-ui/src/app/view-models/{workspace => modals}/conformance-level-modal/conformance-level-modal-view-model.ts (100%) rename catalog-ui/src/app/view-models/{workspace => modals}/conformance-level-modal/conformance-level-modal-view.html (100%) rename catalog-ui/src/app/view-models/{workspace => modals}/conformance-level-modal/conformance-level-modal.less (100%) delete mode 100644 common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/AttributeDataDefinition.java delete mode 100644 common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/MapAttributesDataDefinition.java delete mode 100644 common/openecomp-common-configuration-management/openecomp-configuration-management-cli/dependency-reduced-pom.xml delete mode 100644 openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/VSPPackage.zip create mode 100644 openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedMultiLevels/out/Nested_jsaServiceTemplate.yaml create mode 100644 openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/MANIFEST.json create mode 100644 openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/hot-nimbus-pcm_v0.4.env create mode 100644 openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/hot-nimbus-pcm_v0.4.yaml create mode 100644 openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/nested-pcm_v0.1.yaml create mode 100644 openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/GlobalSubstitutionTypesServiceTemplate.yaml create mode 100644 openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/MainServiceTemplate.yaml create mode 100644 openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/Nested_computeServiceTemplate.yaml create mode 100644 openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/nested-pcm_v0.1ServiceTemplate.yaml delete mode 100644 sdc-os-chef/sdc-cassandra/chef-repo/cookbooks/cassandra-actions/files/default/titan.properties create mode 100644 test-apis-ci/.gitignore create mode 100644 test-apis-ci/pom.xml create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/AttSdcTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ComponentBaseTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ComponentInstanceBaseTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ExtentManager.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ExtentTestManager.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/config/Config.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/config/InvokedMethodListener.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactAssetStructure.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactReqDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/AssetStructure.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ComponentInstanceReqDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ComponentReqDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CsarArtifacts.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/GroupHeatMetaDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatMetaFirstLevelDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ImportReqDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ProductReqDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyHeatMetaDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyReqDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceAssetStructure.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceDetailedAssetStructure.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceExternalReqDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceInstanceAssetStructure.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceReqDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceRespJavaObject.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceAssetStructure.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceDetailedAssetStructure.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceDistributionStatus.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceReqDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceRespJavaObject.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TypeHeatMetaDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ArtifactTypeEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AssocType.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AuditEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AuditJsonKeysEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ComponentType.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/DistributionNotificationStatusEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ErrorInfo.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/EsIndexTypeIdToDelete.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ExceptionEnumType.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ImportTestTypesEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/LifeCycleStatesEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/MandatoryResourceArtifactTypeEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/MandatoryServiceArtifactTypeEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/NormativeTypesEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/OriginTypeEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/PropertyTypeEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ResourceCategoryEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/RespJsonKeysEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/SearchCriteriaEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ServiceApiArtifactEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ServiceCategoriesEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ToscaKeysEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/UserRoleEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedArtifactAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedAuthenticationAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedCategoryAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedDistDownloadAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedEcomConsumerAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedExternalAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedGetUserListAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedGroupingAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedProductAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedResourceAuditJavaObject.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedUserCRUDAudit.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HeaderData.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HeaderValue.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HttpHeaderEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HttpRequest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/MustHeaders.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/RestResponse.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/TODO/ImportCapabilityTypeCITest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ArtifactServletTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/CrudArt.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/DownloadComponentArt.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/HeatEnvArtifact.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/PlaceHolderValidations.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ValidateArtResponse.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ValidateHeatArtFieldsTypes.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/attribute/ComponentInstanceAttributeTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CatalogDataApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CategoriesBaseTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CategoriesTests.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/ElementsApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/GroupingTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/SubCategoriesTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/AndreyTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ArtifactFromCsar.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ImportCsarUpdate.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ImportCsarValidateArtifacts.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ToscaGroupInsideVF.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/test1.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/distribution/AuthanticationTests.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/distribution/DistributionDownloadArtifactTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/externalapi/DownloadArtifactsTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/BasicHttpAuthenticationTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/FeProxyTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/ManageEcompConsumerCredentials.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/UuidTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/CsarUtilsTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ExportToscaTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportCsarResourceTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportGenericResourceCITest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportNewResourceCITest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaCapabilitiesWithProperties.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaResourceTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportUpdateResourseCsarTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/inputs/InputsApiTests.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/lifecycle/LCSbaseTest.java rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ChangeServiceInstanceVersionTest.java (100%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductBaseTest.java (100%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckinTest.java (100%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckoutTest.java (100%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductComponentInstanceCRUDTest.java (97%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCreateWithValidationsTest.java (95%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCrudTest.java (80%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductGetFollowedTest.java (100%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductLifecycleTest.java (100%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductTestBase.java (100%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductToscaYamlGenerationTest.java (100%) rename {asdc-tests => test-apis-ci}/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductUndoCheckoutTest.java (100%) create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/AdditionalInformationServletTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/ComponentInstancePropertyTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/ComponentProperty.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/PropertyApisTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/CheckGetResource.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ComponentRelationshipInVfTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/CreateResourceApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/GetAllResourceVersions.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/GetResourceNotAbstractApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ResourceApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/SampleDataProvider.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/SimultaneousApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/UpdateResourceMetadataTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/VFResourceInstanceNameCRUD.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ValidateExtendedVfData.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/VfComponentInstanceCRUDTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ChangeServiceDistributionStatusApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/CreateServiceMetadataApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetAllServiceVersions.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetComponentAuditApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetServiceLatestVersionTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ReqCapOccurrencesTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ServiceComponentInstanceCRUDTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/UpdateServiceMetadataTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/ActivateDeActivateDeleteUser.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/CreateUserApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/GovernorWorkspaceApiTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/executeOnUGN/distributionClient/ClientConfiguration.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/ComplexResourceBaseTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/DownloadArtifactBaseTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/SimpleOneRsrcOneServiceTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/rules/MyTestWatcher.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/run/StartTest.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/run/StartTest2backup.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/sanity/CrudE2E.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/sanity/MultipleResourceUpdate.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ParametersDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaCapabilitiesNodeTemplatesDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaGroupsMetadataDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaGroupsTopologyTemplateDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaImportsDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaInputsTopologyTemplateDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaNodeTemplatesTopologyTemplateDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaNodeTypesDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaOutputsTopologyTemplateDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaPoliciesTopologyTemplateDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaRelationshipTemplatesTopologyTemplateDefinition.java rename catalog-model/src/main/java/org/openecomp/sdc/be/model/AttributeDefinition.java => test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaRequirementsNodeTemplatesDefinition.java (50%) create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaSubstitutionMappingsDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaTopologyTemplateDefinition.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaTopologyTemplateDefinition2.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/AddUserAuditMessageInfo.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserAuditJavaObject.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserHeaderData.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserResponseMessageEnum.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/WebSealUserDetails.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ArtifactUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/CsarParserUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/DbUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/Decoder.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/DistributionUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ReqCap.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ToscaParserUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/Utils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/cassandra/CassandraUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/cassandra/CassandraUtils2.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/AtomicOperationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/Convertor.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/ElementFactory.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/FileUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/ImportUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ArtifactRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/AssetRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/AutomationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/BaseRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/CatalogRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/CategoryRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ComponentInstanceRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ComponentRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ConsumerRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/EcompUserRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/GroupRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ImportRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/InputsRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/LifecycleRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ProductRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/PropertyRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtilsExternalAPI.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResponseParser.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ServiceRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/UserRestUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ArtifactValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/AuditValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/BaseValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/CategoryValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/CsarValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/DistributionValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ErrorValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ProductValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ResourceValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ServiceValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/UserValidationUtils.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/webSealAccess/NeoJavaObject.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/AssetLifeCycle.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/CRUDExternalAPI.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/DeploymentValiditaion.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetAssetServlet.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetCSARofVF.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetFilteredAssetServlet.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetSpecificAssetMetadataServlet.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/SearchFilterCategoryExternalAPI.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/UserAPIs.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/VFCMTExternalAPI.java create mode 100644 test-apis-ci/src/main/java/org/openecomp/sdc/post/Install.java create mode 100644 test-apis-ci/src/main/resources/ci/conf/attsdc-packages.yaml create mode 100644 test-apis-ci/src/main/resources/ci/conf/attsdc.yaml create mode 100644 test-apis-ci/src/main/resources/ci/conf/extent-config.xml create mode 100644 test-apis-ci/src/main/resources/ci/conf/log4j.properties create mode 100644 test-apis-ci/src/main/resources/ci/conf/log4j.xml create mode 100644 test-apis-ci/src/main/resources/ci/conf/testngLifeCycle.xml create mode 100644 test-apis-ci/src/main/resources/ci/conf/titan.properties create mode 100644 test-apis-ci/src/main/resources/ci/conf/truststore create mode 100644 test-apis-ci/src/main/resources/ci/scripts/addUsersFromList_new.sh create mode 100644 test-apis-ci/src/main/resources/ci/scripts/copyToStorage.sh create mode 100644 test-apis-ci/src/main/resources/ci/scripts/sendMail.sh create mode 100644 test-apis-ci/src/main/resources/ci/scripts/startTest.sh create mode 100644 test-apis-ci/src/main/resources/ci/scripts/userList.txt create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/CRUDArtifacts.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/SearchExternalAPI.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/artifacts.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/category.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/ciFull.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/externalAPIs.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/general.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/imports.xml rename {asdc-tests => test-apis-ci}/src/main/resources/ci/testSuites/product.xml (100%) create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/productAPIs.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/property.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/resource.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/sanity.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/service.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/testngLifeCycle.xml create mode 100644 test-apis-ci/src/main/resources/ci/testSuites/user.xml create mode 100644 test-apis-ci/src/main/resources/log4j.properties create mode 100644 test-apis-ci/src/main/resources/log4j.xml create mode 100644 test-apis-ci/src/main/resources/logback.xml create mode 100644 test-apis-ci/src/test/resources/CI/ecomp-error-configuration.yaml create mode 100644 test-apis-ci/src/test/resources/CI/error-configuration.yaml create mode 100644 test-apis-ci/src/test/resources/CI/importTypesTest/categoryTypesTest.yml create mode 100644 test-apis-ci/src/test/resources/CI/importTypesTest/categoryTypesTest.zip create mode 100644 test-apis-ci/src/test/resources/CI/importTypesTest/myHeatStack1/myHeatStack1.yml create mode 100644 test-apis-ci/src/test/resources/CI/importTypesTest/myHeatStack1/myHeatStack1.zip create mode 100644 test-apis-ci/src/test/resources/CI/importTypesTest/myHeatStack2/myHeatStack2.yml create mode 100644 test-apis-ci/src/test/resources/CI/importTypesTest/myHeatStack2/myHeatStack2.zip create mode 100644 test-apis-ci/src/test/resources/CI/other/mapping.json create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/addYangXmlArtifactToResource.xml create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat 0 2.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat 0 2.zip create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat_net 0 2.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heatEnvfile.env create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heatInvalidFormat.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heat_mini.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidJson.json create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidYamlFormat.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidYangXml.xml create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/jsonArtifact.json create mode 100644 test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/other.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/bluePrintSampleArtifact.xml create mode 100644 test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/docSampleArtifact.docx create mode 100644 test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/emfSampleArtifact.emf create mode 100644 test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/emfSampleArtifact.xml create mode 100644 test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/eventSampleArtifact.xml create mode 100644 test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/jsonSampleArtifact.json create mode 100644 test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/toscaSampleArtifact.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/addHeatArtifactToServiceAndSertify/asc_heat 0 2.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/downloadResourceArtifactSuccess/org.openstack.Rally.zip create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/scripts/install_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/scripts/start_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListNoContentTest/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/scripts/install_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/scripts/start_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataNoContentTest/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/scripts/install_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/scripts/start_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getResourceArtifactPayloadNoContentTest/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/scripts/install_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/scripts/start_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/scripts/install_mysql2.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/scripts/start_mysql2.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/topology.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/topologyTemplate.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource1/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource1/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource2/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource2/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/topology.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/topologyTemplate.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/scripts/install_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/scripts/start_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/scripts/install_mysql2.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/scripts/start_mysql2.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/topology.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/topologyTemplate.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/scripts/install_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/scripts/start_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/scripts/install_mysql2.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/scripts/start_mysql2.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/topology.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/topologyTemplate.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource1/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource1/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource2/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource2/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/topology.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/topologyTemplate.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingDefault.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingDesc.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingType.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithValidParams.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/heatEnv/artifact_1.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/heatEnv/artifact_2.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/heatEnv/yuli.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/BindingAsset.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPHasNoReqCap.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPHasNoReqCap_DerivedFromMyCompute1.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPWithAttributes.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveCapTest_1.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveCapTest_2.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveReqTest_1.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveReqTest_2.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DerivedFromCPWithOwnReq.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DerivedFromWebApplication_HasNoReqType.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentCapFromRoot.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqAndCap.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqCapFromCompute1.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqCapFromCompute2.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqFromCompute.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/FatherHasNoReqCap.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure01.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure02.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure03.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure04.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure05.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure06.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure07.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure08.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure09.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure10.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure11.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure12.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure13.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure14.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure15.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure16.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure01.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure02.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure03.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure04.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure05.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure06.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure07.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure08.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure09.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure10.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure11.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure12.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure13.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure14.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure15.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure16.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MyFatherCompute_NoReqCap.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameCapAsCompute.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameReqAsCompute.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameReqAsCompute_DerivedFromMyCompute1.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/computeCap11.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/computeCap1UNBOUNDED.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/derivedFromMyCompute.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/derivedFromWebAppDerivedReqCap.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importAttributeSuccessFlow.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importCapabilityNameExistsOnParent.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importDuplicateCapability.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importDuplicateRequirements.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertyBadDefault.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertyGoodDefault.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertySuccessFlow.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importMapPropertySuccessFlow.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importRequirementNameExistsOnParent.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importRequirementNameExistsOnParent_DerivedFromMyCompute1.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/missingCapInCapDefinition.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/missingCapInReqDefinition.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myChildCompute_NoReqCap.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myChildWebApp_DerivedFromContainer.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myCompute.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeDerivedFromNotExists.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeIncorrectDefenitionVersionValue.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeIncorrectNameSpaceFormat.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeNoDefenitionVersion.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeOccurencySuccess.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeParssingFalure.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeReqNameExistsOnDerived.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeVF.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeWithNodeTypesTwice.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeWithTopologyTemplate.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myFatherWebApp_derviedFromDocker.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myLinkVL.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myPortCP.yml rename openecomp-be/sonar-project.properties => test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/noContent.yml (100%) create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure01.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure02.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure03.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure04.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure05.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure06.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure07.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure08.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure09.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure10.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure11.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure31.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure32.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure33.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure34.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure35.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure36.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure37.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure38.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure39.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure40.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure41.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/softwareComponentReq11.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/softwareComponentReq12.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/testCsarAPI/topology.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/testCsarAPI/topologyTemplate.txt create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool10_false.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool11_false.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool12_false.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool1_true.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool2_true.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool3_true.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool4_true.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool5_true.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool6_true.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool7_false.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool8_false.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool9_false.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_number1.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_number2.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/uploadComponent/images/mysql.png create mode 100644 test-apis-ci/src/test/resources/CI/tests/uploadComponent/mysql.yml create mode 100644 test-apis-ci/src/test/resources/CI/tests/uploadComponent/scripts/install_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/uploadComponent/scripts/start_mysql.sh create mode 100644 test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/artifact_unsupported.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_bool1.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_bool2.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_number1.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_number2.yaml create mode 100644 test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_string1.yaml create mode 100644 test-apis-ci/src/test/resources/config.json create mode 100644 test-apis-ci/src/test/resources/logback-test.xml create mode 100644 test-apis-ci/testng.xml create mode 100644 test-apis-ci/testngLifeCycle.xml create mode 100644 test-apis-ci/tmpCSAR create mode 100644 ui-ci-dev/.gitignore create mode 100644 ui-ci-dev/pom.xml create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/scripts/CreateVfsFromOnboarding.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CanvasElement.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CanvasManager.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CleanTypeEnum.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CreateAndImportButtonsEnum.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CreateAndUpdateStepsEnum.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/DataTestIdEnum.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/MenuOptionsEnum.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/UserCredentials.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/base/SetupCDTest.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/generalTests/GeneralTests.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/service/ServiceBasicTests.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/service/ServiceInputsTests.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfBasicTests.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfCanvasTests.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfDeploymentTests.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfOnboardingTests.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vfc/VfcBasicTests.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/run/StartTest.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ArtifactUIUtils.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/FileHandling.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/GeneralUIUtils.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/MethodManipulationUtils.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/OnboardUtility.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ResourceUIUtils.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/RestCDUtils.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ServiceUIUtils.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/ServiceVerificator.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/VerificatorUtil.java create mode 100644 ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/VfVerificator.java create mode 100644 ui-ci-dev/src/main/resources/ci/conf/attsdc-packages.yaml create mode 100644 ui-ci-dev/src/main/resources/ci/conf/attsdc.yaml create mode 100644 ui-ci-dev/src/main/resources/ci/conf/credentials.yaml create mode 100644 ui-ci-dev/src/main/resources/ci/conf/log4j.properties create mode 100644 ui-ci-dev/src/main/resources/ci/conf/titan.properties create mode 100644 ui-ci-dev/src/main/resources/ci/scripts/startTest.sh create mode 100644 ui-ci-dev/src/main/resources/ci/testSuites/fullTests.xml create mode 100644 ui-ci-dev/src/main/resources/ci/testSuites/sanity.xml create mode 100644 ui-ci-dev/src/main/resources/images/gizmorambo.jpg create mode 100644 ui-ci-dev/src/test/Completetheform.js create mode 100644 ui-ci/.gitignore create mode 100644 ui-ci/hs_err_pid10052.log create mode 100644 ui-ci/pom.xml create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/AddComponentInstancesArtifactsInCsar.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/ImportUpdateInformationalDeploymentArtifacts.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Inputs.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/LocalGeneralUtilities.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/MIBsArtifactsOnResourceInstance.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/MobProxy.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/NewArtifactTypeGuide.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/RemoveRestrictionOfDeploymentArtifacts.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Service_Tests_UI.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Testing.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/VfModule.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Vf_Tests_UI.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/extendNode_TemplatePropertiesWithDefaultValues.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/businesslogic/ArtifactBusinessLogic.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactInfo.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CanvasElement.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CanvasManager.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CatalogFilterTitlesEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CheckBoxStatusEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CreateAndImportButtonsEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/DataTestIdEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ErrorMessageProperties.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/GeneralCanvasItemsEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatAndHeatEnvNamesPair.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatWithParametersDefinition.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/LifeCycleStateEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/MenuOptionsEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyInfo.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceCategoriesNameEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceCategoriesNameEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TopMenuButtonsEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TypesEnum.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/UserCredentials.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/UserManagementTab.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/VFCArtifact.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/environmentLocal create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/AdminUserManagment.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/CatalogLeftPanelTest.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Categories.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/CustomizationUUID.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/DeploymentViewTests.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/ImportDCAE.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/ImportVFCAsset.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Onboard.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/OnboardViaApis.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Product.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Service.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VFCArtifacts.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Vf.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VfArtifacts.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VfDeploymentInformationalArtifacts.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ArtifactsCorrelationManager.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/AttFtpClient.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/DriverFactory.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentManager.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentTestActions.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentTestManager.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/MobProxy.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/OnboardCSVReport.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ReportAfterTestManager.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/Retry.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/SetupCDTest.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/TestFtp.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WebDriverThread.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WindowTest.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WindowTestManager.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/AdminGeneralPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ComponentLeftMenu.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/CompositionPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/DeploymentArtifactPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/DeploymentPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/GeneralPageElements.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/GovernorOperationPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/HomePage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/IconPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/InformationalArtifactPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/InputsPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/OpsOperationPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ProductGeneralPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ProductLeftMenu.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/PropertiesPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/PropertyPopup.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ResourceGeneralPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ResourceLeftMenu.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ServiceGeneralPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ServiceLeftMenu.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/TesterOperationPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ToscaArtifactsPage.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/UploadArtifactPopup.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AdditionalConditions.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AdminWorkspaceUIUtilies.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ArtifactUIUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AuditCDUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CanvasElement.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CanvasManager.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CatalogUIUtilitis.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/DownloadManager.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/FileHandling.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/GeneralUIUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/HomeUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ImportAssetUIUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/OnboardingUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ProductUIUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/PropertiesUIUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ResourceUIUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/RestCDUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ServiceUIUtils.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/CatalogVerificator.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/CustomizationUUIDVerificator.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/DeploymentViewVerificator.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/ErrorMessageUIVerificator.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/ServiceVerificator.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/UserManagementVerificator.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VFCArtifactVerificator.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VFCverificator.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VfModuleVerificator.java create mode 100644 ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VfVerificator.java create mode 100644 ui-ci/src/main/resources/Downloads/CP_WAN.yml create mode 100644 ui-ci/src/main/resources/Downloads/Fortigate02_vFW_VFC.yml create mode 100644 ui-ci/src/main/resources/ci/conf/attsdc-packages.yaml create mode 100644 ui-ci/src/main/resources/ci/conf/attsdc.yaml create mode 100644 ui-ci/src/main/resources/ci/conf/credentials.yaml create mode 100644 ui-ci/src/main/resources/ci/conf/credentials.yaml_prod create mode 100644 ui-ci/src/main/resources/ci/conf/credentials.yaml_webtest create mode 100644 ui-ci/src/main/resources/ci/conf/extent-config.xml create mode 100644 ui-ci/src/main/resources/ci/conf/log4j.properties create mode 100644 ui-ci/src/main/resources/ci/conf/titan.properties create mode 100644 ui-ci/src/main/resources/ci/drivers/chromedriver.exe create mode 100644 ui-ci/src/main/resources/ci/scripts/addUsersFromList_new.sh create mode 100644 ui-ci/src/main/resources/ci/scripts/copyToStorage.sh create mode 100644 ui-ci/src/main/resources/ci/scripts/sendMail.sh create mode 100644 ui-ci/src/main/resources/ci/scripts/startTest.sh create mode 100644 ui-ci/src/main/resources/ci/scripts/userList.txt create mode 100644 ui-ci/src/main/resources/ci/testSuites/andreyPara.xml create mode 100644 ui-ci/src/main/resources/ci/testSuites/devOnboardSanity.xml create mode 100644 ui-ci/src/main/resources/ci/testSuites/devSanity.xml create mode 100644 ui-ci/src/main/resources/ci/testSuites/extendedSanity.xml create mode 100644 ui-ci/src/main/resources/ci/testSuites/fullCI.xml create mode 100644 ui-ci/src/main/resources/ci/testSuites/onboardingVNFs.xml create mode 100644 ui-ci/src/main/resources/ci/testSuites/sanity.xml create mode 100644 ui-ci/src/main/resources/images/gizmorambo.jpg create mode 100644 ui-ci/src/test/Completetheform.js create mode 100644 ui-ci/tarball.xml diff --git a/asdc-tests/pom.xml b/asdc-tests/pom.xml index 0c0e9a2598..02092fdaf3 100644 --- a/asdc-tests/pom.xml +++ b/asdc-tests/pom.xml @@ -270,7 +270,7 @@ org.openecomp.ecompsdkos - ecompFW + epsdk-fw ${ecomp.version} compile diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java index a8342f8879..0e1c0e4da1 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java +++ b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java @@ -163,6 +163,7 @@ public interface Urls { final String GET_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s"; final String GET_RESOURCE_BY_NAME_AND_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/resources/resourceName/%s/resourceVersion/%s"; final String GET_RESOURCE_BY_CSAR_UUID = "http://%s:%s/sdc2/rest/v1/catalog/resources/csar/%s"; + final String GET_RESOURCE_DATA_BY_PARAMS = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/filteredDataByParams?"; final String GET_COMPONENT_REQUIRMENTS_CAPABILITIES = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/requirmentsCapabilities"; final String DELETE_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s"; @@ -270,7 +271,6 @@ public interface Urls { final String GET_COMPONENT_INSTANCES = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/componentInstances"; //{containerComponentType}/{containerComponentId}/componentInstances/{componentInstanceUniqueId}/properties final String GET_COMPONENT_INSTANCE_PROPERTIES_BY_ID = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/componentInstances/%s/properties"; - // Tal New API final String UPDATE_MULTIPLE_COMPONENT_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/multipleComponentInstance"; final String CHANGE_RESOURCE_INSTANCE_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/%s/changeVersion"; diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/attribute/ComponentInstanceAttributeTest.java b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/attribute/ComponentInstanceAttributeTest.java index d1b6ff5676..b1d04ba88d 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/attribute/ComponentInstanceAttributeTest.java +++ b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/attribute/ComponentInstanceAttributeTest.java @@ -31,7 +31,7 @@ import org.junit.rules.TestName; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; import org.openecomp.sdc.ci.tests.api.Urls; @@ -69,13 +69,13 @@ public class ComponentInstanceAttributeTest extends ComponentBaseTest { .addComponentInstanceToComponentContainer(vfcWithAttributes, vf).left().value(); // util method to get the specific attribute from the vf - Function attributeGetter = resourceVf -> resourceVf + Function attributeGetter = resourceVf -> resourceVf .getComponentInstancesAttributes().values().iterator().next().stream() .filter(att -> att.getName().equals("private_address")).findAny().get(); // update attribute on vfc instance final Resource vfWithInsatncePreUpdate = swallowException( () -> (Resource) AtomicOperationUtils.getCompoenntObject(vf, UserRoleEnum.DESIGNER)); - ComponentInstanceAttribute attributeOfRI = attributeGetter.apply(vfWithInsatncePreUpdate); + ComponentInstanceProperty attributeOfRI = attributeGetter.apply(vfWithInsatncePreUpdate); final String newAttValue = "NewValue"; attributeOfRI.setValue(newAttValue); String body = gson.toJson(attributeOfRI); @@ -87,7 +87,7 @@ public class ComponentInstanceAttributeTest extends ComponentBaseTest { // Retrieve updated vf and verify attribute was updated final Resource vfWithInsatncePostUpdate = swallowException( () -> (Resource) AtomicOperationUtils.getCompoenntObject(vf, UserRoleEnum.DESIGNER)); - ComponentInstanceAttribute updatedAttribute = attributeGetter.apply(vfWithInsatncePostUpdate); + ComponentInstanceProperty updatedAttribute = attributeGetter.apply(vfWithInsatncePostUpdate); assertEquals(updatedAttribute.getValue(), newAttValue); } diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ValidateConformanceLevel.java b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ValidateConformanceLevel.java index 08e7539b28..24c91935d4 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ValidateConformanceLevel.java +++ b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ValidateConformanceLevel.java @@ -63,12 +63,39 @@ public class ValidateConformanceLevel extends ComponentBaseTest { Service serviceFirstImport = ResponseParser.parseToObjectUsingMapper(createdService.getResponse(), Service.class); Component serviceObject = AtomicOperationUtils.changeComponentState(serviceFirstImport, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); - RestResponse apiRes = ComponentRestUtils.validateConformanceLevel(serviceObject.getUniqueId(), user.getUserId()); + RestResponse apiRes = ComponentRestUtils.validateConformanceLevel(serviceObject.getUUID(), user.getUserId()); String result = apiRes.getResponse(); assertTrue(apiRes.getErrorCode() == 200); assertTrue(result.equals("true")); } + @Test + public void testValidateServiceConformanceLevelForSecondMajorVersion() throws Exception { + User user = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + ServiceReqDetails service = ElementFactory.getDefaultService(); + RestResponse createdService = ServiceRestUtils.createService(service, user); + BaseRestUtils.checkCreateResponse(createdService); + Service serviceFirstImport = ResponseParser.parseToObjectUsingMapper(createdService.getResponse(), Service.class); + Component serviceObject = AtomicOperationUtils.changeComponentState(serviceFirstImport, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + String uuid1 = serviceObject.getUUID(); + Component service20Object = AtomicOperationUtils.changeComponentState(serviceFirstImport, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service20Object = AtomicOperationUtils.changeComponentState(service20Object, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + String uuid2 = service20Object.getUUID(); + + assertTrue(uuid1 != uuid2); + + RestResponse apiRes = ComponentRestUtils.validateConformanceLevel(uuid1, user.getUserId()); + String result = apiRes.getResponse(); + assertTrue(apiRes.getErrorCode() == 200); + assertTrue(result.equals("true")); + + apiRes = ComponentRestUtils.validateConformanceLevel(uuid2, user.getUserId()); + result = apiRes.getResponse(); + assertTrue(apiRes.getErrorCode() == 200); + assertTrue(result.equals("true")); + } + @Test public void testValidateConformanceLevel404() throws Exception { User user = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/FilteredDataByParamsComponentServletTest.java b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/FilteredDataByParamsComponentServletTest.java new file mode 100644 index 0000000000..541294c141 --- /dev/null +++ b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/FilteredDataByParamsComponentServletTest.java @@ -0,0 +1,124 @@ +package org.openecomp.sdc.ci.tests.execute.imports; + +import static org.testng.AssertJUnit.assertEquals; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.codec.binary.Base64; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer; +import org.openecomp.sdc.be.ui.model.UiResourceDataTransfer; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.testng.annotations.Test; + + + +public class FilteredDataByParamsComponentServletTest extends ComponentBaseTest{ + + private static final String CSAR_NAME = "LDSA1_with_inputs.csar"; + private static final String COMPONENT_INSTANCES = "include=componentInstances"; + private static final String COMPONENT_INSTANCES_RELATIONS = "include=componentInstancesRelations"; + private static final String DEPLOYMENT_ARTIFACTS = "include=deploymentArtifacts"; + private static final String INFORMATIONAL_ARTIFACTS = "include=artifacts"; + private static final String METADATA = "include=metadata"; + public static TestName name = new TestName(); + + + + protected User designerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + public FilteredDataByParamsComponentServletTest() { + super(name, ImportCsarResourceTest.class.getName()); + } + + + @Test + public void getComponentInstancesAndComponentInstancesRelationsTest() throws Exception { + Resource resource = ResourceRestUtils.importResourceFromCsar(CSAR_NAME); + List parameters = new ArrayList<>(); + parameters.add(COMPONENT_INSTANCES); + parameters.add(COMPONENT_INSTANCES_RELATIONS); + // create UiComponentDataTransfer and parse the ComponentInstancesRelations into it + RestResponse resourceGetResponse = ResourceRestUtils.getResourceFilteredDataByParams(designerDetails, resource.getUniqueId() , parameters); + UiComponentDataTransfer uiComponentWithComponentInstancesAndRelations = ResponseParser.parseToObjectUsingMapper(resourceGetResponse.getResponse() , UiComponentDataTransfer.class); + + uiComponentWithComponentInstancesAndRelations.getComponentInstances().stream().sorted((object1, object2) -> object1.getUniqueId().compareTo(object2.getUniqueId())); + resource.getComponentInstances().stream().sorted((object1, object2) -> object1.getUniqueId().compareTo(object2.getUniqueId())); + + for (int i = 0 ; i < resource.getComponentInstances().size() ; i++){ + assertEquals(uiComponentWithComponentInstancesAndRelations.getComponentInstances().get(i).getUniqueId() ,resource.getComponentInstances().get(i).getUniqueId()); + } + assertEquals(uiComponentWithComponentInstancesAndRelations.getComponentInstancesRelations().size() , resource.getComponentInstancesRelations().size()); + } + + + @Test + public void getComponentDeploymentAndInformationalArtifacts() throws Exception { + Resource resource = ResourceRestUtils.importResourceFromCsar(CSAR_NAME); + List parameters = new ArrayList<>(); + parameters.add(DEPLOYMENT_ARTIFACTS); + parameters.add(INFORMATIONAL_ARTIFACTS); + + // create new UiComponentData transfer and parse the artifacts into it + RestResponse resourceGetResponse = ResourceRestUtils.getResourceFilteredDataByParams(designerDetails, resource.getUniqueId() , parameters); + UiComponentDataTransfer uiComponentWithArtifacts = ResponseParser.parseToObjectUsingMapper(resourceGetResponse.getResponse() , UiComponentDataTransfer.class); + + List deploymentArtifactsFromResource = new ArrayList(resource.getDeploymentArtifacts().values()); + List deploymentArtifactsFromUiComponent = new ArrayList(uiComponentWithArtifacts.getDeploymentArtifacts().values()); + List informationalArtifactsFromResource = new ArrayList(resource.getArtifacts().values()); + List informationalArtifactsFromUiComponent = new ArrayList(uiComponentWithArtifacts.getArtifacts().values()); + + deploymentArtifactsFromResource.stream().sorted((object1, object2) -> object1.getUniqueId().compareTo(object2.getUniqueId())); + deploymentArtifactsFromUiComponent.stream().sorted((object1, object2) -> object1.getUniqueId().compareTo(object2.getUniqueId())); + informationalArtifactsFromResource.stream().sorted((object1, object2) -> object1.getUniqueId().compareTo(object2.getUniqueId())); + informationalArtifactsFromUiComponent.stream().sorted((object1, object2) -> object1.getUniqueId().compareTo(object2.getUniqueId())); + + for (int i = 0 ; i < deploymentArtifactsFromResource.size() ; i++){ + assertEquals(deploymentArtifactsFromResource.get(i).getUniqueId() , deploymentArtifactsFromUiComponent.get(i).getUniqueId()); + } + + for (int i = 0 ; i < informationalArtifactsFromResource.size() ; i++){ + assertEquals(informationalArtifactsFromResource.get(i).getUniqueId() , informationalArtifactsFromUiComponent.get(i).getUniqueId()); + } + } + + + @Test + public void getComponentMetadataTest() throws Exception { + + Resource resource = ResourceRestUtils.importResourceFromCsar(CSAR_NAME); + List parameters = new ArrayList<>(); + parameters.add(METADATA); + + // create new UiResourceDataTransfer and parse the metadata into it + RestResponse resourceGetResponse = ResourceRestUtils.getResourceFilteredDataByParams(designerDetails, resource.getUniqueId() , parameters); + UiResourceDataTransfer uiResourceWithMetadata = ResponseParser.parseToObjectUsingMapper(resourceGetResponse.getResponse(), UiResourceDataTransfer.class); + + // assert that the metadata is equal + assertEquals(uiResourceWithMetadata.getMetadata().getName(), resource.getName()); + assertEquals(uiResourceWithMetadata.getMetadata().getVersion() , resource.getVersion()); + assertEquals(uiResourceWithMetadata.getMetadata().getUniqueId() , resource.getUniqueId()); + assertEquals(uiResourceWithMetadata.getMetadata().getUUID(), resource.getUUID()); + } + + + + +} diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportCsarResourceTest.java b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportCsarResourceTest.java index 6bf3477c1f..f0421fb026 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportCsarResourceTest.java +++ b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportCsarResourceTest.java @@ -1468,26 +1468,7 @@ public class ImportCsarResourceTest extends ComponentBaseTest { @Test public void createImportRIRelationByCapNameFromCsarUITest() throws Exception { - User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); - String payloadName = "vmmc_relate_by_cap_name.csar"; - ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); - String rootPath = System.getProperty("user.dir"); - Path path = null; - byte[] data = null; - String payloadData = null; - - path = Paths.get(rootPath + CSARS_PATH + "vmmc_relate_by_cap_name.csar"); - data = Files.readAllBytes(path); - payloadData = Base64.encodeBase64String(data); - resourceDetails.setPayloadData(payloadData); - - // create new resource from Csar - resourceDetails.setCsarUUID(payloadName); - resourceDetails.setPayloadName(payloadName); - resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); - RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); - BaseRestUtils.checkCreateResponse(createResource); - Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + Resource resource = ResourceRestUtils.importResourceFromCsar("vmmc_relate_by_cap_name.csar"); // assert all relations created assertEquals(80, resource.getComponentInstancesRelations().size()); } diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportNewResourceCITest.java b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportNewResourceCITest.java index 9e8a2a1f95..56841e1c5d 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportNewResourceCITest.java +++ b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportNewResourceCITest.java @@ -38,7 +38,6 @@ import org.junit.Rule; import org.junit.rules.TestName; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.LifecycleStateEnum; import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.Resource; @@ -1470,12 +1469,12 @@ public class ImportNewResourceCITest extends ComponentBaseTest { checkListValues(listValue.get(1), 2, SPECIAL_CHARACTERS); // Verify attributes - List attributes = resource.getAttributes(); + List attributes = resource.getAttributes(); assertEquals("check properties size", 2, attributes.size()); // Verify attribute from type map - AttributeDefinition attributeMapDefinition = attributes.stream() + PropertyDefinition attributeMapDefinition = attributes.stream() .filter(p -> p.getName().equals("validation_test_map")).findFirst().get(); String defaultMapValue = attributeMapDefinition.getDefaultValue(); Map attributeMapValue = gson.fromJson(defaultMapValue, Map.class); @@ -1484,7 +1483,7 @@ public class ImportNewResourceCITest extends ComponentBaseTest { checkMapValues(attributeMapValue, "key", 2, SPECIAL_CHARACTERS); // Verify attribute from type list - AttributeDefinition attributeListDefinition = attributes.stream() + PropertyDefinition attributeListDefinition = attributes.stream() .filter(p -> p.getName().equals("validation_test_list")).findFirst().get(); String defaultListValue = attributeListDefinition.getDefaultValue(); diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaResourceTest.java b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaResourceTest.java index 0973135295..ef95b34198 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaResourceTest.java +++ b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaResourceTest.java @@ -46,7 +46,6 @@ import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.CapReqDef; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.ComponentInstance; @@ -2837,9 +2836,9 @@ public class ImportToscaResourceTest extends ComponentBaseTest { ToscaNodeTypeInfo parseToscaNodeYaml = utils .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); - HashMap attr = new HashMap<>(); + HashMap attr = new HashMap<>(); - AttributeDefinition newAttr2 = new AttributeDefinition(); + PropertyDefinition newAttr2 = new PropertyDefinition(); newAttr2.setName("networks"); newAttr2.setType("map"); newAttr2.setDefaultValue("{\"keyA\" : val1 , \"keyB\" : val2}"); @@ -2850,17 +2849,17 @@ public class ImportToscaResourceTest extends ComponentBaseTest { newAttr2.setSchema(schema); attr.put("networks", newAttr2); - AttributeDefinition newAttr1 = new AttributeDefinition(); + PropertyDefinition newAttr1 = new PropertyDefinition(); newAttr1.setName("public_address"); newAttr1.setType("string"); attr.put("public_address", newAttr1); - AttributeDefinition newAttr3 = new AttributeDefinition(); + PropertyDefinition newAttr3 = new PropertyDefinition(); newAttr3.setName("ports"); newAttr3.setDescription("this is my description"); attr.put("ports", newAttr3); - AttributeDefinition newAttr = new AttributeDefinition(); + PropertyDefinition newAttr = new PropertyDefinition(); newAttr.setDefaultValue("myDefault"); newAttr.setName("private_address"); newAttr.setStatus("supported"); @@ -2880,8 +2879,8 @@ public class ImportToscaResourceTest extends ComponentBaseTest { AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); } - private void validateResourceAttribute(Resource resource, Map attr) { - List resList = resource.getAttributes(); + private void validateResourceAttribute(Resource resource, Map attr) { + List resList = resource.getAttributes(); int size = resList.size(); String attributeName; for (int i = 0; i < size; i++) { diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtils.java b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtils.java index 6e4a6a8018..90371662a7 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtils.java +++ b/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtils.java @@ -24,16 +24,22 @@ import static org.testng.AssertJUnit.assertEquals; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.StringUtils; import org.apache.http.client.ClientProtocolException; import org.json.JSONException; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; @@ -62,6 +68,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ResourceRestUtils extends BaseRestUtils { + + private static final String CSARS_PATH = "/src/test/resources/CI/csars/"; private static Logger logger = LoggerFactory.getLogger(ResourceRestUtils.class.getName()); // ****** CREATE ******* @@ -384,6 +392,16 @@ public class ResourceRestUtils extends BaseRestUtils { return http.httpSendGet(url, headersMap); } + + public static RestResponse getResourceFilteredDataByParams(User sdncModifierDetails, String uniqueId , List parameters) throws IOException { + Config config = Utils.getConfig(); + String urlGetResourceDataByParams = Urls.GET_RESOURCE_DATA_BY_PARAMS; + String joinedParameters = StringUtils.join(parameters , "&"); + String url = String.format(urlGetResourceDataByParams + joinedParameters , config.getCatalogBeHost(), config.getCatalogBePort(), uniqueId); + return sendGet(url, sdncModifierDetails.getUserId()); + + } + public static RestResponse sendOptionsTowardsCatalogFeWithUuid() throws IOException { @@ -661,5 +679,33 @@ public class ResourceRestUtils extends BaseRestUtils { return ProductRestUtils.changeServiceInstanceVersion(containerUniqueId, instanceToReplaceUniqueId, newResourceUniqueId, sdncModifierDetails, componentType); } + + public static Resource importResourceFromCsar(String csarName) throws Exception{ + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String payloadName = csarName; + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + String rootPath = System.getProperty("user.dir"); + Path path = null; + byte[] data = null; + + String payloadData = null; + + path = Paths.get(rootPath + CSARS_PATH + csarName); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + // create new resource from Csar + resourceDetails.setCsarUUID(payloadName); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + return resource; + + // add to restResourceUtil + } + } diff --git a/asdc-tests/src/main/resources/ci/conf/attsdc-packages.yaml b/asdc-tests/src/main/resources/ci/conf/attsdc-packages.yaml index 5d1a3e1537..fae7ab7ece 100644 --- a/asdc-tests/src/main/resources/ci/conf/attsdc-packages.yaml +++ b/asdc-tests/src/main/resources/ci/conf/attsdc-packages.yaml @@ -8,5 +8,4 @@ packages: - org.openecomp.sdc.ci.tests.execute.artifacts - org.openecomp.sdc.ci.tests.execute.imports - org.openecomp.sdc.ci.tests.execute.category - - org.openecomp.sdc.ci.tests.execute.distribution - - org.openecomp.sdc.ci.tests.execute.product \ No newline at end of file + - org.openecomp.sdc.ci.tests.execute.distribution \ No newline at end of file diff --git a/asdc-tests/src/main/resources/ci/testSuites/ciFull.xml b/asdc-tests/src/main/resources/ci/testSuites/ciFull.xml index 26a85fd9c6..1d81e0f689 100644 --- a/asdc-tests/src/main/resources/ci/testSuites/ciFull.xml +++ b/asdc-tests/src/main/resources/ci/testSuites/ciFull.xml @@ -83,54 +83,7 @@ name="org.openecomp.sdc.ci.tests.execute.resource.ValidateExtendedVfData" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/asdc-tests/src/main/resources/ci/testSuites/sanity.xml b/asdc-tests/src/main/resources/ci/testSuites/sanity.xml index 8e787bc8cd..21b7043ad3 100644 --- a/asdc-tests/src/main/resources/ci/testSuites/sanity.xml +++ b/asdc-tests/src/main/resources/ci/testSuites/sanity.xml @@ -152,53 +152,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/asdc-tests/src/test/resources/CI/components/normativeTypes/network/images/network.png b/asdc-tests/src/test/resources/CI/components/normativeTypes/network/images/network.png index c8bf18f31a2486332a6dd7895e071dbf7d4c9104..c98eef324ed15dc5b8ee28be01904f597504330b 100644 GIT binary patch literal 4214 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 literal 159707 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

sFH*fx<7q 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 literal 159707 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

sFH*fx<7q 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 Z+ld+hFO&9(VgV16S&A$Mw}Aiv003on*Ps9Z delta 2068 zcmV+v2&>E0^~CpusGo^Sb6I#jW2azB(MVGatZX1MvI{^B|)5f z>tNXFVWf+JkuGC@8xD&yj`QWP7*jtsfT~D0X_P)bdsJB>m|?Qn7Gz^b3vV6yyEH>u z6!+p*e-T8NTh1@3zj9y?`pGiLoN}Cl#*tx9;c69twqE;DPTRsb-WL8M3YyKZQK2O- zvM_lhO+fH63pYin@SlP@0w-NNcXtohPE;oWD9;P{tpr+%K_33wB%5kIXNT3ElTBeV zA$|@X=D@JNw70G`15aiE=qYOa2p0HN{I9pk(jr(EAb^vgVH`Ci&tATK3S#UdhzlZP zg{#L3x9@!PSmCN!;emNvufwGmBrDnSlWqsPo!j^3$y6ah>K{xFlks6R1g;v`Ka(k9 zC<31wlT%_`0_Z}Mv0{)096~=)@??`oV@LsslaOOx0@mJ>@MBv7tkjcDWL5#elcZ$p z0iu(TWyS)fh_hH`P5}Wkv!`d|0|9iCjBDF}D-?Nv)Wx?Ou zFvHbvl^l*ha1!KqR{t&i4S8MPCGM-bN}4ZuqmBD1f(YN8$e+Ru`FQfU-j-L?{Q`jV zk7-530!lYwY2NXuq39X!h;hbbnJ{j4ri_Dnf&U@XrmswY8;og( zt4MTV0#wZTMo};UgBeMP$xx(vI{Cvsf_x_VbEEMu0@jFB&XaXV3ARpxdA-l)q6IxY zc@=;`1;C)%g#+5NHbOwZxy5+$ZJi~T@4SJBaOsjxx`W$mOZ<+e@u#xvNCc^qzv=`@ zTpU#TvOk6BDgLx)@nZ4>3j=O{I?1P>N}hmpcbu*t?&#K}YJVY>O4XU4A)Z@a!MyC- zXPmtyF}5#|?}aVSK-Sl^EI;|DEWk$H#K8_r*nOy#hIVl8Lcir>uWY5X+qrpw59{1&J~kRi1naHufkcVzJR_;t80>t=!jhYQYZUC*0}_7lbo1@X!*K5C zPUb0au5NlXM7iDepsn2e7S=GT(ZV_#RZ5T!f4$H*m^CrzI{>g3BhSW`)SkcTyb*3ZR%(+J*>>W<1c0*@x&j;7y@rW5zu(N3*fFgUVOKf^x{g}keKb|aR4VX))>tTekuU93-kljKs)|Sa z`&R2{MAiu<(Mw>;CV2ObGET8!3(uonECJ{gdy0*EUB;oA8dLNeeN z3gE&f5V@>zTzKNdErc*a79M#{Ae3o${onk6(sAV1iPrfx;$9Xm*lB+ zHK=tvsdf3!I;%bhporg.json json + + org.slf4j + slf4j-log4j12 + @@ -180,6 +184,12 @@ titan-cassandra ${titan.version} compile + + + org.slf4j + slf4j-log4j12 + + @@ -202,6 +212,12 @@ 2.5.0 true compile + + + org.slf4j + slf4j-log4j12 + + @@ -210,6 +226,12 @@ 2.5.0 true compile + + + org.slf4j + slf4j-log4j12 + + diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/EsToCassandraDataMigrationConfig.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/EsToCassandraDataMigrationConfig.java index 2c0471fb17..3242c27384 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/EsToCassandraDataMigrationConfig.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/EsToCassandraDataMigrationConfig.java @@ -23,6 +23,7 @@ package org.openecomp.sdc.asdctool.impl; import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao; import org.openecomp.sdc.be.dao.cassandra.AuditCassandraDao; import org.openecomp.sdc.be.dao.cassandra.CassandraClient; +import org.openecomp.sdc.be.dao.cassandra.SdcSchemaFilesCassandraDao; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -47,5 +48,9 @@ public class EsToCassandraDataMigrationConfig { public CassandraClient cassandraClient() { return new CassandraClient(); } - + + @Bean(name = "sdc-schema-files-cassandra-dao") + public SdcSchemaFilesCassandraDao sdcSchemaFilesCassandraDao() { + return new SdcSchemaFilesCassandraDao(); + } } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/TitanGraphInitializer.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/TitanGraphInitializer.java index 3f63570ecd..ace1c038f2 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/TitanGraphInitializer.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/TitanGraphInitializer.java @@ -2,18 +2,14 @@ package org.openecomp.sdc.asdctool.impl; import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; import java.util.Map; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.openecomp.sdc.be.config.ConfigurationManager; import org.openecomp.sdc.be.dao.graph.datatype.ActionEnum; import org.openecomp.sdc.be.dao.graph.datatype.GraphElementTypeEnum; import org.openecomp.sdc.be.dao.neo4j.GraphEdgePropertiesDictionary; import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; -import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.dao.utils.UserStatusEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.resources.data.UserData; @@ -72,49 +68,28 @@ public class TitanGraphInitializer { return false; } - private static void createDefaultUsers() { - List users = createUserList(); - for (UserData user : users) { - Vertex vertex = null; - Map checkedProperties = new HashMap(); - checkedProperties.put(GraphPropertiesDictionary.USERID.getProperty(), user.getUserId()); - checkedProperties.put(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.User.getName()); - Map properties = null; - if (!isVertexExist(checkedProperties)) { - vertex = graph.addVertex(); - vertex.property(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.User.getName()); - properties = user.toGraphMap(); - for (Map.Entry entry : properties.entrySet()) { - vertex.property(entry.getKey(), entry.getValue()); - } - } - } + private static void createDefaultAdminUser() { + createUser(getDefaultUserAdmin()); graph.tx().commit(); } - private static List createUserList() { - LinkedList users = new LinkedList(); - users.add(getDefaultUserAdmin1()); - users.add(getDefaultUserAdmin2()); - users.add(getDefaultUserDesigner1()); - users.add(getDefaultUserDesigner2()); - users.add(getDefaultUserTester1()); - users.add(getDefaultUserTester2()); - users.add(getDefaultUserTester3()); - users.add(getDefaultUserGovernor1()); - users.add(getDefaultUserGovernor2()); - users.add(getDefaultUserOps1()); - users.add(getDefaultUserOps2()); - users.add(getDefaultUserProductManager1()); - users.add(getDefaultUserProductManager2()); - users.add(getDefaultUserProductStrategist1()); - users.add(getDefaultUserProductStrategist2()); - users.add(getDefaultUserProductStrategist3()); - return users; + private static void createUser(UserData user) { + Map checkedProperties = new HashMap<>(); + checkedProperties.put(GraphPropertiesDictionary.USERID.getProperty(), user.getUserId()); + checkedProperties.put(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.User.getName()); + Map properties = null; + if (!isVertexExist(checkedProperties)) { + Vertex vertex = graph.addVertex(); + vertex.property(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.User.getName()); + properties = user.toGraphMap(); + for (Map.Entry entry : properties.entrySet()) { + vertex.property(entry.getKey(), entry.getValue()); + } + } } - private static UserData getDefaultUserAdmin1() { + private static UserData getDefaultUserAdmin() { UserData userData = new UserData(); userData.setAction(ActionEnum.Create); userData.setElementType(GraphElementTypeEnum.Node); @@ -128,215 +103,6 @@ public class TitanGraphInitializer { return userData; } - private static UserData getDefaultUserAdmin2() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("tr0001"); - userData.setEmail("admin@sdc.com"); - userData.setFirstName("Todd"); - userData.setLastName("Rundgren"); - userData.setRole("ADMIN"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserDesigner1() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("cs0008"); - userData.setEmail("designer@sdc.com"); - userData.setFirstName("Carlos"); - userData.setLastName("Santana"); - userData.setRole("DESIGNER"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserDesigner2() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("me0009"); - userData.setEmail("designer@sdc.com"); - userData.setFirstName("Melissa"); - userData.setLastName("Etheridge"); - userData.setRole("DESIGNER"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserTester1() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("jm0007"); - userData.setEmail("tester@sdc.com"); - userData.setFirstName("Joni"); - userData.setLastName("Mitchell"); - userData.setRole("TESTER"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserTester2() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("kb0004"); - userData.setEmail("tester@sdc.com"); - userData.setFirstName("Kate"); - userData.setLastName("Bush"); - userData.setRole("TESTER"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserTester3() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("jt0005"); - userData.setEmail("tester@sdc.com"); - userData.setFirstName("James"); - userData.setLastName("Taylor"); - userData.setRole("TESTER"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserOps1() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("op0001"); - userData.setEmail("ops@sdc.com"); - userData.setFirstName("Steve"); - userData.setLastName("Regev"); - userData.setRole("OPS"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserOps2() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("af0006"); - userData.setEmail("designer@sdc.com"); - userData.setFirstName("Aretha"); - userData.setLastName("Franklin"); - userData.setRole("OPS"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserGovernor1() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("gv0001"); - userData.setEmail("governor@sdc.com"); - userData.setFirstName("David"); - userData.setLastName("Shadmi"); - userData.setRole("GOVERNOR"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserGovernor2() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("ah0002"); - userData.setEmail("admin@sdc.com"); - userData.setFirstName("Alex"); - userData.setLastName("Harvey"); - userData.setRole("GOVERNOR"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserProductManager1() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("pm0001"); - userData.setEmail("pm1@sdc.com"); - userData.setFirstName("Teddy"); - userData.setLastName("Isashar"); - userData.setRole("PRODUCT_MANAGER"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserProductManager2() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("pm0002"); - userData.setEmail("pm2@sdc.com"); - userData.setFirstName("Sarah"); - userData.setLastName("Bettens"); - userData.setRole("PRODUCT_MANAGER"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserProductStrategist1() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("ps0001"); - userData.setEmail("ps1@sdc.com"); - userData.setFirstName("Eden"); - userData.setLastName("Rozin"); - userData.setRole("PRODUCT_STRATEGIST"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserProductStrategist2() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("ps0002"); - userData.setEmail("ps2@sdc.com"); - userData.setFirstName("Ella"); - userData.setLastName("Kvetny"); - userData.setRole("PRODUCT_STRATEGIST"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } - - private static UserData getDefaultUserProductStrategist3() { - UserData userData = new UserData(); - userData.setAction(ActionEnum.Create); - userData.setElementType(GraphElementTypeEnum.Node); - userData.setUserId("ps0003"); - userData.setEmail("ps3@sdc.com"); - userData.setFirstName("Geva"); - userData.setLastName("Alon"); - userData.setRole("PRODUCT_STRATEGIST"); - userData.setStatus(UserStatusEnum.ACTIVE.name()); - userData.setLastLoginTime(0L); - return userData; - } private static void createVertexIndixes() { logger.info("** createVertexIndixes started"); @@ -399,6 +165,6 @@ public class TitanGraphInitializer { private static void createIndexesAndDefaults() { createVertexIndixes(); createEdgeIndixes(); - createDefaultUsers(); + createDefaultAdminUser(); } } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/Migration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/Migration1707Task.java similarity index 63% rename from asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/Migration.java rename to asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/Migration1707Task.java index d74bae6087..92e185dbd7 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/Migration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/Migration1707Task.java @@ -1,6 +1,10 @@ package org.openecomp.sdc.asdctool.impl.migration; -public interface Migration { +/** + * for 1707 migration only!!! + * please don't implement this interface unless you are sure you want to run with 1707 migration classes + */ +public interface Migration1707Task { /** * performs a migration operation diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1604/AppConfig.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1604/AppConfig.java index 514c28b9b1..25132caf28 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1604/AppConfig.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1604/AppConfig.java @@ -27,9 +27,11 @@ import org.openecomp.sdc.asdctool.impl.migration.v1610.TitanFixUtils; import org.openecomp.sdc.asdctool.impl.migration.v1610.ToscaArtifactsAlignment; import org.openecomp.sdc.asdctool.impl.migration.v1702.DataTypesUpdate; import org.openecomp.sdc.asdctool.impl.migration.v1702.Migration1702; -import org.openecomp.sdc.asdctool.impl.migration.v1707.VfModulesPropertiesAdding; +import org.openecomp.sdc.asdctool.impl.migration.v1707.Migration1707RelationsFix; +import org.openecomp.sdc.asdctool.impl.migration.v1707.Migration1707VnfFix; import org.openecomp.sdc.be.auditing.api.IAuditingManager; import org.openecomp.sdc.be.auditing.impl.AuditingManager; +import org.openecomp.sdc.be.components.ArtifactsResolver; import org.openecomp.sdc.be.components.distribution.engine.IDistributionEngine; import org.openecomp.sdc.be.components.distribution.engine.ServiceDistributionArtifactsBuilder; import org.openecomp.sdc.be.components.impl.*; @@ -51,7 +53,32 @@ import org.openecomp.sdc.be.model.operations.api.IAdditionalInformationOperation import org.openecomp.sdc.be.model.operations.api.IElementOperation; import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; import org.openecomp.sdc.be.model.operations.api.IUserAdminOperation; -import org.openecomp.sdc.be.model.operations.impl.*; +import org.openecomp.sdc.be.model.operations.impl.AdditionalInformationOperation; +import org.openecomp.sdc.be.model.operations.impl.ArtifactOperation; +import org.openecomp.sdc.be.model.operations.impl.AttributeOperation; +import org.openecomp.sdc.be.model.operations.impl.CacheMangerOperation; +import org.openecomp.sdc.be.model.operations.impl.CapabilityInstanceOperation; +import org.openecomp.sdc.be.model.operations.impl.CapabilityOperation; +import org.openecomp.sdc.be.model.operations.impl.CapabilityTypeOperation; +import org.openecomp.sdc.be.model.operations.impl.ComponentInstanceOperation; +import org.openecomp.sdc.be.model.operations.impl.ConsumerOperation; +import org.openecomp.sdc.be.model.operations.impl.CsarOperation; +import org.openecomp.sdc.be.model.operations.impl.ElementOperation; +import org.openecomp.sdc.be.model.operations.impl.GraphLockOperation; +import org.openecomp.sdc.be.model.operations.impl.GroupInstanceOperation; +import org.openecomp.sdc.be.model.operations.impl.GroupOperation; +import org.openecomp.sdc.be.model.operations.impl.GroupTypeOperation; +import org.openecomp.sdc.be.model.operations.impl.HeatParametersOperation; +import org.openecomp.sdc.be.model.operations.impl.InputsOperation; +import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; +import org.openecomp.sdc.be.model.operations.impl.LifecycleOperation; +import org.openecomp.sdc.be.model.operations.impl.OnboardingClient; +import org.openecomp.sdc.be.model.operations.impl.ProductOperation; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.be.model.operations.impl.RequirementOperation; +import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; +import org.openecomp.sdc.be.model.operations.impl.ServiceOperation; +import org.openecomp.sdc.be.model.operations.impl.UserAdminOperation; import org.openecomp.sdc.be.tosca.CsarUtils; import org.openecomp.sdc.be.tosca.ToscaExportHandler; import org.openecomp.sdc.be.user.IUserBusinessLogic; @@ -66,6 +93,11 @@ import org.springframework.context.annotation.Primary; @Import(DAOSpringConfig.class) public class AppConfig { + @Bean(name="artifact-resolver") + public ArtifactsResolver artifactsResolver() { + return new ArtifactResolverImpl(); + } + @Bean(name = "sdc-schema-files-cassandra-dao") public SdcSchemaFilesCassandraDao sdcSchemaFilesCassandraDao() { return new SdcSchemaFilesCassandraDao(); @@ -543,9 +575,22 @@ public class AppConfig { return new MigrationOperationUtils(); } - @Bean(name = "vfModulesPropertiesAdding") - public VfModulesPropertiesAdding vfModulesPropertiesAdding() { - return new VfModulesPropertiesAdding(); - } + @Bean("consumer-operation") + public ConsumerOperation consumerOperation(@Qualifier("titan-generic-dao") TitanGenericDao titanGenericDao) { + return new ConsumerOperation(titanGenericDao); + } + @Bean(name = "migration1707relationsFix") + public Migration1707RelationsFix migration1707RelationsFix() { + return new Migration1707RelationsFix(); + } + @Bean(name = "migration1707vnfFix") + public Migration1707VnfFix migration1707VnfFix() { + return new Migration1707VnfFix(); + } + +// @Bean(name = "migration1707relationsFix") +// public Migration1707RelationsFix migration1707RelationsFix() { +// return new Migration1707RelationsFix(); +// } } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1702/Migration1702.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1702/Migration1702.java index 861e9136a3..6fa8b45734 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1702/Migration1702.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1702/Migration1702.java @@ -1036,10 +1036,8 @@ public class Migration1702 { property.setName(fe.getKey()); Map definitionInYaml = (Map) fe.getValue(); property.setType((String) definitionInYaml.get("type")); - // Fix by Tal G property.setRequired((Boolean) definitionInYaml.get("required")); property.setDescription((String) definitionInYaml.get("description")); - // Fix by Tal G String defaultValue = definitionInYaml.get("default") == null ? null : definitionInYaml.get("default").toString(); if (defaultValue != null) { property.setDefaultValue(defaultValue); diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/DistributionStatusUpdate.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/DistributionStatusUpdate.java new file mode 100644 index 0000000000..7c0b57fb1d --- /dev/null +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/DistributionStatusUpdate.java @@ -0,0 +1,140 @@ +package org.openecomp.sdc.asdctool.impl.migration.v1707; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import org.apache.commons.collections.MapUtils; +import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; +import org.openecomp.sdc.be.dao.jsongraph.TitanDao; +import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; +import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +@Component("distributionStatusUpdate") +public class DistributionStatusUpdate { + private static Logger LOGGER = LoggerFactory.getLogger(DistributionStatusUpdate.class); + + @Autowired + private ToscaOperationFacade toscaOperationFacade; + @Autowired + private TitanDao titanDao; + + + public boolean migrate() { + boolean result = true; + Either, StorageOperationStatus> getAllServiceComponentsRes = getAllServiceComponents(); + if(getAllServiceComponentsRes.isRight()){ + result = false; + } + if(result && MapUtils.isNotEmpty(getAllServiceComponentsRes.left().value())){ + updateDistributionStatusFromMetadata(getAllServiceComponentsRes.left().value()); + updateDistributionStatusToNotDistributed(getAllServiceComponentsRes.left().value()); + } + + toscaOperationFacade.commit(); + + return result; + } + + + private void updateDistributionStatusToNotDistributed(Map components) { + + Map filteredComponents = components.entrySet() + .stream() + .filter(e -> e.getValue().getLifecycleState() != LifecycleStateEnum.CERTIFIED) + .collect(Collectors.toMap(e -> e.getKey(), e -> (Service)e.getValue())); + + Service service; + Either updateResponse; + GraphVertex metadataV; + + for(Entry currComponent : filteredComponents.entrySet()){ + metadataV = currComponent.getKey(); + service = currComponent.getValue(); + try { + metadataV.addMetadataProperty(GraphPropertyEnum.DISTRIBUTION_STATUS, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + updateResponse = titanDao.updateVertex(metadataV); + + if (updateResponse.isRight()) { + LOGGER.debug("failed to updateDistributionStatusToNotDistributed service {} error {}", service.getUniqueId(), updateResponse.right().value()); + } + + } catch (Exception e) { + LOGGER.debug("failed to updateDistributionStatusToNotDistributed service {} error {}", service.getUniqueId(), e.toString()); + } + } + } + + private void updateDistributionStatusFromMetadata(Map components) { + Service service; + String statusFromMetadata; + Either updateResponse; + GraphVertex metadataV; + + for(Entry currComponent : components.entrySet()){ + metadataV = currComponent.getKey(); + service = currComponent.getValue(); + try { + statusFromMetadata = (String) metadataV.getJsonMetadataField(JsonPresentationFields.DISTRIBUTION_STATUS); + metadataV.addMetadataProperty(GraphPropertyEnum.DISTRIBUTION_STATUS, statusFromMetadata); + updateResponse = titanDao.updateVertex(metadataV); + + if (updateResponse.isRight()) { + LOGGER.debug("failed to updateDistributionStatusFromMetadata service {} error {}", service.getUniqueId(), updateResponse.right().value()); + } + + } catch (Exception e) { + LOGGER.debug("failed to read distribution status of service {} error {}", service.getUniqueId(), e.toString()); + } + + } + } + + + public Either, StorageOperationStatus> getAllServiceComponents() { + + Map components = new HashMap<>(); + Map propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); + Map propertiesNotMatch = new EnumMap<>(GraphPropertyEnum.class); + propertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name()); + propertiesNotMatch.put(GraphPropertyEnum.IS_DELETED, true); + Either, TitanOperationStatus> getVerticiesRes = toscaOperationFacade.getTitanDao().getByCriteria(null, propertiesToMatch, propertiesNotMatch, JsonParseFlagEnum.ParseAll); + + if (getVerticiesRes.isRight() && getVerticiesRes.right().value() != TitanOperationStatus.NOT_FOUND) { + LOGGER.debug("Failed to fetch all service components. Status is {}", getVerticiesRes.right().value()); + return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getVerticiesRes.right().value())); + } + if(getVerticiesRes.isLeft()){ + List componentVerticies = getVerticiesRes.left().value(); + for (GraphVertex componentV : componentVerticies) { + ComponentParametersView filters = new ComponentParametersView(true); + Either getComponentsRes = toscaOperationFacade.getToscaElement(componentV.getUniqueId(), filters); + if (getComponentsRes.isRight()) { + return Either.right(getComponentsRes.right().value()); + } + components.put(componentV, (Service) getComponentsRes.left().value()); + } + } + return Either.left(components); + } + +} diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707.java index be40e4cd0d..84214cc0b0 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707.java @@ -1,27 +1,29 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707; -import org.openecomp.sdc.asdctool.impl.migration.Migration; +import org.openecomp.sdc.asdctool.impl.migration.Migration1707Task; +import org.openecomp.sdc.be.config.ConfigurationManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.annotation.Resource; import java.util.List; +import java.util.Optional; @Component("migration1707") public class Migration1707 { private static Logger LOGGER = LoggerFactory.getLogger(Migration1707.class); - private List migrations; + private List migrations; - public Migration1707(List migrations) { + public Migration1707(List migrations) { this.migrations = migrations; } public boolean migrate() { - for (Migration migration : migrations) { + int startMigrationFrom = Optional.ofNullable(ConfigurationManager.getConfigurationManager().getConfiguration().getStartMigrationFrom()).orElse(0); + List migrations = this.migrations.subList(startMigrationFrom, this.migrations.size()); + for (Migration1707Task migration : migrations) { LOGGER.info(String.format("Starting migration. %s", migration.description())); boolean migrationCompletedSuccessfully = migration.migrate(); if (!migrationCompletedSuccessfully) { @@ -33,5 +35,4 @@ public class Migration1707 { return true; } - } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707Config.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707Config.java index 9c39b58404..eeb29d67c2 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707Config.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707Config.java @@ -3,19 +3,8 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707; import java.util.List; -import org.openecomp.sdc.asdctool.impl.migration.Migration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.MigrationByIdDerivedNodeTypeResolver; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.NormativesMigration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.NormativesResolver; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.ResourceVersionMigration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.ResourcesCategoriesMigration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.ServiceCategoriesMigration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.ServiceVersionMigration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.ServicesMigration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.UserStatesMigration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.UsersMigration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.VFResourcesMigration; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.VersionMigration; +import org.openecomp.sdc.asdctool.impl.migration.Migration1707Task; +import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.*; import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.relations.FulfilledCapabilitiesMigrationService; import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.relations.FulfilledRequirementsMigrationService; import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.relations.RequirementsCapabilitiesMigrationService; @@ -37,6 +26,7 @@ import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.operations.api.IElementOperation; import org.openecomp.sdc.be.model.operations.api.IUserAdminOperation; import org.openecomp.sdc.be.model.operations.api.ToscaDefinitionPathCalculator; +import org.openecomp.sdc.be.model.operations.impl.ConsumerOperation; import org.openecomp.sdc.be.model.operations.impl.ElementOperation; import org.openecomp.sdc.be.model.operations.impl.GroupTypeOperation; import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; @@ -45,6 +35,7 @@ import org.openecomp.sdc.be.model.operations.impl.UserAdminOperation; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.core.annotation.Order; @Configuration @@ -52,69 +43,72 @@ public class Migration1707Config { @Bean(name = "migration1707") - public Migration1707 migration1707(List migrations) { + public Migration1707 migration1707(List migrations) { return new Migration1707(migrations); } - @Bean(name = "renameGraphPropertyKeysMigration") - @Order(1) - public Migration renameGraphPropertyKeysMigration() { - return new RenameGraphPropertyKeys(); - } + //@Bean(name = "renameGraphPropertyKeysMigration") + //@Order(1) + //public Migration1707Task renameGraphPropertyKeysMigration() { + // return new RenameGraphPropertyKeys(); + // } - @Bean(name = "toscaNamesUpdate") - @Order(2) - public Migration toscaNamesUpdate() { - return new ToscaNamesUpdate(); - } + //@Bean(name = "toscaNamesUpdate") + //@Order(2) + //public Migration1707Task toscaNamesUpdate() { + // return new ToscaNamesUpdate(); + //} @Bean(name = "users-migration") - @Order(3) - public Migration usersMigration() { + @Order(1) + public Migration1707Task usersMigration() { return new UsersMigration(); } @Bean(name = "resource-category-migration") - @Order(4) - public Migration resourceCategoriesMigration() { + @Order(2) + public Migration1707Task resourceCategoriesMigration() { return new ResourcesCategoriesMigration(); } @Bean(name = "service-category-migration") - @Order(5) - public Migration serviceCategoriesMigration() { + @Order(3) + public Migration1707Task serviceCategoriesMigration() { return new ServiceCategoriesMigration(); } @Bean(name = "normatives-migration") - @Order(6) - public Migration normativesMigration() { + @Order(4) + public Migration1707Task normativesMigration() { return new NormativesMigration(); } @Bean(name = "vf-migration") - @Order(7) - public Migration vfMigration() { + @Order(5) + public Migration1707Task vfMigration() { return new VFResourcesMigration(); } @Bean(name = "service-migration") - @Order(8) - public Migration serviceMigration() { + @Order(6) + public Migration1707Task serviceMigration() { return new ServicesMigration(); } - @Bean(name = "user-states-migration") - @Order(9) - public Migration userStatesMigration() { - return new UserStatesMigration(); + @Bean(name = "consumers-migration") + @Order(7) + public Migration1707Task consumersMigration() { return new ConsumersMigration(); } + + @Bean(name = "tosca-template-regeneration") + @Order(8) + public Migration1707Task ToscaTemplateRegeneration() { + return new ToscaTemplateRegeneration(); + } + + @Bean(name = "distributionStatusUpdate") + public DistributionStatusUpdate distributionStatusUpdate() { + return new DistributionStatusUpdate(); } - -// @Bean(name = "tosca-template-regeneration") -// @Order(10) -// public Migration ToscaTemplateRegeneration() { -// return new ToscaTemplateRegeneration(); -// } @Bean("resource-version-migration") public VersionMigration resourceVersionMigration() { @@ -236,5 +230,20 @@ public class Migration1707Config { return new MigrationByIdDerivedNodeTypeResolver(); } + @Bean(name = "invariant-uuid-resolver") + public InvariantUUIDResolver invariantUUIDResolver() { + return new InvariantUUIDResolver(); + } + + @Bean(name="consumer-operation-mig") + @Primary + public ConsumerOperation consumerOperation(@Qualifier("titan-generic-dao-migration") TitanGenericDao titanGenericDao) { + return new ConsumerOperation(titanGenericDao); + } + + @Bean(name = "vfModulesPropertiesAdding") + public VfModulesPropertiesAdding vfModulesPropertiesAdding() { + return new VfModulesPropertiesAdding(); + } } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707RelationsFix.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707RelationsFix.java new file mode 100644 index 0000000000..47bce78893 --- /dev/null +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707RelationsFix.java @@ -0,0 +1,131 @@ +package org.openecomp.sdc.asdctool.impl.migration.v1707; + +import java.util.EnumMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; +import org.openecomp.sdc.be.dao.jsongraph.TitanDao; +import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum; +import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; +import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; +import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import fj.data.Either; +@Component("migration1707relationsFix") +public class Migration1707RelationsFix { + + private static Logger LOGGER = LoggerFactory.getLogger(Migration1707RelationsFix.class); + + @Autowired + private TitanDao titanDao; + + public boolean migrate() { + boolean result = true; + + try{ + Map propsHasNot = new EnumMap<>(GraphPropertyEnum.class); + propsHasNot.put(GraphPropertyEnum.IS_DELETED, true); + Either, TitanOperationStatus> getAllTopologyTemplatesRes = titanDao.getByCriteria(VertexTypeEnum.TOPOLOGY_TEMPLATE, null, propsHasNot, JsonParseFlagEnum.ParseMetadata); + if (getAllTopologyTemplatesRes.isRight() && getAllTopologyTemplatesRes.right().value() != TitanOperationStatus.NOT_FOUND) { + LOGGER.debug("Failed to fetch all non marked as deleted topology templates , error {}", getAllTopologyTemplatesRes.right().value()); + result = false; + } + if(getAllTopologyTemplatesRes.isLeft()){ + fixComponentsRelations(getAllTopologyTemplatesRes.left().value()); + } + if(result){ + Either, TitanOperationStatus> getAllNodeTypesRes = titanDao.getByCriteria(VertexTypeEnum.NODE_TYPE, null, propsHasNot, JsonParseFlagEnum.ParseMetadata); + if (getAllNodeTypesRes.isRight() && getAllNodeTypesRes.right().value() != TitanOperationStatus.NOT_FOUND) { + LOGGER.debug("Failed to fetch all non marked as deleted node types , error {}", getAllNodeTypesRes.right().value()); + result = false; + } + if(getAllNodeTypesRes.isLeft()){ + fixComponentsRelations(getAllNodeTypesRes.left().value()); + } + } + } catch (Exception e){ + LOGGER.debug("The exception {} occured upon migration 1707 relations fixing. ", e.getMessage()); + e.printStackTrace(); + result = false; + } + finally{ + if(result){ + titanDao.commit(); + } else { + titanDao.rollback(); + } + } + return result; + } + + private void fixComponentsRelations(List notDeletedComponentVerticies) { + notDeletedComponentVerticies.stream().forEach(this::fixComponentRelations); + } + + private void fixComponentRelations(GraphVertex componentV) { + fixCreatorComponentRelation(componentV); + fixLastModifierComponentRelation(componentV); + fixStateComponentRelation(componentV); + } + + private void fixStateComponentRelation(GraphVertex componentV) { + boolean relevantEdgeFound = false; + Iterator edges = componentV.getVertex().edges(Direction.IN, EdgeLabelEnum.STATE.name()); + String getState = (String) componentV.getJsonMetadataField(JsonPresentationFields.LIFECYCLE_STATE); + while(edges.hasNext()){ + Edge edge = edges.next(); + String edgeState = (String) edge.property(GraphPropertyEnum.STATE.getProperty()).orElse(null); + if(getState.equals(edgeState) && !relevantEdgeFound){ + relevantEdgeFound = true; + } else { + removeEdge(edge); + } + } + } + + private void fixCreatorComponentRelation(GraphVertex componentV) { + boolean relevantUserFound = false; + Iterator edges = componentV.getVertex().edges(Direction.IN, EdgeLabelEnum.CREATOR.name()); + String getCreatorUserId = (String) componentV.getJsonMetadataField(JsonPresentationFields.USER_ID_CREATOR); + while(edges.hasNext()){ + Edge edge = edges.next(); + String userId = (String) edge.outVertex().property(GraphPropertyEnum.USERID.getProperty()).orElse(null); + if(getCreatorUserId.equals(userId) && !relevantUserFound){ + relevantUserFound = true; + } else { + removeEdge(edge); + } + } + } + + private void fixLastModifierComponentRelation(GraphVertex componentV) { + boolean relevantUserFound = false; + Iterator edges = componentV.getVertex().edges(Direction.IN, EdgeLabelEnum.LAST_MODIFIER.name()); + String getLastUpdaterUserId = (String) componentV.getJsonMetadataField(JsonPresentationFields.USER_ID_LAST_UPDATER); + while(edges.hasNext()){ + Edge edge = edges.next(); + String updaterId = (String) edge.outVertex().property(GraphPropertyEnum.USERID.getProperty()).orElse(null); + if(getLastUpdaterUserId.equals(updaterId) && !relevantUserFound){ + relevantUserFound = true; + } else { + removeEdge(edge); + } + } + } + + private void removeEdge(Edge edge) { + LOGGER.debug("Going to remove edge {} upon migration 1707 relations fixing. ", edge.id()); + edge.remove(); + LOGGER.debug("The edge {} has been removed. ", edge.id()); + } + +} diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707VnfFix.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707VnfFix.java new file mode 100644 index 0000000000..d3bd494a85 --- /dev/null +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/Migration1707VnfFix.java @@ -0,0 +1,100 @@ +package org.openecomp.sdc.asdctool.impl.migration.v1707; + +import java.util.EnumMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; +import org.openecomp.sdc.be.dao.jsongraph.TitanDao; +import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum; +import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; +import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum; +import org.openecomp.sdc.be.dao.jsongraph.utils.JsonParserUtils; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.jsontitan.operations.TopologyTemplateOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.thinkaurelius.titan.core.TitanVertex; + +import fj.data.Either; + +@Component("migration1707vnfFix") +public class Migration1707VnfFix{ + + private static final String VF_MODULES_METADATA = "vfModulesMetadata"; + + @Autowired + private TitanDao titanDao; + + @Autowired + private TopologyTemplateOperation topologyTemplateOperation; + + private static Logger LOGGER = LoggerFactory.getLogger(Migration1707RelationsFix.class); + + public boolean migrate() { + boolean result = true; + + Map propsHasNot = new EnumMap<>(GraphPropertyEnum.class); + propsHasNot.put(GraphPropertyEnum.IS_DELETED, true); + + Map propsHas = new EnumMap<>(GraphPropertyEnum.class); + propsHas.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE.name()); + propsHas.put(GraphPropertyEnum.RESOURCE_TYPE, ResourceTypeEnum.VF.name()); + propsHas.put(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED); + + Either, TitanOperationStatus> getAllTopologyTemplatesRes = titanDao.getByCriteria(VertexTypeEnum.TOPOLOGY_TEMPLATE, null, propsHasNot, JsonParseFlagEnum.ParseMetadata); + if (getAllTopologyTemplatesRes.isRight() && getAllTopologyTemplatesRes.right().value() != TitanOperationStatus.NOT_FOUND) { + LOGGER.debug("Failed to fetch all non marked as deleted topology templates , error {}", getAllTopologyTemplatesRes.right().value()); + result = false; + } + List metadataVertices = getAllTopologyTemplatesRes.left().value(); + for (GraphVertex metadataV : metadataVertices) { + Either, TitanOperationStatus> dataFromGraph = topologyTemplateOperation.getDataFromGraph(metadataV.getUniqueId(), EdgeLabelEnum.DEPLOYMENT_ARTIFACTS); + if (dataFromGraph.isLeft()) { + Map artifacts = dataFromGraph.left().value(); + if (artifacts.containsKey(VF_MODULES_METADATA)) { + artifacts.remove(VF_MODULES_METADATA); + Either vertexById = titanDao.getVertexById(metadataV.getUniqueId()); + TitanVertex vertex = vertexById.left().value().getVertex(); + Iterator edges = vertex.edges(Direction.OUT, EdgeLabelEnum.DEPLOYMENT_ARTIFACTS.name()); + if (edges.hasNext()) { + Edge edge = edges.next(); + Vertex dataV = edge.inVertex(); + + String jsonStr; + try { + jsonStr = JsonParserUtils.jsonToString(artifacts); + dataV.property(GraphPropertyEnum.JSON.getProperty(), jsonStr); + } catch (Exception e) { + LOGGER.debug("Failed to update deployment artifacts for VF {}", metadataV.getUniqueId()); + } + } + } + } + TitanOperationStatus commit = titanDao.commit(); + if ( commit != TitanOperationStatus.OK){ + LOGGER.debug("Failed to commit changes for deployment artifacts for VF {} {}", metadataV.getUniqueId(), metadataV.getMetadataProperty(GraphPropertyEnum.NAME)); + } + } + + return result; + } + + public String description() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/RenameGraphPropertyKeys.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/RenameGraphPropertyKeys.java index a69fb9d011..a1c1b6b4cc 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/RenameGraphPropertyKeys.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/RenameGraphPropertyKeys.java @@ -1,8 +1,6 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707; -import org.openecomp.sdc.asdctool.impl.migration.MigrationMsg; -import org.openecomp.sdc.asdctool.impl.migration.Migration; -import org.openecomp.sdc.asdctool.impl.migration.MigrationOperationUtils; +import org.openecomp.sdc.asdctool.impl.migration.*; import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -11,7 +9,7 @@ import java.util.HashMap; import java.util.Map; @Component("renameGraphPropertyKeysMigration") -public class RenameGraphPropertyKeys implements Migration { +public class RenameGraphPropertyKeys implements Migration1707Task { private final static Map KEY_PROPERTIES_TO_RENAME; diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/ToscaNamesUpdate.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/ToscaNamesUpdate.java index 262c300009..5213fae619 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/ToscaNamesUpdate.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/ToscaNamesUpdate.java @@ -8,7 +8,7 @@ import java.util.function.Function; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutableTriple; import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.openecomp.sdc.asdctool.impl.migration.Migration; +import org.openecomp.sdc.asdctool.impl.migration.Migration1707Task; import org.openecomp.sdc.be.dao.graph.GraphElementFactory; import org.openecomp.sdc.be.dao.graph.datatype.GraphElementTypeEnum; import org.openecomp.sdc.be.dao.graph.datatype.GraphNode; @@ -46,7 +46,7 @@ import com.thinkaurelius.titan.core.TitanVertex; import fj.data.Either; @Component("toscaNamesUpdate") -public class ToscaNamesUpdate implements Migration { +public class ToscaNamesUpdate implements Migration1707Task { private static Logger log = LoggerFactory.getLogger(ToscaNamesUpdate.class.getName()); @Override diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/ToscaTemplateRegeneration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/ToscaTemplateRegeneration.java index 824bb83ec9..09e52619f0 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/ToscaTemplateRegeneration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/ToscaTemplateRegeneration.java @@ -1,14 +1,11 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707; import java.util.EnumMap; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import org.apache.commons.collections.MapUtils; -import org.openecomp.sdc.asdctool.impl.migration.Migration; +import org.apache.commons.collections.CollectionUtils; +import org.openecomp.sdc.asdctool.impl.migration.Migration1707Task; import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao; import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus; import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; @@ -34,7 +31,7 @@ import org.springframework.stereotype.Component; import fj.data.Either; @Component("toscaTemplateRegeneration") -public class ToscaTemplateRegeneration implements Migration { +public class ToscaTemplateRegeneration implements Migration1707Task { private static Logger LOGGER = LoggerFactory.getLogger(ToscaTemplateRegeneration.class); @@ -50,13 +47,13 @@ public class ToscaTemplateRegeneration implements Migration { @Override public boolean migrate() { boolean result = true; - Either, StorageOperationStatus> getAllCertifiedComponentsRes; + Either, StorageOperationStatus> getAllCertifiedComponentsRes; try{ getAllCertifiedComponentsRes = getAllCertifiedComponents(); if(getAllCertifiedComponentsRes.isRight()){ result = false; } - if(result && MapUtils.isNotEmpty(getAllCertifiedComponentsRes.left().value())){ + if(result && CollectionUtils.isNotEmpty(getAllCertifiedComponentsRes.left().value())){ result = regenerateToscaTemplateArtifacts(getAllCertifiedComponentsRes.left().value()); } } catch(Exception e){ @@ -72,17 +69,21 @@ public class ToscaTemplateRegeneration implements Migration { return result; } - private boolean regenerateToscaTemplateArtifacts(Map components) { + private boolean regenerateToscaTemplateArtifacts(List components) { boolean result = true; - - Map filteredComponents = components.entrySet() - .stream() - .filter(e -> e.getValue().getToscaArtifacts()!=null && e.getValue().getToscaArtifacts().containsKey(ToscaExportHandler.ASSET_TOSCA_TEMPLATE)) - .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())); - - for(Entry currComponent : filteredComponents.entrySet()){ - result = regenerateToscaTemplateArtifact(currComponent); - if(!result){ + for(GraphVertex componentV : components){ + Either getComponentsRes = toscaOperationFacade.getToscaElement(componentV); + if (getComponentsRes.isRight()) { + result = false; + break; + } + if(getComponentsRes.left().value().getToscaArtifacts()!=null && getComponentsRes.left().value().getToscaArtifacts().containsKey(ToscaExportHandler.ASSET_TOSCA_TEMPLATE)){ + result = regenerateToscaTemplateArtifact(getComponentsRes.left().value(), componentV); + } + if(result){ + toscaOperationFacade.commit(); + } else { + toscaOperationFacade.rollback(); break; } } @@ -90,26 +91,26 @@ public class ToscaTemplateRegeneration implements Migration { } @SuppressWarnings("unchecked") - private boolean regenerateToscaTemplateArtifact(Map.Entry parent) { + private boolean regenerateToscaTemplateArtifact(org.openecomp.sdc.be.model.Component parent, GraphVertex parentV) { boolean result = true; Either toscaDataVertexRes = null; ArtifactDataDefinition data = null; LOGGER.debug("tosca artifact generation"); - Either exportComponent = toscaExportUtils.exportComponent(parent.getValue()); + Either exportComponent = toscaExportUtils.exportComponent(parent); if (exportComponent.isRight()) { - LOGGER.debug("Failed export tosca yaml for component {} error {}", parent.getValue().getUniqueId(), exportComponent.right().value()); + LOGGER.debug("Failed export tosca yaml for component {} error {}", parent.getUniqueId(), exportComponent.right().value()); result = false; } if(result){ - LOGGER.debug("Tosca yaml exported for component {} ", parent.getValue().getUniqueId()); - toscaDataVertexRes = toscaOperationFacade.getTitanDao().getChildVertex(parent.getKey(), EdgeLabelEnum.TOSCA_ARTIFACTS, JsonParseFlagEnum.ParseJson); + LOGGER.debug("Tosca yaml exported for component {} ", parent.getUniqueId()); + toscaDataVertexRes = toscaOperationFacade.getTitanDao().getChildVertex(parentV, EdgeLabelEnum.TOSCA_ARTIFACTS, JsonParseFlagEnum.ParseJson); if(toscaDataVertexRes.isRight()){ - LOGGER.debug("Failed to fetch tosca data vertex {} for component {}. Status is {}", EdgeLabelEnum.TOSCA_ARTIFACTS, parent.getValue().getUniqueId(), exportComponent.right().value()); + LOGGER.debug("Failed to fetch tosca data vertex {} for component {}. Status is {}", EdgeLabelEnum.TOSCA_ARTIFACTS, parent.getUniqueId(), exportComponent.right().value()); result = false; } } if(result){ - data = parent.getValue().getToscaArtifacts().get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); + data = parent.getToscaArtifacts().get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); data.setArtifactChecksum(GeneralUtility.calculateMD5ByByteArray(exportComponent.left().value().getMainYaml().getBytes())); ((Map) toscaDataVertexRes.left().value().getJson()).put(ToscaExportHandler.ASSET_TOSCA_TEMPLATE, data); @@ -129,26 +130,19 @@ public class ToscaTemplateRegeneration implements Migration { return result; } - public Either, StorageOperationStatus> getAllCertifiedComponents() { + public Either, StorageOperationStatus> getAllCertifiedComponents() { - Map components = new HashMap<>(); Map propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); propertiesToMatch.put(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED.name()); - Either, TitanOperationStatus> getVerticiesRes = toscaOperationFacade.getTitanDao().getByCriteria(null, propertiesToMatch,JsonParseFlagEnum.ParseAll); + List components = null; + Either, TitanOperationStatus> getVerticiesRes = toscaOperationFacade.getTitanDao().getByCriteria(null, propertiesToMatch,JsonParseFlagEnum.ParseMetadata); if (getVerticiesRes.isRight() && getVerticiesRes.right().value() != TitanOperationStatus.NOT_FOUND) { LOGGER.debug("Failed to fetch all certified components. Status is {}", getVerticiesRes.right().value()); return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getVerticiesRes.right().value())); } if(getVerticiesRes.isLeft()){ - List componentVerticies = getVerticiesRes.left().value(); - for (GraphVertex componentV : componentVerticies) { - Either getComponentsRes = toscaOperationFacade.getToscaElement(componentV); - if (getComponentsRes.isRight()) { - return Either.right(getComponentsRes.right().value()); - } - components.put(componentV, getComponentsRes.left().value()); - } + components = getVerticiesRes.left().value(); } return Either.left(components); } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/VfModulesPropertiesAdding.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/VfModulesPropertiesAdding.java index 5b1441903f..ca1ed2b2a8 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/VfModulesPropertiesAdding.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/VfModulesPropertiesAdding.java @@ -13,10 +13,12 @@ import javax.annotation.Resource; import org.apache.commons.collections.CollectionUtils; import org.openecomp.sdc.asdctool.impl.migration.v1702.DataTypesUpdate; import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; +import org.openecomp.sdc.be.dao.jsongraph.TitanDao; import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum; import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; @@ -45,7 +47,7 @@ import fj.data.Either; @Component("vfModulesPropertiesAdding") public class VfModulesPropertiesAdding { - private static Logger LOGGER = LoggerFactory.getLogger(ToscaTemplateRegeneration.class); + private static Logger LOGGER = LoggerFactory.getLogger(VfModulesPropertiesAdding.class); @Autowired private ToscaOperationFacade toscaOperationFacade; @@ -61,25 +63,35 @@ public class VfModulesPropertiesAdding { public boolean migrate(String groupsTypeYmlFilePath) { + LOGGER.debug("Going to add new properties to vfModules. "); boolean result = true; - Either, StorageOperationStatus> getAllComponentsRes = null; GroupTypeDefinition vfModule; Either, TitanOperationStatus> getAllTopologyTemplatesRes = null; - List newProperties = null; - + String vfModuleUid = "org.openecomp.groups.VfModule.1.0.grouptype"; Either getGroupTypeVfModuleRes ; + List updatedProperties = null; try{ - getGroupTypeVfModuleRes = groupTypeOperation.getGroupTypeByUid("org.openecomp.groups.VfModule.1.0.grouptype"); + LOGGER.debug("Going to fetch {}. ", vfModuleUid); + getGroupTypeVfModuleRes = groupTypeOperation.getGroupTypeByUid(vfModuleUid); - if(getGroupTypeVfModuleRes.isRight()){ - result = false; + if(getGroupTypeVfModuleRes.isRight() && getGroupTypeVfModuleRes.right().value() != TitanOperationStatus.NOT_FOUND){ + LOGGER.debug("Failed to fetch the group type {}. The status is {}. ", vfModuleUid, getGroupTypeVfModuleRes.right().value()); + result = false; + } + if(getGroupTypeVfModuleRes.isRight() && getGroupTypeVfModuleRes.right().value() == TitanOperationStatus.NOT_FOUND){ + LOGGER.debug("The group type with id {} was not found. Skipping adding the new properties. ", vfModuleUid); + return true; } if(result){ + LOGGER.debug("Going to add the new properties {} to org.openecomp.groups.VfModule.1.0.grouptype. "); vfModule = getGroupTypeVfModuleRes.left().value(); - newProperties = getNewVfModuleTypeProperties(getAllVfModuleTypePropertiesFromYaml(groupsTypeYmlFilePath), vfModule); - result = addNewPropertiesToGroupType(vfModule, newProperties); + updatedProperties = getAllVfModuleTypePropertiesFromYaml(groupsTypeYmlFilePath); + result = addNewPropertiesToGroupType(vfModule, getNewVfModuleTypeProperties(updatedProperties, vfModule)); + if(!result){ + LOGGER.debug("Failed to add the new properties {} to org.openecomp.groups.VfModule.1.0.grouptype. "); + } } - if(result && CollectionUtils.isNotEmpty(newProperties)){ + if(result && CollectionUtils.isNotEmpty(updatedProperties)){ Map propsHasNot = new EnumMap<>(GraphPropertyEnum.class); propsHasNot.put(GraphPropertyEnum.IS_DELETED, true); getAllTopologyTemplatesRes = toscaOperationFacade.getTitanDao().getByCriteria(VertexTypeEnum.TOPOLOGY_TEMPLATE, null, propsHasNot, JsonParseFlagEnum.ParseAll); @@ -89,13 +101,7 @@ public class VfModulesPropertiesAdding { } } if(result && getAllTopologyTemplatesRes!=null && getAllTopologyTemplatesRes.isLeft()){ - getAllComponentsRes = getAllContainerComponents(getAllTopologyTemplatesRes.left().value()); - if(getAllComponentsRes.isRight()){ - result = false; - } - } - if(result && getAllComponentsRes != null){ - result = addNewVfModulesProperties(getAllComponentsRes.left().value(), newProperties); + result = addNewVfModulesProperties(getAllTopologyTemplatesRes.left().value(), updatedProperties); } } catch (Exception e){ result = false; @@ -110,41 +116,61 @@ public class VfModulesPropertiesAdding { return result; } - private boolean addNewVfModulesProperties(Map components, List newGroupTypeProperties) { + private boolean addNewVfModulesProperties(List components, List updatedProperties) { boolean result = true; - for(Map.Entry component : components.entrySet()){ - result = addNewPropertiesToVfModules(component, newGroupTypeProperties); + for(GraphVertex component : components){ + LOGGER.debug("Going to add the new properties {} to component {}. ", updatedProperties, component.getUniqueId()); + result = addNewPropertiesToVfModules(component, updatedProperties); if(!result){ + LOGGER.debug("Failed to add the new properties {} to component {}. ", updatedProperties, component.getUniqueId()); break; } + toscaOperationFacade.commit(); } return result; } - private boolean addNewPropertiesToVfModules(Entry component, List newGroupTypeProperties) { + private boolean addNewPropertiesToVfModules(GraphVertex componentV, List updatedProperties) { boolean result = true; List vfModules = null; - if(CollectionUtils.isNotEmpty(component.getKey().getGroups())){ - vfModules = component.getKey().getGroups().stream().filter(g -> g.getType().equals(BaseOperation.VF_MODULE)).collect(Collectors.toList()); + Either getToscaElementRes = toscaOperationFacade.getToscaElement(componentV); + if(getToscaElementRes.isRight()){ + LOGGER.debug("Failed to fetch the component {}. ", componentV.getUniqueId()); + result = false; + } + else if(CollectionUtils.isNotEmpty(getToscaElementRes.left().value().getGroups())){ + vfModules = getToscaElementRes.left().value().getGroups().stream().filter(g -> g.getType().equals(BaseOperation.VF_MODULE)).collect(Collectors.toList()); } if(vfModules != null){ - vfModules.forEach(vfModule -> vfModule.getProperties().addAll(newGroupTypeProperties)); - StorageOperationStatus status = topologyTemplateOperation.updateToscaDataOfToscaElement(component.getValue(), EdgeLabelEnum.GROUPS, VertexTypeEnum.GROUPS, vfModules, JsonPresentationFields.NAME); + vfModules.forEach(vfModule -> addAllNewProperties(vfModule.getProperties(), updatedProperties)); + StorageOperationStatus status = topologyTemplateOperation.updateToscaDataOfToscaElement(componentV, EdgeLabelEnum.GROUPS, VertexTypeEnum.GROUPS, vfModules, JsonPresentationFields.NAME); if(status!= StorageOperationStatus.OK){ + LOGGER.debug("Failed to add the new properties {} to groups of component {}. ", updatedProperties, componentV.getUniqueId()); result = false; } } - if(result && CollectionUtils.isNotEmpty(component.getKey().getComponentInstances())){ - result = addPropertiesToVfModuleInstances(component, newGroupTypeProperties); + if(result && CollectionUtils.isNotEmpty(getToscaElementRes.left().value().getComponentInstances())){ + result = addPropertiesToVfModuleInstances(getToscaElementRes.left().value(), componentV, updatedProperties); } return result; } - private boolean addPropertiesToVfModuleInstances(Entry component, List newGroupTypeProperties) { + private void addAllNewProperties(List vfModuleProperties, List updatedProperties) { + Map propertiesMap = vfModuleProperties.stream().collect(Collectors.toMap(p->p.getName(), p->p)); + + for(PropertyDefinition property : updatedProperties){ + if(!propertiesMap.containsKey(property.getName())){ + vfModuleProperties.add(property); + } + } + } + + private boolean addPropertiesToVfModuleInstances(org.openecomp.sdc.be.model.Component component, GraphVertex componentV, List updatedProperties) { boolean result = true; List vfModuleInstances; List pathKeys; - for(ComponentInstance componentInstance : component.getKey().getComponentInstances()){ + LOGGER.debug("Going to add the new properties {} to group instances of component {}. ", updatedProperties, componentV.getUniqueId()); + for(ComponentInstance componentInstance : component.getComponentInstances()){ vfModuleInstances = null; if(CollectionUtils.isNotEmpty(componentInstance.getGroupInstances())){ vfModuleInstances = componentInstance.getGroupInstances() @@ -154,41 +180,25 @@ public class VfModulesPropertiesAdding { } if(vfModuleInstances != null){ for(GroupInstance vfModuleInstance :vfModuleInstances){ - vfModuleInstance.getProperties().addAll(newGroupTypeProperties); + addAllNewProperties(vfModuleInstance.getProperties(),updatedProperties); pathKeys = new ArrayList<>(); pathKeys.add(componentInstance.getUniqueId()); StorageOperationStatus status = topologyTemplateOperation - .updateToscaDataDeepElementOfToscaElement(component.getValue(), EdgeLabelEnum.INST_GROUPS, VertexTypeEnum.INST_GROUPS, vfModuleInstance, pathKeys, JsonPresentationFields.NAME); + .updateToscaDataDeepElementOfToscaElement(componentV, EdgeLabelEnum.INST_GROUPS, VertexTypeEnum.INST_GROUPS, vfModuleInstance, pathKeys, JsonPresentationFields.NAME); if(status!= StorageOperationStatus.OK){ result = false; + LOGGER.debug("Failed to add the new properties {} to group instances of component {}. ", updatedProperties, componentV.getUniqueId()); break; } } if(!result){ + LOGGER.debug("Failed to add the new properties {} to group instances of component {}. ", updatedProperties, componentV.getUniqueId()); break; } } } return result; } - - private Either, StorageOperationStatus> getAllContainerComponents(List componentsV) { - Map foundComponents = new HashMap<>(); - Either, StorageOperationStatus> result = null; - for(GraphVertex componentV : componentsV){ - Either getComponentRes = toscaOperationFacade.getToscaElement(componentV); - if(getComponentRes.isRight()){ - result = Either.right(getComponentRes.right().value()); - break; - } - foundComponents.put(getComponentRes.left().value(), componentV); - } - if(result == null){ - result = Either.left(foundComponents); - } - return result; - } - private boolean addNewPropertiesToGroupType(GroupTypeDefinition vfModule, List newProperties) { boolean result = true; diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ComponentMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ComponentMigration.java index c9212f91ca..63eb8879c9 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ComponentMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ComponentMigration.java @@ -1,20 +1,20 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel; -import fj.Function; import fj.data.Either; -import org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.relations.FulfilledCapabilitiesMigrationService; -import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.relations.FulfilledRequirementsMigrationService; import org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.relations.RequirementsCapabilitiesMigrationService; import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.migration.MigrationMalformedDataLogger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + import static org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils.handleError; public abstract class ComponentMigration extends JsonModelMigration { @@ -27,10 +27,15 @@ public abstract class ComponentMigration extends JsonModel @Resource(name = "req-cap-mig-service") RequirementsCapabilitiesMigrationService requirementsCapabilitiesMigrationService; + @Resource(name = "invariant-uuid-resolver") + private InvariantUUIDResolver invariantUUIDResolver; + @Override - Either save(T element) { + boolean save(T element) { LOGGER.debug(String.format("creating component %s in new graph", element.getName())); - return toscaOperations.createToscaComponent(element).right().map(err -> handleError(err, String.format("failed to create component %s.", element.getName()))); + return toscaOperations.createToscaComponent(element) + .either(savedNode -> true, + err -> handleError(String.format("failed to create component %s with id %s. reason: %s", element.getName(), element.getUniqueId(), err.name()))); } @@ -45,4 +50,26 @@ public abstract class ComponentMigration extends JsonModel return StorageOperationStatus.NOT_FOUND; } + @Override + void doPreMigrationOperation(List elements) { + setMissingInvariantUids(elements); + } + + //some invariants uids are missing in production + private void setMissingInvariantUids(List components) { + List missingInvariantCmpts = getComponentsWithNoInvariantUUIDs(components); + for (T missingInvariantCmpt : missingInvariantCmpts) { + missingInvariantCmpt.setInvariantUUID(invariantUUIDResolver.resolveInvariantUUID(components, missingInvariantCmpt)); + } + } + + private List getComponentsWithNoInvariantUUIDs(List components) { + List cmptsWithoutInvariant = components.stream().filter(c -> c.getInvariantUUID() == null).collect(Collectors.toList()); + if (!cmptsWithoutInvariant.isEmpty()) { + cmptsWithoutInvariant.forEach(cmpt -> MigrationMalformedDataLogger.logMalformedDataMsg(String.format("component %s is missing invariant uuid", cmpt.getUniqueId()))); + } + return cmptsWithoutInvariant; + } + + } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ConsumersMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ConsumersMigration.java new file mode 100644 index 0000000000..83078baf6e --- /dev/null +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ConsumersMigration.java @@ -0,0 +1,47 @@ +package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel; + +import fj.data.Either; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ConsumerOperation; +import org.openecomp.sdc.be.resources.data.ConsumerData; + +import javax.annotation.Resource; +import java.util.List; + +import static org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils.handleError; + +public class ConsumersMigration extends JsonModelMigration { + + @Resource(name = "consumer-operation") + private ConsumerOperation consumerOperation; + + @Resource(name = "consumer-operation-mig") + private ConsumerOperation consumerOperationMigration; + + @Override + Either, ?> getElementsToMigrate() { + return consumerOperation.getAll(); + } + + @Override + Either getElementFromNewGraph(ConsumerData element) { + return consumerOperationMigration.getCredentials(element.getConsumerDataDefinition().getConsumerName()); + } + + @Override + boolean save(ConsumerData element) { + return consumerOperationMigration.createCredentials(element) + .either(savedConsumer -> true, + err -> handleError(String.format("failed to save consumer %s. reason: %s", element.getConsumerDataDefinition().getConsumerName(), err.name()))); + } + + @Override + StorageOperationStatus getNotFoundErrorStatus() { + return StorageOperationStatus.NOT_FOUND; + } + + @Override + public String description() { + return "consumers migration"; + } +} diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/InvariantUUIDResolver.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/InvariantUUIDResolver.java new file mode 100644 index 0000000000..bf28507877 --- /dev/null +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/InvariantUUIDResolver.java @@ -0,0 +1,41 @@ +package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel; + +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.operations.migration.MigrationMalformedDataLogger; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +public class InvariantUUIDResolver { + + public String resolveInvariantUUID(List components, T missingInvariantCmpt) { + String uuid = missingInvariantCmpt.getUUID(); + String systemName = missingInvariantCmpt.getSystemName(); + String invariantUid = findInvariantUUidByAllVersionsMap(missingInvariantCmpt, components).orElseGet(() -> findInvariantUUidByUUIDOrSystemName(components, uuid, systemName)); + if (invariantUid == null) { + MigrationMalformedDataLogger.logMalformedDataMsg(String.format("could not find invariant uuid for component %s with id %s", missingInvariantCmpt.getName(), missingInvariantCmpt.getUniqueId())); + } + return invariantUid; + } + + private String findInvariantUUidByUUIDOrSystemName(List components, String uuid, String systemName) { + return components.stream() + .filter(c -> c.getUUID().equals(uuid) || c.getSystemName().equals(systemName)) + .map(Component::getInvariantUUID) + .filter(c -> c != null) + .findAny().orElse(null); + } + + private Optional findInvariantUUidByAllVersionsMap(T component, List allComponents) { + if (component.getAllVersions() == null) return Optional.empty(); + Collection allVersionsComponentIds = component.getAllVersions().values(); + return allComponents.stream().filter(c -> allVersionsComponentIds.contains(c.getUniqueId())) + .map(Component::getInvariantUUID) + .filter(c -> c != null) + .findAny(); + + + } + +} diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/JsonModelMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/JsonModelMigration.java index 6070104d44..4e62b2f497 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/JsonModelMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/JsonModelMigration.java @@ -1,17 +1,19 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel; import fj.data.Either; +import org.openecomp.sdc.asdctool.impl.migration.Migration1707Task; import org.openecomp.sdc.asdctool.impl.migration.MigrationMsg; -import org.openecomp.sdc.asdctool.impl.migration.Migration; import org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils; import org.openecomp.sdc.be.dao.jsongraph.TitanDao; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Resource; import java.util.List; -public abstract class JsonModelMigration implements Migration { +public abstract class JsonModelMigration implements Migration1707Task { - private final boolean COMPLETED_OK = true; + private static final Logger LOGGER = LoggerFactory.getLogger(JsonModelMigration.class); @Resource(name = "titan-dao") TitanDao titanDao; @@ -31,7 +33,11 @@ public abstract class JsonModelMigration implements Migration { return true; } + void doPreMigrationOperation(List elements){} + private boolean migrateElementsToNewGraph(List elementsToMigrate) { + LOGGER.info(this.description() + ": starting to migrate elements to new graph. elements to migrate: {}", elementsToMigrate.size()); + doPreMigrationOperation(elementsToMigrate); for (T node : elementsToMigrate) { boolean migratedSuccessfully = migrateElement(node); if (!migratedSuccessfully) { @@ -59,14 +65,10 @@ public abstract class JsonModelMigration implements Migration { } private boolean saveElementIfNotExists(T element) { - return isExists(element).either(isExist -> isExist || createElement(element), + return isExists(element).either(isExist -> isExist || save(element), status -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_GET_NODE_FROM_GRAPH.getMessage(status.toString()))); } - private boolean createElement(T element) { - return save(element).either(savedNode -> COMPLETED_OK, - errorStatus -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_CREATE_NODE.getMessage(element.getClass().getName(), errorStatus.toString()))); - } private Either isExists(T element) { Either byId = getElementFromNewGraph(element); @@ -82,7 +84,7 @@ public abstract class JsonModelMigration implements Migration { abstract Either getElementFromNewGraph(T element); - abstract Either save(T element); + abstract boolean save(T element); abstract S getNotFoundErrorStatus(); diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/NormativesMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/NormativesMigration.java index 5fc02301dc..82d59e57b7 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/NormativesMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/NormativesMigration.java @@ -1,18 +1,22 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel; import fj.data.Either; -import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; +import jersey.repackaged.com.google.common.collect.Sets; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.Resource; -import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; -import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; +import java.util.Optional; +import java.util.Set; public class NormativesMigration extends ComponentMigration { private static Logger LOGGER = LoggerFactory.getLogger(NormativesMigration.class); + private static final String JCP_VERSION_PROPERTY = "jcp-version"; + private static final Set e2eMalformedVfcs = Sets.newHashSet("71879ee1-ad63-46d0-9943-d33083a6fdbb", "e54e7c4d-6020-4c53-838b-42d34c0da5c9"); @javax.annotation.Resource(name = "normatives-resolver") private NormativesResolver normativesResolver; @@ -30,6 +34,30 @@ public class NormativesMigration extends ComponentMigration { return normativesResolver.getAllNodeTypeNormatives(); } + @Override + boolean save(Resource element) { + if (e2eMalformedVfcs.contains(element.getUniqueId())) { + replaceJcpVersionPropertyTypeToVersion(element); + } + return super.save(element); + } + + private void replaceJcpVersionPropertyTypeToVersion(Resource element) { + getJcpIntegerProperty(element).ifPresent(propertyDefinition -> { + LOGGER.info("resource {} with id {}: found property jcp-version with type 'integer', changing type to 'version'", element.getName(), element.getUniqueId()); + propertyDefinition.setType(ToscaPropertyType.VERSION.getType()); + }); + } + + private Optional getJcpIntegerProperty(Resource element) { + if (element.getProperties() == null) return Optional.empty(); + return element.getProperties().stream() + .filter(prop -> prop.getName().equals(JCP_VERSION_PROPERTY)) + .filter(prop -> prop.getType().equals(ToscaPropertyType.INTEGER.getType())) + .findAny(); + + } + @Override boolean doPostMigrateOperation(List elements) { LOGGER.info("migrating node types versions"); diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ResourcesCategoriesMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ResourcesCategoriesMigration.java index 01654d284f..5285c4c406 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ResourcesCategoriesMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ResourcesCategoriesMigration.java @@ -2,7 +2,7 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel; import fj.data.Either; import org.openecomp.sdc.asdctool.impl.migration.MigrationMsg; -import org.openecomp.sdc.asdctool.impl.migration.Migration; +import org.openecomp.sdc.asdctool.impl.migration.Migration1707Task; import org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.jsongraph.TitanDao; @@ -11,6 +11,7 @@ import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.category.CategoryDefinition; import org.openecomp.sdc.be.model.category.SubCategoryDefinition; import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import javax.annotation.Resource; import java.util.ArrayList; @@ -22,7 +23,7 @@ import static org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.Categori import static org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel.CategoriesUtils.filterOldSubCategories; -public class ResourcesCategoriesMigration implements Migration { +public class ResourcesCategoriesMigration implements Migration1707Task { @Resource(name = "element-operation") private IElementOperation elementOperation; @@ -74,7 +75,10 @@ public class ResourcesCategoriesMigration implements Migration { } private List getAllDistinctSubCategories (List categoriesDefinitions) { - Map> subCategoriesByNormalName = categoriesDefinitions.stream().flatMap(ct -> ct.getSubcategories().stream()).collect(Collectors.groupingBy(SubCategoryDefinition::getNormalizedName)); + Map> subCategoriesByNormalName = categoriesDefinitions.stream() + .filter(ct -> ct.getSubcategories()!=null) + .flatMap(ct -> ct.getSubcategories().stream()) + .collect(Collectors.groupingBy(SubCategoryDefinition::getNormalizedName)); return getDistinctSubCategories(subCategoriesByNormalName); } @@ -112,7 +116,7 @@ public class ResourcesCategoriesMigration implements Migration { } private boolean migrateSubcategoryIfNotExists(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) { - return isExists(subCategory).either(isExists -> isExists || migrateSubCategory(parentCategory, subCategory), + return isExists(parentCategory, subCategory).either(isExists -> isExists || migrateSubCategory(parentCategory, subCategory), status -> MigrationUtils.handleError(MigrationMsg.FAILED_TO_RETRIEVE_CATEGORY.getMessage(subCategory.getName(), status.name()))); } @@ -124,13 +128,13 @@ public class ResourcesCategoriesMigration implements Migration { } private Either isExists(CategoryDefinition category) { - Either byId = getCategoryById(category.getUniqueId()); + Either byId = getCategoryById(category); return byId.either(existingVal -> Either.left(true), this::getEitherNotExistOrErrorStatus); } - private Either isExists(SubCategoryDefinition subCategory) { - return getSubCategoryById(subCategory.getUniqueId()).either(existingVal -> Either.left(true), + private Either isExists(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) { + return getSubCategoryById(parentCategory, subCategory).either(existingVal -> Either.left(true), this::getEitherNotExistOrErrorStatus); } @@ -138,12 +142,19 @@ public class ResourcesCategoriesMigration implements Migration { return status == ActionStatus.COMPONENT_CATEGORY_NOT_FOUND ? Either.left(false) : Either.right(status); } - private Either getCategoryById(String uid) { - return elementOperationMigration.getCategory(NodeTypeEnum.ResourceNewCategory, uid); + private Either getCategoryById(CategoryDefinition category) { + return elementOperationMigration.getCategory(NodeTypeEnum.ResourceNewCategory, category.getUniqueId()); } - private Either getSubCategoryById(String uid) { - return elementOperationMigration.getSubCategory(NodeTypeEnum.ResourceSubcategory, uid); + private Either getSubCategoryById(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) { + String subCategoryUid = getExpectedSubCategoryId(parentCategory, subCategory); + return elementOperationMigration.getSubCategory(NodeTypeEnum.ResourceSubcategory, subCategoryUid); + } + + //since a sub category might belong to a different category in old graph its new graph id is different than its old graph id + private String getExpectedSubCategoryId(CategoryDefinition parentCategory, SubCategoryDefinition subCategory) { + String parentId = UniqueIdBuilder.buildCategoryUid(parentCategory.getNormalizedName(), NodeTypeEnum.ResourceNewCategory); + return UniqueIdBuilder.buildSubCategoryUid(parentId, subCategory.getNormalizedName()); } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ServiceCategoriesMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ServiceCategoriesMigration.java index f745b88d02..f8f79ad9ba 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ServiceCategoriesMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ServiceCategoriesMigration.java @@ -10,6 +10,8 @@ import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import javax.annotation.Resource; import java.util.List; +import static org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils.handleError; + public class ServiceCategoriesMigration extends JsonModelMigration { @Resource(name = "element-operation") @@ -31,12 +33,15 @@ public class ServiceCategoriesMigration extends JsonModelMigration getElementFromNewGraph(CategoryDefinition node) { - return elementOperationMigration.getCategory(NodeTypeEnum.ServiceNewCategory, node.getUniqueId()); + String categoryUid = UniqueIdBuilder.buildCategoryUid(node.getNormalizedName(), NodeTypeEnum.ServiceNewCategory);//in malformed graph there are some categories with different id but same normalized name. so in new graph they same id + return elementOperationMigration.getCategory(NodeTypeEnum.ServiceNewCategory, categoryUid); } @Override - Either save(CategoryDefinition graphNode) { - return elementOperationMigration.createCategory(graphNode, NodeTypeEnum.ServiceNewCategory); + boolean save(CategoryDefinition graphNode) { + return elementOperationMigration.createCategory(graphNode, NodeTypeEnum.ServiceNewCategory) + .either(savedCategory -> true, + err -> handleError(String.format("failed to save category %s. error: %s", graphNode.getName(), err.name()))); } @Override diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ServicesMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ServicesMigration.java index f5ff96284f..254a75b317 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ServicesMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/ServicesMigration.java @@ -1,25 +1,23 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel; import fj.data.Either; -import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; -import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.Service; import org.openecomp.sdc.be.model.operations.api.IServiceOperation; -import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; -import org.openecomp.sdc.be.model.operations.migration.MigrationErrorInformer; +import org.openecomp.sdc.be.model.operations.migration.MigrationMalformedDataLogger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class ServicesMigration extends ComponentMigration { + private static final String DEFAULT_CONFORMANCE_LEVEL = "0.0"; private static Logger LOGGER = LoggerFactory.getLogger(ServicesMigration.class); @Resource(name = "service-operation") @@ -39,10 +37,10 @@ public class ServicesMigration extends ComponentMigration { } @Override - Either save(Service element) { - MigrationErrorInformer.logIfServiceUsingMalformedVfs(element); - filterOutVFInstancePropsAndAttrs(element); - element.setConformanceLevel("0.0"); + boolean save(Service element) { + MigrationMalformedDataLogger.logIfServiceUsingMalformedVfs(element); + filterOutDuplicatePropsAndAttrs(element); + element.setConformanceLevel(DEFAULT_CONFORMANCE_LEVEL); requirementsCapabilitiesMigrationService.overrideInstanceCapabilitiesRequirements(element); return super.save(element); } @@ -60,48 +58,95 @@ public class ServicesMigration extends ComponentMigration { return versionMigration.buildComponentsVersionChain(elements); } - private void filterOutVFInstancePropsAndAttrs(Service element) { - if (element.getComponentInstances() != null) { - List vfInstancesIds = getVFInstancesIds(element); - filterOutVFInstacnecProps(element, vfInstancesIds); - filterOutVFInstanceAttrs(element, vfInstancesIds); + private void filterOutDuplicatePropsAndAttrs(Service element) { + if (element.getComponentInstancesProperties() != null) { + removeDuplicatedNameProperties(element); } + if (element.getComponentInstancesAttributes() != null) { + removeDuplicatedNameAttributes(element); + } + } + + private void removeDuplicatedNameProperties(Service service) { + Map> componentInstancesProperties = service.getComponentInstancesProperties(); + componentInstancesProperties.forEach((uid, properties) -> { + componentInstancesProperties.put(uid, getUniquedNamePropertyList(service, properties)); + }); } - private void filterOutVFInstanceAttrs(Service element, List vfInstancesIds) { - Map> componentInstancesAttributes = element.getComponentInstancesAttributes(); - if (componentInstancesAttributes != null) { - element.setComponentInstancesAttributes(filterOutVFInstanceAttributes(componentInstancesAttributes, vfInstancesIds)); + private List getUniquedNamePropertyList(Service service, List properties) { + if (properties == null) { + return null; } + List uniqueNameProperties = new ArrayList<>(); + Map> collect = properties.stream().collect(Collectors.groupingBy(ComponentInstanceProperty::getName)); + collect.forEach((name, duplicatedProperties) -> { + logServiceDuplicateProperties(service, name, duplicatedProperties); + uniqueNameProperties.add(duplicatedProperties.get(0)); + }); + return uniqueNameProperties; } - private void filterOutVFInstacnecProps(Service element, List vfInstancesIds) { - Map> componentInstancesProperties = element.getComponentInstancesProperties(); - if (componentInstancesProperties != null) { - element.setComponentInstancesProperties(filterOutVFInstanceProperties(componentInstancesProperties, vfInstancesIds)); + private void logServiceDuplicateProperties(Service service, String name, List duplicatedProperties) { + if (duplicatedProperties.size() > 1) { + LOGGER.debug("service {} with id {} has instance {} with duplicate property {}", service.getName(), service.getUniqueId(), duplicatedProperties.get(0).getUniqueId(), name); } } - private Map> filterOutVFInstanceProperties(Map> instances, List vfInstanceIds) { - return instances.entrySet() - .stream() - .filter(entry -> !vfInstanceIds.contains(entry.getKey())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + private void removeDuplicatedNameAttributes(Service service) { + Map> componentInstancesAttributes = service.getComponentInstancesAttributes(); + componentInstancesAttributes.forEach((uid, attributes) -> { + componentInstancesAttributes.put(uid, getUniquedNameAttributeList(service, attributes)); + }); } - private Map> filterOutVFInstanceAttributes(Map> instances, List vfInstanceIds) { - return instances.entrySet() - .stream() - .filter(entry -> !vfInstanceIds.contains(entry.getKey())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + private List getUniquedNameAttributeList(Service service, List attributes) { + if (attributes == null) { + return null; + } + List uniqueNameAttributes = new ArrayList<>(); + Map> collect = attributes.stream().collect(Collectors.groupingBy(ComponentInstanceProperty::getName)); + collect.forEach((name, duplicatedAttributess) -> { + logServiceMalformedAttributes(service, name, duplicatedAttributess); + uniqueNameAttributes.add(duplicatedAttributess.get(0)); + }); + return uniqueNameAttributes; } - private List getVFInstancesIds(Service service) { - return service.getComponentInstances() - .stream() - .filter(componentInstance -> componentInstance.getOriginType() == OriginTypeEnum.VF) - .map(ComponentInstanceDataDefinition::getUniqueId) - .collect(Collectors.toList()); + private void logServiceMalformedAttributes(Service service, String name, List duplicatedAttributess) { + if (duplicatedAttributess.size() > 1) { + MigrationMalformedDataLogger.logMalformedDataMsg(String.format("service %s with id %s has instance %s with duplicate attribute %s", + service.getName(), service.getUniqueId(), duplicatedAttributess.get(0).getUniqueId(), name)); + } } + // private void filterOutVFInstanceAttrs(Service element, List vfInstancesIds) { +// Map> componentInstancesAttributes = element.getComponentInstancesAttributes(); +// if (componentInstancesAttributes != null) { +// element.setComponentInstancesAttributes(filterOutVFInstanceAttributes(componentInstancesAttributes, vfInstancesIds)); +// } +// } +// +// private void filterOutVFInstacnecProps(Service element, List vfInstancesIds) { +// Map> componentInstancesProperties = element.getComponentInstancesProperties(); +// if (componentInstancesProperties != null) { +// element.setComponentInstancesProperties(filterOutVFInstanceProperties(componentInstancesProperties, vfInstancesIds)); +// } +// } +// +// private Map> filterOutVFInstanceProperties(Map> instances, List vfInstanceIds) { +// return instances.entrySet() +// .stream() +// .filter(entry -> !vfInstanceIds.contains(entry.getKey())) +// .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); +// } +// +// private Map> filterOutVFInstanceAttributes(Map> instances, List vfInstanceIds) { +// return instances.entrySet() +// .stream() +// .filter(entry -> !vfInstanceIds.contains(entry.getKey())) +// .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); +// } + + } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/UserStatesMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/UserStatesMigration.java index b248d90bd2..67d9235cee 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/UserStatesMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/UserStatesMigration.java @@ -7,7 +7,6 @@ import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Property; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.openecomp.sdc.asdctool.impl.migration.MigrationMsg; -import org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils; import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.dao.titan.TitanGenericDao; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; @@ -23,6 +22,7 @@ import java.util.List; import java.util.stream.Collectors; import static fj.data.List.list; +import static org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils.handleError; public class UserStatesMigration extends JsonModelMigration { @@ -71,9 +71,16 @@ public class UserStatesMigration extends JsonModelMigration { } @Override - Either save(Edge userState) { + boolean save(Edge userState) { Either titanVertices = findEdgeInOutVerticesInNewGraph(userState); - return titanVertices.left().bind(inOutVertices -> genericDaoMigration.copyEdge(inOutVertices.getOutVertex(), inOutVertices.getInVertex(), userState)); + return titanVertices.either(inOutVertices -> saveUserState(inOutVertices, userState), + err -> handleError(String.format("could not find user edge %s in vertx. error: %s", userState.label(), err.name()))); + } + + private boolean saveUserState(InOutVertices inOutVertices, Edge userState) { + return genericDaoMigration.copyEdge(inOutVertices.getOutVertex(), inOutVertices.getInVertex(), userState) + .either(edge -> true, + err -> handleError(String.format("failed to save user state edge %s. reason: %s", userState.label(), err.name()))); } @Override @@ -125,7 +132,7 @@ public class UserStatesMigration extends JsonModelMigration { String vertexUniqueId = getVertexUniqueId(vertex); LOGGER.debug(String.format("fetching vertex %s from new graph", vertexUniqueId)); return genericDaoMigration.getVertexByProperty(vertexUniqueId, vertex.property(vertexUniqueId).value()) - .right().map(err -> MigrationUtils.handleError(err, String.format("could not find vertex %s in new graph.", vertexUniqueId))) ; + .right().map(err -> handleError(err, String.format("could not find vertex %s in new graph.", vertexUniqueId))) ; } // private boolean deleteAllEdges(UserData userData, Direction direction) { @@ -154,6 +161,7 @@ public class UserStatesMigration extends JsonModelMigration { TitanVertex getInVertex() { return inVertex; } + } } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/UsersMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/UsersMigration.java index 9dd3fc4853..a578f066bf 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/UsersMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/UsersMigration.java @@ -1,13 +1,10 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel; -import fj.Function; import fj.data.Either; -import org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.utils.UserStatusEnum; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.operations.api.IUserAdminOperation; -import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,13 +33,16 @@ public class UsersMigration extends JsonModelMigration { @Override Either getElementFromNewGraph(User user) { LOGGER.debug(String.format("trying to load user %s from new graph", user.getUserId())); - return userAdminOperationMigration.getUserData(user.getUserId(), false); + return user.getStatus().equals(UserStatusEnum.ACTIVE) ? userAdminOperationMigration.getUserData(user.getUserId(), false) : + userAdminOperationMigration.getInactiveUserData(user.getUserId()); } @Override - Either save(User user) { + boolean save(User user) { LOGGER.debug(String.format("trying to save user %s to new graph", user.getUserId())); - return userAdminOperationMigration.saveUserData(user); + return userAdminOperationMigration.saveUserData(user) + .either(savedUser -> true, + err -> handleError(String.format("failed when saving user %s. error %s", user.getUserId(), err.name()))); } @Override diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/VFResourcesMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/VFResourcesMigration.java index b684883323..34c40f0aa9 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/VFResourcesMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/VFResourcesMigration.java @@ -31,7 +31,7 @@ public class VFResourcesMigration extends ComponentMigration { } @Override - Either save(Resource element) { + boolean save(Resource element) { requirementsCapabilitiesMigrationService.overrideInstanceCapabilitiesRequirements(element); return super.save(element); } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/VersionMigration.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/VersionMigration.java index 7dadd79a1b..145ae28c81 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/VersionMigration.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1707/jsonmodel/VersionMigration.java @@ -1,9 +1,7 @@ package org.openecomp.sdc.asdctool.impl.migration.v1707.jsonmodel; import fj.data.Either; -import org.apache.commons.lang3.StringUtils; import org.apache.tinkerpop.gremlin.structure.Edge; -import org.openecomp.sdc.asdctool.impl.migration.MigrationException; import org.openecomp.sdc.asdctool.impl.migration.MigrationMsg; import org.openecomp.sdc.asdctool.impl.migration.v1707.MigrationUtils; import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; @@ -13,7 +11,6 @@ import org.openecomp.sdc.be.dao.titan.TitanGenericDao; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.Component; -import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,8 +33,7 @@ public abstract class VersionMigration { private TitanDao titanDao; public boolean buildComponentsVersionChain(List components) { - setMissingInvariantUid(components); - Map> componentsByInvariant = components.stream().collect(Collectors.groupingBy(Component::getInvariantUUID)); + Map> componentsByInvariant = components.stream().filter(c -> c.getInvariantUUID() != null).collect(Collectors.groupingBy(Component::getInvariantUUID)); for (List componentsList : componentsByInvariant.values()) { boolean versionChainBuilt = buildVersionChainForInvariant(componentsList); if (!versionChainBuilt) { @@ -63,7 +59,7 @@ public abstract class VersionMigration { } private void sortComponentsByVersion(List components) { - Collections.sort(components, (o1, o2) -> o1.getVersion().compareTo(o2.getVersion())); + Collections.sort(components, (o1, o2) -> Double.valueOf(o1.getVersion()).compareTo(Double.valueOf(o2.getVersion()))); } private boolean createVersionRelationIfNotExist(String fromUid, String toUid) { @@ -74,10 +70,10 @@ public abstract class VersionMigration { private boolean createVersionRelation(String fromUid, String toUid) { LOGGER.debug(String.format("creating version edge between vertex %s and vertex %s", fromUid, toUid)); - Either vertexById = titanDao.getVertexById(fromUid); - Either vertexById1 = titanDao.getVertexById(toUid); - if (vertexById1.isLeft() && vertexById.isLeft()) { - TitanOperationStatus versionCreated = titanDao.createEdge(vertexById.left().value(), vertexById1.left().value(), EdgeLabelEnum.VERSION, new HashMap<>()); + Either fromVertex = titanDao.getVertexById(fromUid); + Either toVertex = titanDao.getVertexById(toUid); + if (toVertex.isLeft() && fromVertex.isLeft()) { + TitanOperationStatus versionCreated = titanDao.createEdge(fromVertex.left().value(), toVertex.left().value(), EdgeLabelEnum.VERSION, new HashMap<>()); return versionCreated == TitanOperationStatus.OK; } return MigrationUtils.handleError(String.format("could not create version edge between vertex %s and vertex %s.", fromUid, toUid)); @@ -99,28 +95,4 @@ public abstract class VersionMigration { } abstract NodeTypeEnum getNodeTypeEnum(); - - //some invariatn uids are missing in production - private void setMissingInvariantUid(List components) { - List missingInvariantCmpts = getComponentsWithNoInvariantUids(components); - for (T missingInvariantCmpt : missingInvariantCmpts) { - String uuid = missingInvariantCmpt.getUUID(); - missingInvariantCmpt.setInvariantUUID(findInvariantUidOrElseFail(components, uuid)); - } - } - - private List getComponentsWithNoInvariantUids(List components) { - List cmptsWithoutInvariant = components.stream().filter(c -> c.getInvariantUUID() == null).collect(Collectors.toList()); - LOGGER.info(String.format("the following components are missing invariant uids: %s", StringUtils.join(cmptsWithoutInvariant.stream().map(Component::getUniqueId).collect(Collectors.toList()), ","))); - return cmptsWithoutInvariant; - } - - private String findInvariantUidOrElseFail(List components, String uuid) { - return components.stream() - .filter(c -> c.getUUID().equals(uuid)) - .map(Component::getInvariantUUID) - .filter(c -> c != null) - .findAny().orElseThrow(() -> new MigrationException(String.format("cannot find invariantuid for component with uuid %s", uuid))); - } - } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/MigrationMenu.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/MigrationMenu.java index c914e3b082..c3d8743b86 100644 --- a/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/MigrationMenu.java +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/MigrationMenu.java @@ -35,6 +35,8 @@ import org.openecomp.sdc.asdctool.impl.migration.v1610.ToscaArtifactsAlignment; import org.openecomp.sdc.asdctool.impl.migration.v1702.Migration1702; import org.openecomp.sdc.asdctool.impl.migration.v1707.Migration1707; import org.openecomp.sdc.asdctool.impl.migration.v1707.Migration1707Config; +import org.openecomp.sdc.asdctool.impl.migration.v1707.DistributionStatusUpdate; +import org.openecomp.sdc.asdctool.impl.migration.v1707.Migration1707VnfFix; import org.openecomp.sdc.asdctool.impl.migration.v1707.VfModulesPropertiesAdding; import org.openecomp.sdc.be.config.ConfigurationManager; import org.openecomp.sdc.common.api.ConfigurationSource; @@ -64,7 +66,10 @@ public class MigrationMenu { FIX_ICONS("fix-icons", "titanFixUtils"), MIGRATION_1610_1702("migrate-1610-1702", "migration1702"), MIGRATION_1702_1707("migrate-1702-1707", "migration1707"), - VFMODULES_PROPERTIES_ADDING("vfModules-properties-adding", "vfModulesPropertiesAdding"); + DISTRIBUTION_STATUS_UPDATE_1707("distribution-status-update-1707", "distributionStatusUpdate"), + VFMODULES_PROPERTIES_ADDING("vfModules-properties-adding", "vfModulesPropertiesAdding"), + MIGRATION_1707_RELATIONS_FIX("fix-relations-after-migration-1707", "migration1707relationsFix"), + MIGRATION_1707_VNF_FIX("fix-vnf-after-migration-1707", "migration1707vnfFix"); // UPDATE_DATA_TYPES("update_data_types", "updateDataTypes"); private String value, beanName; @@ -238,9 +243,8 @@ public class MigrationMenu { } break; - case MIGRATION_1702_1707: + case MIGRATION_1702_1707://this migration is currently not needed, but will be commented out for production env // log.info("Start ASDC migration from 1702 to 1707"); - System.exit(0); // Migration1707 migration1707 = (Migration1707) context.getBean(operationEnum.getBeanName()); // isSuccessful = migration1707.migrate(); // if (isSuccessful) { @@ -250,18 +254,59 @@ public class MigrationMenu { // log.info("SDC migration from 1702 to 1707 has failed"); // System.exit(2); // } + System.exit(0); break; - case VFMODULES_PROPERTIES_ADDING: - log.info("Start adding new properties to vfModules"); - VfModulesPropertiesAdding migrationVfModulesProperties = (VfModulesPropertiesAdding) context.getBean(operationEnum.getBeanName()); - isSuccessful = migrationVfModulesProperties.migrate(args[1]); - if (isSuccessful) { - log.info("Adding new properties to vfModules was finished successfully"); - System.exit(0); - } else{ - log.info("Adding new properties to vfModules has failed"); - System.exit(2); - } + case VFMODULES_PROPERTIES_ADDING://this migration is currently not needed, but will be commented out for production env +// log.info("Start adding new properties to vfModules"); +// VfModulesPropertiesAdding migrationVfModulesProperties = (VfModulesPropertiesAdding) context.getBean(operationEnum.getBeanName()); +// isSuccessful = migrationVfModulesProperties.migrate(args[1]); +// if (isSuccessful) { +// log.info("Adding new properties to vfModules was finished successfully"); +// System.exit(0); +// } else{ +// log.info("Adding new properties to vfModules has failed"); +// System.exit(2); +// } + System.exit(0); + break; + case MIGRATION_1707_VNF_FIX://this migration is currently not needed, but will be commented out for production env +// log.info("Start fixing vnf after 1707 migration"); +// Migration1707VnfFix migrationVnfFix = (Migration1707VnfFix) context.getBean(operationEnum.getBeanName()); +// isSuccessful = migrationVnfFix.migrate(); +// if (isSuccessful) { +// log.info("Fixing VNFs after 1707 migration was finished successfully"); +// System.exit(0); +// } else{ +// log.info("Fixing VNFs after 1707 migration has failed"); +// System.exit(2); +// } + System.exit(0); + break; + case DISTRIBUTION_STATUS_UPDATE_1707://not needed can be dropped +// log.info("Start Distribution status update 1707"); +// DistributionStatusUpdate distStatusUpdate = (DistributionStatusUpdate) context.getBean(operationEnum.getBeanName()); +// isSuccessful = distStatusUpdate.migrate(); +// if (isSuccessful) { +// log.info("ASDC Distribution status update 1707 was finished successful"); +// System.exit(0); +// } else{ +// log.info("ASDC Distribution status update 1707 has failed"); +// System.exit(2); +// } + System.exit(0); + break; + case MIGRATION_1707_RELATIONS_FIX://not needed can be dropped +// log.info("Start fixing relations after 1707 migration"); +// Migration migrationFix = (Migration1707RelationsFix) context.getBean(operationEnum.getBeanName()); +// isSuccessful = migrationFix.migrate(); +// if (isSuccessful) { +// log.info("Fixing relations after 1707 migration was finished successfully"); +// System.exit(0); +// } else{ +// log.info("Fixing relations after 1707 migration has failed"); +// System.exit(2); +// } + System.exit(0); break; default: usageAndExit(); @@ -298,6 +343,9 @@ public class MigrationMenu { System.out.println("Usage: migrate-1610-1702 "); System.out.println("Usage: migrate-1702-1707 "); System.out.println("Usage: update_data_types "); + System.out.println("Usage: distribution-status-update-1707"); System.out.println("Usage: vfModules-properties-adding "); + System.out.println("Usage: fix-relations-after-migration-1707 "); + System.out.println("Usage: fix-vnf-after-migration-1707 "); } } diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/SdcSchemaFileImport.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/SdcSchemaFileImport.java new file mode 100644 index 0000000000..edeb56787b --- /dev/null +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/main/SdcSchemaFileImport.java @@ -0,0 +1,84 @@ +package org.openecomp.sdc.asdctool.main; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Date; + +import org.apache.commons.codec.digest.DigestUtils; +import org.openecomp.sdc.asdctool.impl.EsToCassandraDataMigrationConfig; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus; +import org.openecomp.sdc.be.dao.cassandra.SdcSchemaFilesCassandraDao; +import org.openecomp.sdc.be.resources.data.SdcSchemaFilesData; +import org.openecomp.sdc.common.api.ConfigurationSource; +import org.openecomp.sdc.common.impl.ExternalConfiguration; +import org.openecomp.sdc.common.impl.FSConfigurationSource; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + + +public class SdcSchemaFileImport { + + private static SdcSchemaFilesCassandraDao schemaFilesCassandraDao; + + public static void main(String[] args) throws Exception { + + final String FILE_NAME = "SDC.zip"; + + if (args == null || args.length < 4) { + usageAndExit(); + } + + String pathAndFile = args[0]; + String sdcReleaseNum = args[1]; + String conformanceLevel = args[2]; + String appConfigDir = args[3]; + + File file = new File(pathAndFile); + if(!file.exists()){ + System.out.println("The file or path does not exist"); + System.exit(1); + } else if(!file.isFile()){ + System.out.println("Specify the file name"); + System.exit(1); + } + + AnnotationConfigApplicationContext context = initContext(appConfigDir); + schemaFilesCassandraDao = (SdcSchemaFilesCassandraDao) context.getBean("sdc-schema-files-cassandra-dao"); + + Path path = Paths.get(pathAndFile); + byte[] fileBytes = Files.readAllBytes(path); + + Date date = new Date(); + String md5Hex = DigestUtils.md5Hex(fileBytes); + + SdcSchemaFilesData schemeFileData = new SdcSchemaFilesData(sdcReleaseNum, date, conformanceLevel, FILE_NAME, fileBytes, md5Hex); + CassandraOperationStatus saveSchemaFile = schemaFilesCassandraDao.saveSchemaFile(schemeFileData); + + if(!saveSchemaFile.equals(CassandraOperationStatus.OK)){ + System.out.println("SdcSchemaFileImport failed cassandra error" + saveSchemaFile); + System.exit(1); + } + + System.out.println("SdcSchemaFileImport successfully completed"); + + System.exit(0); + } + + private static void usageAndExit(){ + SdcSchemaFileImportUsage(); + System.exit(1); + } + + private static void SdcSchemaFileImportUsage(){ + System.out.println("Usage: "); + } + + private static AnnotationConfigApplicationContext initContext(String appConfigDir) { + ConfigurationSource configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(), appConfigDir); + ConfigurationManager configurationManager = new ConfigurationManager(configurationSource); + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EsToCassandraDataMigrationConfig.class); + return context; + } +} diff --git a/asdctool/src/main/resources/config/configuration.yaml b/asdctool/src/main/resources/config/configuration.yaml index d376ba3c0e..beca6c98aa 100644 --- a/asdctool/src/main/resources/config/configuration.yaml +++ b/asdctool/src/main/resources/config/configuration.yaml @@ -25,8 +25,8 @@ beSslPort: 8443 version: 1.0 released: 2012-11-30 -titanCfgFile: C:\Git_work\Git_UGN\d2-sdnc\asdctool\src\main\resources\config\titan.properties -titanMigrationKeySpaceCfgFile: C:\Git_work\Git_UGN\d2-sdnc\asdctool\src\main\resources\config\titan-migration.properties +titanCfgFile: src\main\resources\config\titan.properties +titanMigrationKeySpaceCfgFile: src\main\resources\config\titan-migration.properties titanInMemoryGraph: false titanLockTimeout: 1800 titanReconnectIntervalInSeconds: 3 diff --git a/asdctool/src/main/resources/config/groupTypes.yml b/asdctool/src/main/resources/config/groupTypes.yml index c72dc88c53..ce457e4add 100644 --- a/asdctool/src/main/resources/config/groupTypes.yml +++ b/asdctool/src/main/resources/config/groupTypes.yml @@ -63,7 +63,20 @@ org.openecomp.groups.VfModule: Group. VID operator must select the Volume Group instance to attach to a VF-Module at deployment time. - + availability_zone_count: + type: integer + required: false + description: > + Quantity of Availability Zones needed for this VF-Module + (source: Extracted from VF-Module HEAT template) + vfc_list: + type: map + entry_schema: + description: : + type: string + required: false + description: > + Identifies the set of VM types and their count included in the VF-Module tosca.groups.Root: description: The TOSCA Group Type all other TOSCA Group Types derive from interfaces: diff --git a/asdctool/src/main/resources/config/logback.xml b/asdctool/src/main/resources/config/logback.xml index 87795ae163..0426a32d9e 100644 --- a/asdctool/src/main/resources/config/logback.xml +++ b/asdctool/src/main/resources/config/logback.xml @@ -1,7 +1,7 @@ - - + + @@ -36,9 +36,33 @@ + + ${HOME}/asdctool/logs/${ECOMP-component-name}/${ECOMP-subcomponent-name}/malformed-data.log + + + ${HOME}/asdctool/logs/${ECOMP-component-name}/${ECOMP-subcomponent-name}/malformed-data.log.%i + + 1 + 10 + + + + 20MB + + + ${default-log-pattern} + + + + + + + \ No newline at end of file diff --git a/asdctool/src/main/resources/scripts/dataMigration1707.sh b/asdctool/src/main/resources/scripts/dataMigration1707.sh index e67de2a540..11a151a7c3 100644 --- a/asdctool/src/main/resources/scripts/dataMigration1707.sh +++ b/asdctool/src/main/resources/scripts/dataMigration1707.sh @@ -18,7 +18,7 @@ source ${FULL_PATH}/baseOperation.sh mainClass="org.openecomp.sdc.asdctool.main.MigrationMenu" -command="java $JVM_LOG_FILE -cp $JARS $mainClass migrate-1702-1707 $@" +command="java $JVM_LOG_FILE -Xmx6000M -cp $JARS $mainClass migrate-1702-1707 $@" echo $command $command diff --git a/asdctool/src/main/resources/scripts/distributionStatusUpdate1707.sh b/asdctool/src/main/resources/scripts/distributionStatusUpdate1707.sh new file mode 100644 index 0000000000..a9d308f933 --- /dev/null +++ b/asdctool/src/main/resources/scripts/distributionStatusUpdate1707.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +############################## +# Distribution Status Update 1707 +############################## + +CURRENT_DIR=`pwd` +BASEDIR=$(dirname $0) + +if [ ${BASEDIR:0:1} = "/" ] +then + FULL_PATH=$BASEDIR +else + FULL_PATH=$CURRENT_DIR/$BASEDIR +fi + +source ${FULL_PATH}/baseOperation.sh + +mainClass="org.openecomp.sdc.asdctool.main.MigrationMenu" + +command="java $JVM_LOG_FILE -cp $JARS $mainClass distribution-status-update-1707 $@" +echo $command + +$command +result=$? + + + +echo "***********************************" +echo "***** $result *********************" +echo "***********************************" + +exit $result + + diff --git a/asdctool/src/main/resources/scripts/migration1707RelationsFix.sh b/asdctool/src/main/resources/scripts/migration1707RelationsFix.sh new file mode 100644 index 0000000000..c930243750 --- /dev/null +++ b/asdctool/src/main/resources/scripts/migration1707RelationsFix.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +############################## +# Data Migration: fix relations after migration 1707 +############################## + +CURRENT_DIR=`pwd` +BASEDIR=$(dirname $0) + +if [ ${BASEDIR:0:1} = "/" ] +then + FULL_PATH=$BASEDIR +else + FULL_PATH=$CURRENT_DIR/$BASEDIR +fi + +source ${FULL_PATH}/baseOperation.sh + +mainClass="org.openecomp.sdc.asdctool.main.MigrationMenu" + +command="java $JVM_LOG_FILE -cp $JARS $mainClass fix-relations-after-migration-1707 $@" +echo $command + +$command +result=$? + +echo "***********************************" +echo "***** $result *********************" +echo "***********************************" + +exit $result + + diff --git a/asdctool/src/main/resources/scripts/retrieve_schema_file.sh b/asdctool/src/main/resources/scripts/retrieve_schema_file.sh new file mode 100644 index 0000000000..f66b530f20 --- /dev/null +++ b/asdctool/src/main/resources/scripts/retrieve_schema_file.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +cass_user=asdc_user +cass_pass='Aa1234%^!' +sdcReleaseNum=$1 +conformanceLevel=$2 + +CQLSH="/home/vagrant/cassandra/apache-cassandra-2.1.9/bin/cqlsh" + + + ### Get payload + + select_payload="select payload from sdcartifact.sdcschemafiles where conformanceLevel='$conformanceLevel' and sdcReleaseNum='$sdcReleaseNum'" + + echo "Run: [$select_payload]" + +$CQLSH -e "$select_payload" |grep "0x" |xxd -r -p > SDC-downloaded.zip + +res=$? +echo "After select payload, res=[$res]" \ No newline at end of file diff --git a/asdctool/src/main/resources/scripts/vfmoduleFix1707.sh b/asdctool/src/main/resources/scripts/vfmoduleFix1707.sh new file mode 100644 index 0000000000..48579242bf --- /dev/null +++ b/asdctool/src/main/resources/scripts/vfmoduleFix1707.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +############################## +# Distribution Status Update 1707 +############################## + +CURRENT_DIR=`pwd` +BASEDIR=$(dirname $0) + +if [ ${BASEDIR:0:1} = "/" ] +then + FULL_PATH=$BASEDIR +else + FULL_PATH=$CURRENT_DIR/$BASEDIR +fi + +source ${FULL_PATH}/baseOperation.sh + +mainClass="org.openecomp.sdc.asdctool.main.MigrationMenu" + +command="java $JVM_LOG_FILE -cp $JARS $mainClass fix-vnf-after-migration-1707 $@" +echo $command + +$command +result=$? + + + +echo "***********************************" +echo "***** $result *********************" +echo "***********************************" + +exit $result + + diff --git a/catalog-be/pom.xml b/catalog-be/pom.xml index e53069cf5a..6f35b3a5a1 100644 --- a/catalog-be/pom.xml +++ b/catalog-be/pom.xml @@ -24,7 +24,7 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml - ${jackson.version} + ${jackson.yaml.version} compile @@ -450,7 +450,7 @@ org.openecomp.ecompsdkos - ecompFW + epsdk-fw ${ecomp.version} compile diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/ArtifactsResolver.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/ArtifactsResolver.java new file mode 100644 index 0000000000..95f1edd61f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/ArtifactsResolver.java @@ -0,0 +1,27 @@ +package org.openecomp.sdc.be.components; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; + +public interface ArtifactsResolver { + + /** + * searching for an artifact with the give {@code artifactId} on the given {@code component} + * @param component the component to look for artifact in + * @param componentType the type of the component to look for artifact in + * @param artifactId the id of the artifact to find + * @return the found artifact or null if not exist + */ + ArtifactDefinition findArtifactOnComponent(Component component, ComponentTypeEnum componentType, String artifactId); + + /** + * searching for an artifact with the give {@code artifactId} on the given {@code componentInstance} + * @param componentInstance the component instance to look for the artifact in + * @param artifactId the if of the artifact to find + * @return the found artifact or null if not exist + */ + ArtifactDefinition findArtifactOnComponentInstance(ComponentInstance componentInstance, String artifactId); + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/JsonContainerResourceInstance.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/JsonContainerResourceInstance.java index d1b445b065..5efcfe7fa8 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/JsonContainerResourceInstance.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/JsonContainerResourceInstance.java @@ -118,4 +118,11 @@ public class JsonContainerResourceInstance { public void setSubcategory(String subcategory) { this.subcategory = subcategory; } + + @Override + public String toString() { + return "JsonContainerResourceInstance [resourceInstanceName=" + resourceInstanceName + ", resourceName=" + resourceName + ", resourceVersion=" + resourceVersion + ", resoucreType=" + resoucreType + ", resourceUUID=" + resourceUUID + + ", resourceInvariantUUID=" + resourceInvariantUUID + ", resourceCustomizationUUID=" + resourceCustomizationUUID + ", category=" + category + ", subcategory=" + subcategory + ", artifacts=" + artifacts + "]"; + } + } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationDataImpl.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationDataImpl.java index 8a2ef8e63b..149499811f 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationDataImpl.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/NotificationDataImpl.java @@ -77,9 +77,11 @@ public class NotificationDataImpl implements INotificationData { this.serviceDescription = serviceDescription; } + @Override public String toString() { - return "NotificationDataImpl [distributionID=" + distributionID + ", serviceName=" + serviceName + ", serviceVersion=" + serviceVersion + ", serviceUUID=" + serviceUUID + ", serviceInvariantUUID=" + serviceInvariantUUID + "]"; + return "NotificationDataImpl [distributionID=" + distributionID + ", serviceName=" + serviceName + ", serviceVersion=" + serviceVersion + ", serviceUUID=" + serviceUUID + ", serviceDescription=" + serviceDescription + + ", serviceInvariantUUID=" + serviceInvariantUUID + ", resources=" + resources + ", serviceArtifacts=" + serviceArtifacts + "]"; } @Override diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/VfModuleArtifactPayload.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/VfModuleArtifactPayload.java index 71593fa99a..2bcaa4f54a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/VfModuleArtifactPayload.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/distribution/engine/VfModuleArtifactPayload.java @@ -62,6 +62,8 @@ public class VfModuleArtifactPayload { vfModuleModelDescription = group.getDescription(); artifacts = group.getArtifactsUuid(); + artifacts.addAll(group.getGroupInstanceArtifactsUuid()); + // Base Value is set from properties setBaseValue(group); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactResolverImpl.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactResolverImpl.java new file mode 100644 index 0000000000..7ef3a1961f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactResolverImpl.java @@ -0,0 +1,62 @@ +package org.openecomp.sdc.be.components.impl; + +import org.openecomp.sdc.be.components.ArtifactsResolver; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@org.springframework.stereotype.Component("artifact-resolver") +public class ArtifactResolverImpl implements ArtifactsResolver { + + @Override + public ArtifactDefinition findArtifactOnComponent(Component component, ComponentTypeEnum componentType, String artifactId) { + List allComponentsArtifacts = getAllComponentsArtifacts(component, componentType); + return findById(allComponentsArtifacts, artifactId); + + } + + @Override + public ArtifactDefinition findArtifactOnComponentInstance(ComponentInstance componentInstance, String artifactId) { + List allInstanceArtifacts = getAllInstanceArtifacts(componentInstance); + return findById(allInstanceArtifacts, artifactId); + } + + private ArtifactDefinition findById(List artifacts, String artifactId) { + return artifacts.stream() + .filter(artifact -> artifact.getUniqueId().equals(artifactId)) + .findFirst().orElse(null); + } + + private List getAllComponentsArtifacts(Component component, ComponentTypeEnum componentType) { + Map deploymentArtifacts = Optional.ofNullable(component.getDeploymentArtifacts()).orElse(Collections.emptyMap()); + Map artifacts = Optional.ofNullable(component.getArtifacts()).orElse(Collections.emptyMap()); + Map serviceApiArtifacts = Collections.emptyMap(); + if (componentType.equals(ComponentTypeEnum.SERVICE)) { + serviceApiArtifacts = Optional.ofNullable(((Service) component).getServiceApiArtifacts()).orElse(Collections.emptyMap()); + } + return appendAllArtifacts(deploymentArtifacts, artifacts, serviceApiArtifacts); + } + + private List getAllInstanceArtifacts(ComponentInstance instance) { + Map deploymentArtifacts = Optional.ofNullable(instance.getDeploymentArtifacts()).orElse(Collections.emptyMap()); + Map artifacts = Optional.ofNullable(instance.getArtifacts()).orElse(Collections.emptyMap()); + return appendAllArtifacts(deploymentArtifacts, artifacts); + } + + @SafeVarargs + private final List appendAllArtifacts(Map... artifacts) { + List allArtifacts = new ArrayList<>(); + Arrays.stream(artifacts).forEach(a -> allArtifacts.addAll(a.values())); + return allArtifacts; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java index 6739d28bd4..83c8183a01 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ArtifactsBusinessLogic.java @@ -43,6 +43,7 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.ArtifactsResolver; import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic; @@ -180,6 +181,9 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { @Autowired NodeTemplateOperation nodeTemplateOperation; + @Autowired + private ArtifactsResolver artifactsResolver; + public ArtifactsBusinessLogic() { // defaultHeatTimeout = ConfigurationManager.getConfigurationManager().getConfiguration().getDefaultHeatArtifactTimeoutMinutes(); // if ((defaultHeatTimeout == null) || (defaultHeatTimeout < 1)) { @@ -609,22 +613,22 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { } if (groupType == ArtifactGroupTypeEnum.DEPLOYMENT) { List list = getDeploymentArtifacts(component, componentType.getNodeType(), componentId); - if (list != null && !list.isEmpty()){ + if (list != null && !list.isEmpty()) { resMap = list.stream().collect(Collectors.toMap(a -> a.getArtifactLabel(), a -> a)); - }else{ + } else { resMap = new HashMap<>(); } resultOp = Either.left(resMap); return resultOp; } else { - Either, StorageOperationStatus> artifactsMapStatus = getArtifacts(realComponentId, componentType.getNodeType(), false, groupType, componentId ); + Either, StorageOperationStatus> artifactsMapStatus = getArtifacts(realComponentId, componentType.getNodeType(), false, groupType, componentId); if (artifactsMapStatus.isRight()) { if (artifactsMapStatus.right().value() != StorageOperationStatus.NOT_FOUND) { ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.MISSING_INFORMATION); log.debug("handleGetArtifactsByType - not falid groupType {} , component id {}", artifactGroupType, componentId); resultOp = Either.right(responseFormat); - }else{ + } else { resMap = new HashMap<>(); resultOp = Either.left(resMap); } @@ -934,7 +938,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { if (validateAndSetArtifactname.isRight()) { return Either.right(validateAndSetArtifactname.right().value()); } - Either artifactById = findArtifactOnParentComponent(parentComponent, parentId, operation, artifactId); + Either artifactById = findArtifactOnParentComponent(parentComponent, componentType, parentId, operation, artifactId); if (artifactById.isRight()) { return Either.right(artifactById.right().value()); } @@ -1033,27 +1037,12 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { return Either.left(artifactInfo); } - private Either findArtifactOnParentComponent(Component parentComponent, String parentId, ArtifactOperationInfo operation, String artifactId) { + private Either findArtifactOnParentComponent(Component parentComponent, ComponentTypeEnum componentType, String parentId, ArtifactOperationInfo operation, String artifactId) { Either result = null; ArtifactDefinition foundArtifact = null; if (StringUtils.isNotEmpty(artifactId)) { - if (parentComponent.getUniqueId().equals(parentId)) { - if (parentComponent.getDeploymentArtifacts() != null) { - foundArtifact = parentComponent.getDeploymentArtifacts().values().stream().filter(e -> e.getUniqueId().equals(artifactId)).findFirst().orElse(null); - } - if (foundArtifact == null && parentComponent.getArtifacts() != null) { - foundArtifact = parentComponent.getArtifacts().values().stream().filter(e -> e.getUniqueId().equals(artifactId)).findFirst().orElse(null); - } - } else { - ComponentInstance instance = findComponentInstance(parentId, parentComponent); - if (instance.getDeploymentArtifacts() != null) { - foundArtifact = instance.getDeploymentArtifacts().values().stream().filter(e -> e.getUniqueId().equals(artifactId)).findFirst().orElse(null); - } - if (foundArtifact == null && instance.getArtifacts() != null) { - foundArtifact = instance.getArtifacts().values().stream().filter(e -> e.getUniqueId().equals(artifactId)).findFirst().orElse(null); - } - } + foundArtifact = findArtifact(parentComponent, componentType, parentId, artifactId); } if (foundArtifact != null && operation.getArtifactOperationEnum() == ArtifactOperationEnum.Create) { log.debug("Artifact {} already exist", artifactId); @@ -1069,6 +1058,17 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { return result; } + private ArtifactDefinition findArtifact(Component parentComponent, ComponentTypeEnum componentType, String parentId, String artifactId) { + ArtifactDefinition foundArtifact; + if (parentComponent.getUniqueId().equals(parentId)) { + foundArtifact = artifactsResolver.findArtifactOnComponent(parentComponent, componentType, artifactId); + } else { + ComponentInstance instance = findComponentInstance(parentId, parentComponent); + foundArtifact = artifactsResolver.findArtifactOnComponentInstance(instance, artifactId); + } + return foundArtifact; + } + private Either validateInformationalArtifact(ArtifactDefinition artifactInfo, Component parentComponent) { ComponentTypeEnum parentComponentType = parentComponent.getComponentType(); ArtifactGroupTypeEnum groupType = artifactInfo.getArtifactGroupType(); @@ -1254,11 +1254,11 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { for (GroupInstance groupInstance : groupInstances) { isUpdated = false; if (CollectionUtils.isNotEmpty(groupInstance.getGroupInstanceArtifacts()) && groupInstance.getGroupInstanceArtifacts().contains(artifactId)) { - groupInstance.getArtifacts().remove(artifactId); + groupInstance.getGroupInstanceArtifacts().remove(artifactId); isUpdated = true; } if (CollectionUtils.isNotEmpty(groupInstance.getGroupInstanceArtifactsUuid()) && groupInstance.getGroupInstanceArtifactsUuid().contains(foundArtifact.getArtifactUUID())) { - groupInstance.getArtifacts().remove(foundArtifact.getArtifactUUID()); + groupInstance.getGroupInstanceArtifactsUuid().remove(foundArtifact.getArtifactUUID()); isUpdated = true; } if (isUpdated) { @@ -1278,7 +1278,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { if (isMandatory) { log.debug("Going to update mandatory artifact {} from the component {}", artifactId, parentId); resetMandatoryArtifactFields(foundArtifact); - result = artifactToscaOperation.updateArtifactOnGraph(componentId, foundArtifact, parentType, artifactId, instanceId); + result = artifactToscaOperation.updateArtifactOnGraph(componentId, foundArtifact, parentType, artifactId, instanceId, true); } else if (cloneIsNeeded) { log.debug("Going to clone artifacts and to delete the artifact {} from the component {}", artifactId, parentId); result = artifactToscaOperation.deleteArtifactWithClonnigOnGraph(componentId, foundArtifact, parentType, instanceId, false); @@ -2098,11 +2098,11 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { return deploymentArtifacts; } ComponentInstance ri = getRI.left().value(); - if(ri.getDeploymentArtifacts() != null){ + if (ri.getDeploymentArtifacts() != null) { deploymentArtifacts.addAll(ri.getDeploymentArtifacts().values()); } - } else if(parentComponent.getDeploymentArtifacts() !=null){ - deploymentArtifacts.addAll(parentComponent.getDeploymentArtifacts().values()); + } else if (parentComponent.getDeploymentArtifacts() != null) { + deploymentArtifacts.addAll(parentComponent.getDeploymentArtifacts().values()); } } return deploymentArtifacts; @@ -3145,7 +3145,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { } } } - if ( !found ){ + if (!found) { artifacts = resourceInstance.getArtifacts(); if (artifacts != null) { for (Map.Entry entry : artifacts.entrySet()) { @@ -3154,7 +3154,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { break; } } - } + } } } return found; @@ -3370,7 +3370,37 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { public Either generateHeatEnvArtifact(ArtifactDefinition artifactDefinition, ComponentTypeEnum componentType, org.openecomp.sdc.be.model.Component component, String resourceInstanceName, User modifier, boolean shouldLock, String instanceId) { String payload = generateHeatEnvPayload(artifactDefinition); - return generateAndSaveHeatEnvArtifact(artifactDefinition, payload, componentType, component, resourceInstanceName, modifier, shouldLock, instanceId); + String prevUUID = artifactDefinition.getArtifactUUID(); + ArtifactDefinition clonedBeforeGenerate = new ArtifactDefinition(artifactDefinition); + Either generateResult = generateAndSaveHeatEnvArtifact(artifactDefinition, payload, componentType, component, resourceInstanceName, modifier, shouldLock, instanceId); + if (generateResult.isLeft()) { + ArtifactDefinition updatedArtDef = generateResult.left().value(); + if (!prevUUID.equals(updatedArtDef.getArtifactUUID())) { + List componentInstances = component.getComponentInstances(); + if (componentInstances != null) { + Optional findFirst = componentInstances.stream().filter(ci -> ci.getUniqueId().equals(instanceId)).findFirst(); + if (findFirst.isPresent()) { + ComponentInstance relevantInst = findFirst.get(); + List updatedGroupInstances = getUpdatedGroupInstances(updatedArtDef.getUniqueId(), clonedBeforeGenerate, relevantInst.getGroupInstances()); + + if (CollectionUtils.isNotEmpty(updatedGroupInstances)) { + updatedGroupInstances.forEach(gi -> { + gi.getGroupInstanceArtifacts().add(updatedArtDef.getUniqueId()); + gi.getGroupInstanceArtifactsUuid().add(updatedArtDef.getArtifactUUID()); + }); + Either, StorageOperationStatus> status = toscaOperationFacade.updateGroupInstancesOnComponent(component, componentType, instanceId, updatedGroupInstances); + if (status.isRight()) { + log.debug("Failed to update groups of the component {}. ", component.getUniqueId()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(status.right().value()), clonedBeforeGenerate.getArtifactDisplayName()); + return Either.right(responseFormat); + } + } + } + } + } + } + + return generateResult; } private String generateHeatEnvPayload(ArtifactDefinition artifactDefinition) { @@ -3438,7 +3468,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { } sb.append(ConfigurationManager.getConfigurationManager().getConfiguration().getHeatEnvArtifactFooter()); - // DE265919 fix Tal G + // DE265919 fix String result = sb.toString().replaceAll("\\\\n", "\n"); return result; @@ -3522,7 +3552,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { oldCheckSum = artifactDefinition.getArtifactChecksum(); artifactDefinition.setArtifactChecksum(newCheckSum); - artifactToscaOperation.updateUUID(artifactDefinition, oldCheckSum, artifactDefinition.getArtifactVersion()); +// artifactToscaOperation.updateUUID(artifactDefinition, oldCheckSum, artifactDefinition.getArtifactVersion()); artifactDefinition.setEsId(artifactDefinition.getUniqueId()); updateArifactDefinitionStatus = artifactToscaOperation.updateArifactOnResource(artifactDefinition, component.getUniqueId(), artifactDefinition.getUniqueId(), componentType.getNodeType(), instanceId); @@ -3530,6 +3560,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { } if (updateArifactDefinitionStatus != null && updateArifactDefinitionStatus.isLeft()) { + artifactDefinition = updateArifactDefinitionStatus.left().value(); artifactData.setId(artifactDefinition.getUniqueId()); CassandraOperationStatus saveArtifactStatus = artifactCassandraDao.saveArtifact(artifactData); @@ -3965,7 +3996,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { String origMd5 = request.getHeader(Constants.MD5_HEADER); String userId = request.getHeader(Constants.USER_ID_HEADER); - Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata); + Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata, true); if (getComponentRes.isRight()) { StorageOperationStatus status = getComponentRes.right().value(); log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); @@ -4026,7 +4057,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { String userId = request.getHeader(Constants.USER_ID_HEADER); ImmutablePair componentRiPair = null; - Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata); + Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata, true); if (getComponentRes.isRight()) { StorageOperationStatus status = getComponentRes.right().value(); log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); @@ -4089,7 +4120,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { String origMd5 = request.getHeader(Constants.MD5_HEADER); String userId = request.getHeader(Constants.USER_ID_HEADER); - Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata); + Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata, true); if (getComponentRes.isRight()) { StorageOperationStatus status = getComponentRes.right().value(); log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); @@ -4158,7 +4189,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { String userId = request.getHeader(Constants.USER_ID_HEADER); ImmutablePair componentRiPair = null; - Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata); + Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata, true); if (getComponentRes.isRight()) { StorageOperationStatus status = getComponentRes.right().value(); log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); @@ -4223,7 +4254,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { String origMd5 = request.getHeader(Constants.MD5_HEADER); String userId = request.getHeader(Constants.USER_ID_HEADER); - Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata); + Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata, true); if (getComponentRes.isRight()) { StorageOperationStatus status = getComponentRes.right().value(); log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); @@ -4288,7 +4319,7 @@ public class ArtifactsBusinessLogic extends BaseBusinessLogic { String origMd5 = request.getHeader(Constants.MD5_HEADER); String userId = request.getHeader(Constants.USER_ID_HEADER); ImmutablePair componentRiPair = null; - Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata); + Either getComponentRes = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata, true); if (getComponentRes.isRight()) { StorageOperationStatus status = getComponentRes.right().value(); log.debug("Could not fetch component with type {} and uuid {}. Status is {}. ", componentType, componentUuid, status); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AttributeBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AttributeBusinessLogic.java index 84cf20dcfa..4fd4610ef9 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AttributeBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/AttributeBusinessLogic.java @@ -28,8 +28,8 @@ import java.util.Optional; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; @@ -65,8 +65,8 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { * @param userId * @return AttributeDefinition if created successfully Or ResponseFormat */ - public Either createAttribute(String resourceId, AttributeDefinition newAttributeDef, String userId) { - Either result = null; + public Either createAttribute(String resourceId, PropertyDefinition newAttributeDef, String userId) { + Either result = null; Either resp = validateUserExists(userId, "create Attribute", false); if (resp.isRight()) { return Either.right(resp.right().value()); @@ -111,7 +111,7 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { // add the new attribute to resource on graph // need to get StorageOpaerationStatus and convert to ActionStatus from // componentsUtils - Either either = toscaOperationFacade.addAttributeOfResource(resource, newAttributeDef); + Either either = toscaOperationFacade.addAttributeOfResource(resource, newAttributeDef); if (either.isRight()) { result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(either.right().value()), resource.getName())); return result; @@ -126,7 +126,7 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { } - private boolean isAttributeExist(List attributes, String resourceUid, String propertyName) { + private boolean isAttributeExist(List attributes, String resourceUid, String propertyName) { boolean isExist = false; if (attributes != null) { isExist = attributes.stream().filter(p -> Objects.equals(p.getName(), propertyName) && Objects.equals(p.getParentUniqueId(), resourceUid)).findAny().isPresent(); @@ -141,7 +141,7 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { * @param userId * @return */ - public Either getAttribute(String resourceId, String attributeId, String userId) { + public Either getAttribute(String resourceId, String attributeId, String userId) { Either resp = validateUserExists(userId, "get Attribute", false); if (resp.isRight()) { @@ -155,13 +155,13 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { } Resource resource = status.left().value(); - List attributes = resource.getAttributes(); + List attributes = resource.getAttributes(); if (attributes == null) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.ATTRIBUTE_NOT_FOUND, "")); } else { - Either result; + Either result; // verify attribute exist in resource - Optional optionalAtt = attributes.stream().filter(att -> att.getUniqueId().equals(attributeId) && att.getParentUniqueId().equals(resourceId)).findAny(); + Optional optionalAtt = attributes.stream().filter(att -> att.getUniqueId().equals(attributeId) && att.getParentUniqueId().equals(resourceId)).findAny(); if (optionalAtt.isPresent()) { result = Either.left(optionalAtt.get()); @@ -182,8 +182,8 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { * @param userId * @return */ - public Either updateAttribute(String resourceId, String attributeId, AttributeDefinition newAttDef, String userId) { - Either result = null; + public Either updateAttribute(String resourceId, String attributeId, PropertyDefinition newAttDef, String userId) { + Either result = null; StorageOperationStatus lockResult = graphLockOperation.lockComponent(resourceId, NodeTypeEnum.Resource); if (lockResult != StorageOperationStatus.OK) { @@ -205,7 +205,7 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { } // verify attribute exist in resource - Either eitherAttribute = getAttribute(resourceId, attributeId, userId); + Either eitherAttribute = getAttribute(resourceId, attributeId, userId); if (eitherAttribute.isRight()) { return Either.right(eitherAttribute.right().value()); } @@ -228,7 +228,7 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { } - Either eitherAttUpdate = toscaOperationFacade.updateAttributeOfResource(resource, newAttDef); + Either eitherAttUpdate = toscaOperationFacade.updateAttributeOfResource(resource, newAttDef); if (eitherAttUpdate.isRight()) { log.debug("Problem while updating attribute with id {}. Reason - {}", attributeId, eitherAttUpdate.right().value()); @@ -253,9 +253,9 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { * @param userId * @return */ - public Either deleteAttribute(String resourceId, String attributeId, String userId) { + public Either deleteAttribute(String resourceId, String attributeId, String userId) { - Either result = null; + Either result = null; Either resp = validateUserExists(userId, "delete Attribute", false); if (resp.isRight()) { @@ -283,7 +283,7 @@ public class AttributeBusinessLogic extends BaseBusinessLogic { } // verify attribute exist in resource - Either eitherAttributeExist = getAttribute(resourceId, attributeId, userId); + Either eitherAttributeExist = getAttribute(resourceId, attributeId, userId); if (eitherAttributeExist.isRight()) { return Either.right(eitherAttributeExist.right().value()); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java index f880883438..5ee5c88f69 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java @@ -21,38 +21,31 @@ package org.openecomp.sdc.be.components.impl; import java.util.ArrayList; -import java.util.Collection; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.function.Function; -import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.config.ConfigurationManager; import org.openecomp.sdc.be.dao.api.ActionStatus; -import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum; -import org.openecomp.sdc.be.datamodel.utils.UiComponentDataConverter; -import org.openecomp.sdc.be.datatypes.components.ComponentMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.components.ServiceMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; -import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; import org.openecomp.sdc.be.model.ArtifactDefinition; import org.openecomp.sdc.be.model.CapReqDef; -import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; import org.openecomp.sdc.be.model.ComponentInstanceInput; @@ -64,13 +57,10 @@ import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.LifecycleStateEnum; import org.openecomp.sdc.be.model.Operation; import org.openecomp.sdc.be.model.PropertyDefinition; -import org.openecomp.sdc.be.model.RequirementDefinition; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.cache.ComponentCache; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; -import org.openecomp.sdc.be.model.operations.impl.ComponentOperation; -import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.resources.data.ComponentMetadataData; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; @@ -87,9 +77,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import com.datastax.driver.core.UserType.Field; -import com.wordnik.swagger.models.auth.In; - import fj.data.Either; public abstract class ComponentBusinessLogic extends BaseBusinessLogic { @@ -283,40 +270,43 @@ public abstract class ComponentBusinessLogic extends BaseBusinessLogic { } - public Either validateConformanceLevel(String componentId, ComponentTypeEnum componentTypeEnum, String userId) { + public Either validateConformanceLevel(String componentUuid, ComponentTypeEnum componentTypeEnum, String userId) { log.trace("validate conformance level"); if (componentTypeEnum != ComponentTypeEnum.SERVICE) { - log.error("conformance level validation for non service component, id {}", componentId); + log.error("conformance level validation for non service component, id {}", componentUuid); ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT); return Either.right(errorResponse); } Either resp = validateUserExists(userId, "validateConformanceLevel", false); if (resp.isRight()) { - log.error("can't validate conformance level, user is not validated, id {}, userId {}", componentId, userId); + log.error("can't validate conformance level, user is not validated, uuid {}, userId {}", componentUuid, userId); return Either.right(resp.right().value()); } - ComponentParametersView filter = new ComponentParametersView(true); - Either eitherComponent = validateComponentExists(componentId, componentTypeEnum, filter); + Either eitherComponent = toscaOperationFacade.getLatestComponentMetadataByUuid(componentUuid, JsonParseFlagEnum.ParseMetadata, null); if (eitherComponent.isRight()) { - log.error("can't validate conformance level, component not found, id {}", componentId); - BeEcompErrorManager.getInstance().logBeComponentMissingError("validateConformanceLevel", componentTypeEnum.getValue(), componentId); - return Either.right(eitherComponent.right().value()); + log.error("can't validate conformance level, component not found, uuid {}", componentUuid); + BeEcompErrorManager.getInstance().logBeComponentMissingError("validateConformanceLevel", componentTypeEnum.getValue(), componentUuid); + + StorageOperationStatus status = eitherComponent.right().value(); + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(status, componentTypeEnum); + ResponseFormat responseFormat = componentsUtils.getResponseFormat(actionStatus); + return Either.right(responseFormat); } - Component component = eitherComponent.left().value(); - if (component.getConformanceLevel() == null || "".equals(component.getConformanceLevel())) { - log.error("component conformance level property is null or empty, id {}", componentId); + String componentConformanceLevel = eitherComponent.left().value().getMetadataDataDefinition().getConformanceLevel(); + if (StringUtils.isBlank(componentConformanceLevel)) { + log.error("component conformance level property is null or empty, uuid {}", componentUuid); ResponseFormat errorResponse = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); return Either.right(errorResponse); } String configConformanceLevel = ConfigurationManager.getConfigurationManager().getConfiguration().getMinToscaConformanceLevel(); Boolean result = true; - if (CommonBeUtils.conformanceLevelCompare(component.getConformanceLevel(), configConformanceLevel) < 0) { - log.error("invalid asset conformance level, id {}, asset conformanceLevel {}, config conformanceLevel {}", componentId, component.getConformanceLevel(), configConformanceLevel); + if (CommonBeUtils.conformanceLevelCompare(componentConformanceLevel, configConformanceLevel) < 0) { + log.error("invalid asset conformance level, uuid {}, asset conformanceLevel {}, config conformanceLevel {}", componentUuid, componentConformanceLevel, configConformanceLevel); result = false; } log.trace("conformance level validation finished"); @@ -1154,9 +1144,7 @@ public abstract class ComponentBusinessLogic extends BaseBusinessLogic { return Either.right(fetchAndSetLatestGeneric.right().value()); Resource genericTypeResource = fetchAndSetLatestGeneric.left().value(); if(null == currentGenericType || !currentGenericType.equals(genericTypeResource.getToscaResourceName()) || !currentGenericVersion.equals(genericTypeResource.getVersion())){ - List genericTypeProps = genericTypeResource.getProperties(); - List genericTypeInputs = null == genericTypeProps? null : convertGenericTypePropertiesToInputsDefintion(genericTypeProps, genericTypeResource.getUniqueId()); - shouldUpgrade = upgradeToLatestGeneric(clonedComponent, genericTypeInputs); + shouldUpgrade = upgradeToLatestGeneric(clonedComponent, genericTypeResource); if(!shouldUpgrade) { reverntUpdateOfGenericVersion(clonedComponent, currentGenericType, currentGenericVersion); } @@ -1169,12 +1157,37 @@ public abstract class ComponentBusinessLogic extends BaseBusinessLogic { clonedComponent.setDerivedFromGenericVersion(currentGenericVersion); } + private Either, String> validateNoConflictingProperties(List currentList, List upgradedList) { + Map currentMap = ToscaDataDefinition.listToMapByName(currentList); + Map upgradedMap = ToscaDataDefinition.listToMapByName(upgradedList); + return ToscaDataDefinition.mergeDataMaps(upgradedMap, currentMap, true); + } - private boolean upgradeToLatestGeneric(Component componentToCheckOut, List upgradedList) { - - if (!componentToCheckOut.shouldGenerateInputs()) - return true; + private boolean shouldUpgradeNodeType(Component componentToCheckOut, Resource latestGeneric){ + List genericTypeProps = latestGeneric.getProperties(); + Either, String> validMerge = validateNoConflictingProperties(genericTypeProps, ((Resource)componentToCheckOut).getProperties()); + if (validMerge.isRight()) { + log.debug("property {} cannot be overriden, check out performed without upgrading to latest generic", validMerge.right().value()); + return false; + } + List genericTypeAttributes = latestGeneric.getAttributes(); + validMerge = validateNoConflictingProperties(genericTypeAttributes, ((Resource)componentToCheckOut).getAttributes()); + if (validMerge.isRight()) { + log.debug("attribute {} cannot be overriden, check out performed without upgrading to latest generic", validMerge.right().value()); + return false; + } + return true; + } + + private boolean upgradeToLatestGeneric(Component componentToCheckOut, Resource latestGeneric) { + + if (!componentToCheckOut.shouldGenerateInputs()) { + //node type - validate properties and attributes + return shouldUpgradeNodeType(componentToCheckOut, latestGeneric); + } + List genericTypeProps = latestGeneric.getProperties(); + List genericTypeInputs = null == genericTypeProps? null : convertGenericTypePropertiesToInputsDefintion(genericTypeProps, latestGeneric.getUniqueId()); List currentList = new ArrayList<>(); // nullify existing ownerId from existing list and merge into updated list if (null != componentToCheckOut.getInputs()) { @@ -1184,20 +1197,20 @@ public abstract class ComponentBusinessLogic extends BaseBusinessLogic { currentList.add(copy); } } - if (null == upgradedList) { + if (null == genericTypeInputs) { componentToCheckOut.setInputs(currentList); return true; } - Map currentMap = PropertyDataDefinition.listToMapByName(currentList); - Map upgradedMap = PropertyDataDefinition.listToMapByName(upgradedList); - Either, String> eitherMerged = PropertyDataDefinition.mergeProperties(upgradedMap, currentMap, true); + + Either, String> eitherMerged = validateNoConflictingProperties(genericTypeInputs, currentList); if (eitherMerged.isRight()) { - log.debug("property {} cannot be overriden, check out performed without upgrading to latest generic", eitherMerged.right().value()); + log.debug("input {} cannot be overriden, check out performed without upgrading to latest generic", eitherMerged.right().value()); return false; } componentToCheckOut.setInputs(new ArrayList(eitherMerged.left().value().values())); return true; } + private List getFilteredInstances(Component component, List resourceTypes) { List filteredInstances = null; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java index 1623375926..203a63894b 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java @@ -51,7 +51,6 @@ import org.openecomp.sdc.be.info.CreateAndAssotiateInfo; import org.openecomp.sdc.be.model.ArtifactDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; import org.openecomp.sdc.be.model.ComponentInstanceInput; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.ComponentParametersView; @@ -338,6 +337,10 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { for (ArtifactDefinition artifact : componentDeploymentArtifacts.values()) { String type = artifact.getArtifactType(); + + if ( !type.equalsIgnoreCase(ArtifactTypeEnum.HEAT_ENV.getType()) ){ + finalDeploymentArtifacts.put(artifact.getArtifactLabel(), artifact); + } if (!(type.equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType()) || type.equalsIgnoreCase(ArtifactTypeEnum.HEAT_NET.getType()) || type.equalsIgnoreCase(ArtifactTypeEnum.HEAT_VOL.getType()))) { continue; @@ -351,9 +354,6 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { } ArtifactDefinition artifactDefinition = createHeatEnvPlaceHolder.left().value(); - //put heat - finalDeploymentArtifacts.put(artifact.getArtifactLabel(), artifact); - //put env finalDeploymentArtifacts.put(artifactDefinition.getArtifactLabel(), artifactDefinition); @@ -890,12 +890,12 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { } } - private Either updateAttributeValue(ComponentInstanceAttribute attribute, String resourceInstanceId) { - Either eitherAttribute = componentInstanceOperation.updateAttributeValueInResourceInstance(attribute, resourceInstanceId, true); - Either result; + private Either updateAttributeValue(ComponentInstanceProperty attribute, String resourceInstanceId) { + Either eitherAttribute = componentInstanceOperation.updateAttributeValueInResourceInstance(attribute, resourceInstanceId, true); + Either result; if (eitherAttribute.isLeft()) { log.debug("Attribute value {} was updated on graph.", attribute.getValueUniqueUid()); - ComponentInstanceAttribute instanceAttribute = eitherAttribute.left().value(); + ComponentInstanceProperty instanceAttribute = eitherAttribute.left().value(); result = Either.left(instanceAttribute); @@ -910,9 +910,9 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { return result; } - private Either createAttributeValue(ComponentInstanceAttribute attribute, String resourceInstanceId) { + private Either createAttributeValue(ComponentInstanceProperty attribute, String resourceInstanceId) { - Either result; + Either result; Wrapper indexCounterWrapper = new Wrapper<>(); Wrapper errorWrapper = new Wrapper<>(); @@ -921,10 +921,10 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { if (!errorWrapper.isEmpty()) { result = Either.right(errorWrapper.getInnerElement()); } else { - Either eitherAttribute = componentInstanceOperation.addAttributeValueToResourceInstance(attribute, resourceInstanceId, indexCounterWrapper.getInnerElement(), true); + Either eitherAttribute = componentInstanceOperation.addAttributeValueToResourceInstance(attribute, resourceInstanceId, indexCounterWrapper.getInnerElement(), true); if (eitherAttribute.isLeft()) { log.debug("Attribute value was added to resource instance {}", resourceInstanceId); - ComponentInstanceAttribute instanceAttribute = eitherAttribute.left().value(); + ComponentInstanceProperty instanceAttribute = eitherAttribute.left().value(); result = Either.left(instanceAttribute); } else { @@ -948,8 +948,8 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { * @param userId * @return */ - public Either createOrUpdateAttributeValue(ComponentTypeEnum componentTypeEnum, String componentId, String resourceInstanceId, ComponentInstanceAttribute attribute, String userId) { - Either result = null; + public Either createOrUpdateAttributeValue(ComponentTypeEnum componentTypeEnum, String componentId, String resourceInstanceId, ComponentInstanceProperty attribute, String userId) { + Either result = null; Wrapper errorWrapper = new Wrapper<>(); validateUserExist(userId, "create Or Update Attribute Value", errorWrapper); @@ -1104,8 +1104,6 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { BeEcompErrorManager.getInstance().logBeInvalidValueError("Add property value", pair.getLeft(), property.getName(), propertyType); return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(TitanOperationStatus.ILLEGAL_ARGUMENT)))); } - - try { List instanceProperties = containerComponent.getComponentInstancesProperties().get(resourceInstanceId); @@ -1122,6 +1120,10 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { resultOp = Either.right(componentsUtils.getResponseFormatForResourceInstanceProperty(actionStatus, "")); return resultOp; } + List path = new ArrayList<>(); + path.add(foundResourceInstance.getUniqueId()); + property.setPath(path); + foundResourceInstance.setCustomizationUUID(UUID.randomUUID().toString()); Either updateContainerRes = toscaOperationFacade.updateComponentInstanceMetadataOfTopologyTemplate(containerComponent); @@ -1603,7 +1605,7 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { return resultOp; } - List groupInstances = currentResourceInstance.getGroupInstances(); + // List groupInstances = currentResourceInstance.getGroupInstances(); Map deploymentArtifacts = currentResourceInstance.getDeploymentArtifacts(); resultOp = deleteComponentInstance(containerComponent, componentInstanceId, containerComponentType); if (resultOp.isRight()) { @@ -1639,13 +1641,15 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { return resultOp; } - if (CollectionUtils.isNotEmpty(groupInstances)) { + /* if (CollectionUtils.isNotEmpty(groupInstances)) { StorageOperationStatus addGroupsToComponentInstance = toscaOperationFacade.addGroupInstancesToComponentInstance(containerComponent, updatedComponentInstance, groupInstances); if (addGroupsToComponentInstance != StorageOperationStatus.OK) { BeEcompErrorManager.getInstance().logInternalFlowError("ChangeComponentInstanceVersion", "Failed to associate groups to new component instance", ErrorSeverity.ERROR); resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); return resultOp; } + + } if (MapUtils.isNotEmpty(deploymentArtifacts)) { StorageOperationStatus addDeploymentArtifactsToComponentInstance = toscaOperationFacade.addDeploymentArtifactsToComponentInstance(containerComponent, updatedComponentInstance, deploymentArtifacts); @@ -1654,7 +1658,7 @@ public abstract class ComponentInstanceBusinessLogic extends BaseBusinessLogic { resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); return resultOp; } - } + }*/ ComponentParametersView filter = new ComponentParametersView(true); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CsarValidationUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CsarValidationUtils.java index ae6237897a..3d280ab7ca 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CsarValidationUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CsarValidationUtils.java @@ -289,7 +289,7 @@ public class CsarValidationUtils { return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID, csarUUID)); } byte[] toscaMetaBytes = csar.get(TOSCA_METADATA_FILE); - // Tal && exchanged for || + // && exchanged for || if (toscaMetaBytes == null || toscaMetaBytes.length == 0) { log.debug("TOSCA-Metadata/TOSCA.meta file not found in csar, csar ID {}", csarUUID); BeEcompErrorManager.getInstance().logInternalDataError("TOSCA-Metadata/TOSCA.meta file not found in CSAR with id " + csarUUID, "CSAR structure is invalid", ErrorSeverity.ERROR); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogic.java index 958adc0eef..d8746737d3 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ElementBusinessLogic.java @@ -990,9 +990,9 @@ public class ElementBusinessLogic extends BaseBusinessLogic { } Map> resMap = new HashMap<>(); - Either, StorageOperationStatus> resResources = toscaOperationFacade.getCatalogComponents(ComponentTypeEnum.RESOURCE); + Either, StorageOperationStatus> resResources = toscaOperationFacade.getCatalogComponents(ComponentTypeEnum.RESOURCE, true); if (resResources.isLeft()) { - Either, StorageOperationStatus> resServices = toscaOperationFacade.getCatalogComponents(ComponentTypeEnum.SERVICE); + Either, StorageOperationStatus> resServices = toscaOperationFacade.getCatalogComponents(ComponentTypeEnum.SERVICE, true); if (resServices.isLeft()) { // Either, StorageOperationStatus> resProducts = productOperation.getProductCatalogData(false); // if (resProducts.isLeft()) { @@ -1021,7 +1021,7 @@ public class ElementBusinessLogic extends BaseBusinessLogic { } if (filters == null || filters.isEmpty()) { - Either, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum); + Either, StorageOperationStatus> componentsList = toscaOperationFacade.getCatalogComponents(assetTypeEnum, false); if(componentsList.isRight()) { return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentsList.right().value()))); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupBusinessLogic.java index ba08f11928..f298b0f203 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupBusinessLogic.java @@ -79,6 +79,7 @@ import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.operations.impl.GroupOperation; import org.openecomp.sdc.be.model.operations.impl.GroupTypeOperation; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; import org.openecomp.sdc.common.api.Constants; import org.openecomp.sdc.exception.ResponseFormat; import org.slf4j.Logger; @@ -112,7 +113,6 @@ public class GroupBusinessLogic extends BaseBusinessLogic { @javax.annotation.Resource private GroupTypeOperation groupTypeOperation; - @Autowired ArtifactsOperations artifactsOperation; @@ -121,7 +121,6 @@ public class GroupBusinessLogic extends BaseBusinessLogic { @Autowired private ApplicationDataTypeCache dataTypeCache; - /** * * 1. validate user exist @@ -145,67 +144,39 @@ public class GroupBusinessLogic extends BaseBusinessLogic { * @param inTransaction * @return */ - /*public Either createGroup(String componentId, String userId, ComponentTypeEnum componentType, GroupDefinition groupDefinition, boolean inTransaction) { - - Either result = null; - - try { - Either validateUserExists = validateUserExists(userId, CREATE_GROUP, inTransaction); - - if (validateUserExists.isRight()) { - result = Either.right(validateUserExists.right().value()); - return result; - } - - User user = validateUserExists.left().value(); - // 5. check service/resource existence - // 6. check service/resource check out - // 7. user is owner of checkout state - org.openecomp.sdc.be.model.Component component = null; - - // String realComponentId = componentType == - // ComponentTypeEnum.RESOURCE_INSTANCE ? parentId : componentId; - String realComponentId = componentId; - - ComponentParametersView componentParametersView = new ComponentParametersView(); - componentParametersView.disableAll(); - componentParametersView.setIgnoreGroups(false); - componentParametersView.setIgnoreArtifacts(false); - componentParametersView.setIgnoreUsers(false); - componentParametersView.setIgnoreComponentInstances(false); - - Either validateComponent = validateComponentExists(realComponentId, componentType, componentParametersView); - - if (validateComponent.isRight()) { - result = Either.right(validateComponent.right().value()); - return result; - } - component = validateComponent.left().value(); - Either canWork = validateCanWorkOnComponent(component, userId); - if (canWork.isRight()) { - result = Either.right(canWork.right().value()); - return result; - } - - result = this.createGroup(component, user, componentType, groupDefinition, inTransaction); - return result; - - } finally { - - if (false == inTransaction) { - - if (result == null || result.isRight()) { - log.debug("Going to execute rollback on create group."); - titanDao.rollback(); - } else { - log.debug("Going to execute commit on create group."); - titanDao.commit(); - } - - } - - } - }*/ + /* + * public Either createGroup(String componentId, String userId, ComponentTypeEnum componentType, GroupDefinition groupDefinition, boolean inTransaction) { + * + * Either result = null; + * + * try { Either validateUserExists = validateUserExists(userId, CREATE_GROUP, inTransaction); + * + * if (validateUserExists.isRight()) { result = Either.right(validateUserExists.right().value()); return result; } + * + * User user = validateUserExists.left().value(); // 5. check service/resource existence // 6. check service/resource check out // 7. user is owner of checkout state org.openecomp.sdc.be.model.Component component = null; + * + * // String realComponentId = componentType == // ComponentTypeEnum.RESOURCE_INSTANCE ? parentId : componentId; String realComponentId = componentId; + * + * ComponentParametersView componentParametersView = new ComponentParametersView(); componentParametersView.disableAll(); componentParametersView.setIgnoreGroups(false); componentParametersView.setIgnoreArtifacts(false); + * componentParametersView.setIgnoreUsers(false); componentParametersView.setIgnoreComponentInstances(false); + * + * Either validateComponent = validateComponentExists(realComponentId, componentType, componentParametersView); + * + * if (validateComponent.isRight()) { result = Either.right(validateComponent.right().value()); return result; } component = validateComponent.left().value(); Either canWork = validateCanWorkOnComponent(component, + * userId); if (canWork.isRight()) { result = Either.right(canWork.right().value()); return result; } + * + * result = this.createGroup(component, user, componentType, groupDefinition, inTransaction); return result; + * + * } finally { + * + * if (false == inTransaction) { + * + * if (result == null || result.isRight()) { log.debug("Going to execute rollback on create group."); titanDao.rollback(); } else { log.debug("Going to execute commit on create group."); titanDao.commit(); } + * + * } + * + * } } + */ private String getComponentTypeForResponse(org.openecomp.sdc.be.model.Component component) { String componentTypeForResponse = "SERVICE"; @@ -235,7 +206,7 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } List currentArtifacts = deploymentArtifacts.values().stream().map(p -> p.getUniqueId()).collect(Collectors.toList()); - log.debug("The deployment artifacts of component {} are {}" , component.getNormalizedName(), deploymentArtifacts); + log.debug("The deployment artifacts of component {} are {}", component.getNormalizedName(), deploymentArtifacts); if (false == currentArtifacts.containsAll(artifacts)) { BeEcompErrorManager.getInstance().logInvalidInputError(context, "Not all artifacts belongs to component " + component.getNormalizedName(), ErrorSeverity.INFO); return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); @@ -285,48 +256,48 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } } -// ComponentOperation componentOperation = getComponentOperationByParentComponentType(componentType); -// if (componentOperation instanceof ResourceOperation) { -// ResourceOperation resourceOperation = (ResourceOperation) componentOperation; -// -// for (Entry groupMember : groupMembers.entrySet()) { -// -// String componentInstName = groupMember.getKey(); -// String componentInstUid = groupMember.getValue(); -// -// ComponentInstance componentInstance = compInstUidToCompInstMap.get(componentInstUid); -// String componentUid = componentInstance.getComponentUid(); -// List componentToscaNames = new ArrayList<>(); -// TitanOperationStatus status = resourceOperation.fillResourceDerivedListFromGraph(componentUid, componentToscaNames); -// if (status != TitanOperationStatus.OK) { -// BeEcompErrorManager.getInstance().logInternalFlowError(CREATE_GROUP, "Cannot find tosca list of component id " + componentUid, ErrorSeverity.ERROR); -// return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); -// } -// -// log.debug("The tosca names of component id {} are {}", componentUid, memberToscaTypes); -// -// boolean found = false; -// for (String memberToscaType : memberToscaTypes) { -// if (componentToscaNames.contains(memberToscaType)) { -// found = true; -// break; -// } -// } -// if (found == false) { -// BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, -// "No tosca types from " + memberToscaTypes + " can be found in the tosca list " + componentToscaNames + " of component " + componentInstance.getNormalizedName(), ErrorSeverity.INFO); -// /* -// * # %1 - member name # %2 - group name # %3 - group type -// */ -// return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_INVALID_TOSCA_NAME_OF_COMPONENT_INSTANCE, componentInstName, groupName, groupType)); -// } else { -// log.debug("Component instance {} fits to one of the required tosca types", componentInstance.getNormalizedName()); -// } -// } -// } else { -// BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "Cannot find tosca list since it is not supported for product", ErrorSeverity.ERROR); -// return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); -// } + // ComponentOperation componentOperation = getComponentOperationByParentComponentType(componentType); + // if (componentOperation instanceof ResourceOperation) { + // ResourceOperation resourceOperation = (ResourceOperation) componentOperation; + // + // for (Entry groupMember : groupMembers.entrySet()) { + // + // String componentInstName = groupMember.getKey(); + // String componentInstUid = groupMember.getValue(); + // + // ComponentInstance componentInstance = compInstUidToCompInstMap.get(componentInstUid); + // String componentUid = componentInstance.getComponentUid(); + // List componentToscaNames = new ArrayList<>(); + // TitanOperationStatus status = resourceOperation.fillResourceDerivedListFromGraph(componentUid, componentToscaNames); + // if (status != TitanOperationStatus.OK) { + // BeEcompErrorManager.getInstance().logInternalFlowError(CREATE_GROUP, "Cannot find tosca list of component id " + componentUid, ErrorSeverity.ERROR); + // return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + // } + // + // log.debug("The tosca names of component id {} are {}", componentUid, memberToscaTypes); + // + // boolean found = false; + // for (String memberToscaType : memberToscaTypes) { + // if (componentToscaNames.contains(memberToscaType)) { + // found = true; + // break; + // } + // } + // if (found == false) { + // BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, + // "No tosca types from " + memberToscaTypes + " can be found in the tosca list " + componentToscaNames + " of component " + componentInstance.getNormalizedName(), ErrorSeverity.INFO); + // /* + // * # %1 - member name # %2 - group name # %3 - group type + // */ + // return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_INVALID_TOSCA_NAME_OF_COMPONENT_INSTANCE, componentInstName, groupName, groupType)); + // } else { + // log.debug("Component instance {} fits to one of the required tosca types", componentInstance.getNormalizedName()); + // } + // } + // } else { + // BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "Cannot find tosca list since it is not supported for product", ErrorSeverity.ERROR); + // return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + // } } @@ -340,21 +311,12 @@ public class GroupBusinessLogic extends BaseBusinessLogic { * @param inTransaction * @return */ - /*public Either updateGroupVersion(GroupDefinition groupDefinition, boolean inTransaction) { - Either result = null; - List groupIdsToUpdateVersion = new ArrayList<>(); - groupIdsToUpdateVersion.add(groupDefinition.getUniqueId()); - Either, StorageOperationStatus> updateGroupVersion = updateGroupVersion(groupIdsToUpdateVersion, inTransaction); - if (updateGroupVersion.isLeft()) { - result = Either.left(updateGroupVersion.left().value().get(0)); - } else { - log.debug("Failed to update group version. Status is {} ", updateGroupVersion.right().value()); - result = Either.right(updateGroupVersion.right().value()); - } - return result; - }*/ - - + /* + * public Either updateGroupVersion(GroupDefinition groupDefinition, boolean inTransaction) { Either result = null; List groupIdsToUpdateVersion = new + * ArrayList<>(); groupIdsToUpdateVersion.add(groupDefinition.getUniqueId()); Either, StorageOperationStatus> updateGroupVersion = updateGroupVersion(groupIdsToUpdateVersion, inTransaction); if (updateGroupVersion.isLeft()) + * { result = Either.left(updateGroupVersion.left().value().get(0)); } else { log.debug("Failed to update group version. Status is {} ", updateGroupVersion.right().value()); result = Either.right(updateGroupVersion.right().value()); } return + * result; } + */ /** * Update list of groups versions @@ -363,52 +325,44 @@ public class GroupBusinessLogic extends BaseBusinessLogic { * @param inTransaction * @return */ - /*public Either, StorageOperationStatus> updateGroupVersion(List groupsUniqueId, boolean inTransaction) { - - Either, StorageOperationStatus> result = null; - - try { - - result = groupOperation.updateGroupVersion(groupsUniqueId, true); - - return result; - - } finally { - - if (false == inTransaction) { - - if (result == null || result.isRight()) { - log.debug("Going to execute rollback on create group."); - titanDao.rollback(); - } else { - log.debug("Going to execute commit on create group."); - titanDao.commit(); - } - - } - - } + /* + * public Either, StorageOperationStatus> updateGroupVersion(List groupsUniqueId, boolean inTransaction) { + * + * Either, StorageOperationStatus> result = null; + * + * try { + * + * result = groupOperation.updateGroupVersion(groupsUniqueId, true); + * + * return result; + * + * } finally { + * + * if (false == inTransaction) { + * + * if (result == null || result.isRight()) { log.debug("Going to execute rollback on create group."); titanDao.rollback(); } else { log.debug("Going to execute commit on create group."); titanDao.commit(); } + * + * } + * + * } + * + * } + */ - }*/ + /** + * Update GroupDefinition metadata + * + * @param componentId + * @param user + * @param componentType + * @param updatedGroup + * @param inTransaction + * @return + */ + public Either validateAndUpdateGroupMetadata(String componentId, User user, ComponentTypeEnum componentType, GroupDefinition updatedGroup, boolean inTransaction) { -/** - * Update GroupDefinition metadata - * @param componentId - * @param user - * @param componentType - * @param updatedGroup - * @param inTransaction - * @return - */ - public Either validateAndUpdateGroupMetadata( - String componentId, - User user, - ComponentTypeEnum componentType, - GroupDefinition updatedGroup, - boolean inTransaction) { - Either result = null; - try{ + try { // Validate user exist Either validateUserExists = validateUserExists(user.getUserId(), UPDATE_GROUP, inTransaction); if (validateUserExists.isRight()) { @@ -429,14 +383,14 @@ public class GroupBusinessLogic extends BaseBusinessLogic { return result; } List currentGroups = component.getGroups(); - if(CollectionUtils.isEmpty(currentGroups)){ + if (CollectionUtils.isEmpty(currentGroups)) { log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(), component.getName(), ActionStatus.GROUP_IS_MISSING); result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(), component.getComponentType().getValue())); return result; } // Validate groups exists in the component Optional currentGroupOpt = currentGroups.stream().filter(g -> g.getUniqueId().equals(updatedGroup.getUniqueId())).findAny(); - if(!currentGroupOpt.isPresent()){ + if (!currentGroupOpt.isPresent()) { log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(), component.getName(), ActionStatus.GROUP_IS_MISSING); result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(), component.getComponentType().getValue())); return result; @@ -451,14 +405,14 @@ public class GroupBusinessLogic extends BaseBusinessLogic { if (!currentGroup.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE)) { log.error("Failed to update the metadata of group {}. Group type is {} and different then: {}", currentGroup.getName(), currentGroup.getType(), Constants.DEFAULT_GROUP_VF_MODULE); ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_TYPE, updatedGroup.getType()); - result = Either.right(responseFormat); + result = Either.right(responseFormat); return result; } result = updateGroupMetadata(component, currentGroup, updatedGroup); return result; - + } finally { - if(result.isLeft()){ + if (result.isLeft()) { titanDao.commit(); } else { titanDao.rollback(); @@ -466,15 +420,15 @@ public class GroupBusinessLogic extends BaseBusinessLogic { graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); } } - + private Either updateGroupMetadata(Component component, GroupDefinition currentGroup, GroupDefinition updatedGroup) { String currentGroupName = currentGroup.getName(); Either result = validateAndUpdateGroupMetadata(currentGroup, updatedGroup); - - if(result.isRight()){ + + if (result.isRight()) { log.debug("Failed to validate a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName()); } - if(result.isLeft()){ + if (result.isLeft()) { result = updateGroup(component, currentGroup, currentGroupName); } return result; @@ -483,25 +437,25 @@ public class GroupBusinessLogic extends BaseBusinessLogic { private Either updateGroup(Component component, GroupDefinition updatedGroup, String currentGroupName) { Either handleGroupRes; Either result = null; - if(updatedGroup.getName().equals(currentGroupName)){ + if (updatedGroup.getName().equals(currentGroupName)) { handleGroupRes = groupsOperation.updateGroup(component, updatedGroup); - if(handleGroupRes.isRight()){ + if (handleGroupRes.isRight()) { log.debug("Failed to update a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName()); result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(handleGroupRes.right().value()))); } } else { StorageOperationStatus deleteStatus = groupsOperation.deleteGroup(component, currentGroupName); - if(deleteStatus != StorageOperationStatus.OK){ + if (deleteStatus != StorageOperationStatus.OK) { log.debug("Failed to delete the group {} from component {}. ", updatedGroup.getName(), component.getName()); - result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteStatus))); + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteStatus))); } handleGroupRes = groupsOperation.addGroup(component, updatedGroup); - if(handleGroupRes.isRight()){ + if (handleGroupRes.isRight()) { log.debug("Failed to add the group {} to component {}. ", updatedGroup.getName(), component.getName()); result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(handleGroupRes.right().value()))); } } - if(result == null){ + if (result == null) { result = Either.left(updatedGroup); } return result; @@ -509,6 +463,7 @@ public class GroupBusinessLogic extends BaseBusinessLogic { /** * Validate and Update Group Property + * * @param componentId * @param groupUniqueId * @param user @@ -517,43 +472,36 @@ public class GroupBusinessLogic extends BaseBusinessLogic { * @param inTransaction * @return */ - public Either, ResponseFormat> validateAndUpdateGroupProperties( - String componentId, - String groupUniqueId, - User user, - ComponentTypeEnum componentType, - List groupPropertiesToUpdate, boolean inTransaction) { - + public Either, ResponseFormat> validateAndUpdateGroupProperties(String componentId, String groupUniqueId, User user, ComponentTypeEnum componentType, List groupPropertiesToUpdate, boolean inTransaction) { + Either, ResponseFormat> result = Either.left(groupPropertiesToUpdate); - try{ + try { Optional optionalGroupConnectedToVf = null; GroupDefinition currentGroup = null; StorageOperationStatus lockResult = graphLockOperation.lockComponent(componentId, componentType.getNodeType()); - if( lockResult != StorageOperationStatus.OK ){ - result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse( - lockResult, componentType), componentId)); + if (lockResult != StorageOperationStatus.OK) { + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(lockResult, componentType), componentId)); } - if( result.isLeft() ){ - //VF exist because lock succedded + if (result.isLeft()) { + // VF exist because lock succedded Resource vf = (Resource) toscaOperationFacade.getToscaElement(componentId).left().value(); - optionalGroupConnectedToVf = - //All groups on resource + optionalGroupConnectedToVf = + // All groups on resource vf.getGroups().stream(). - //Filter in group sent is part of VF groups - filter( e -> e.getUniqueId().equals(groupUniqueId)). - //Collect - findAny(); - if( !optionalGroupConnectedToVf.isPresent() ){ - result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, - groupUniqueId, vf.getName(), ComponentTypeEnum.RESOURCE.getValue())); + // Filter in group sent is part of VF groups + filter(e -> e.getUniqueId().equals(groupUniqueId)). + // Collect + findAny(); + if (!optionalGroupConnectedToVf.isPresent()) { + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, groupUniqueId, vf.getName(), ComponentTypeEnum.RESOURCE.getValue())); } } - - if( result.isLeft() ){ + + if (result.isLeft()) { currentGroup = optionalGroupConnectedToVf.get(); result = validateGroupPropertyAndResetEmptyValue(currentGroup, groupPropertiesToUpdate); } - if( result.isLeft() ){ + if (result.isLeft()) { result = updateGroupPropertiesValue(componentId, currentGroup, groupPropertiesToUpdate, inTransaction); if (result.isRight()) { BeEcompErrorManager.getInstance().logBeSystemError("Update GroupProperties"); @@ -561,49 +509,47 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } } - } - catch(Exception e){ + } catch (Exception e) { log.debug("Error in validateAndUpdateGroupProperty {}", e); result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); - } - finally{ + } finally { graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); } return result; } + private void resetEmptyValueWithDefaults(List groupPropertiesToUpdate, GroupDefinition originalGroup) { Map originalProperties = - //Stream of original properties from group + // Stream of original properties from group originalGroup.convertToGroupProperties().stream(). - //Collecting to map with name as key - collect(Collectors.toMap(e -> e.getName(), e -> e)); - for( GroupProperty gp : groupPropertiesToUpdate){ - if( StringUtils.isEmpty(gp.getValue())){ + // Collecting to map with name as key + collect(Collectors.toMap(e -> e.getName(), e -> e)); + for (GroupProperty gp : groupPropertiesToUpdate) { + if (StringUtils.isEmpty(gp.getValue())) { gp.setValue(originalProperties.get(gp.getName()).getDefaultValue()); } } - + } - private Either, ResponseFormat> validateGroupPropertyAndResetEmptyValue( - GroupDefinition originalGroup, List groupPropertiesToUpdate) { - + private Either, ResponseFormat> validateGroupPropertyAndResetEmptyValue(GroupDefinition originalGroup, List groupPropertiesToUpdate) { + Either, ResponseFormat> ret = validateOnlyValueChanged(groupPropertiesToUpdate, originalGroup); if (ret.isLeft()) { resetEmptyValueWithDefaults(groupPropertiesToUpdate, originalGroup); } if (ret.isLeft()) { // Validate Type Match Value - Optional optionalError = - //Stream of group properties + Optional optionalError = + // Stream of group properties groupPropertiesToUpdate.stream(). - //Validate each and map to returned Strorage status value - map( e -> groupOperation .validateAndUpdatePropertyValue(e)). - //Keep only failed result if there is such - filter( e -> e != StorageOperationStatus.OK). - //collect - findFirst(); - if( optionalError.isPresent()){ + // Validate each and map to returned Strorage status value + map(e -> groupOperation.validateAndUpdatePropertyValue(e)). + // Keep only failed result if there is such + filter(e -> e != StorageOperationStatus.OK). + // collect + findFirst(); + if (optionalError.isPresent()) { ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(optionalError.get()); ret = Either.right(componentsUtils.getResponseFormat(actionStatus)); } @@ -612,60 +558,54 @@ public class GroupBusinessLogic extends BaseBusinessLogic { if (ret.isLeft()) { // Validate min max ect... ret = validatePropertyBusinessLogic(groupPropertiesToUpdate, originalGroup); - } + } return ret; } - private Either, ResponseFormat> validatePropertyBusinessLogic( - List groupPropertiesToUpdate, GroupDefinition originalGroup) { + + private Either, ResponseFormat> validatePropertyBusinessLogic(List groupPropertiesToUpdate, GroupDefinition originalGroup) { Either, ResponseFormat> ret = Either.left(groupPropertiesToUpdate); - + Map nameValueMap = new HashMap<>(); - for(GroupProperty gp : groupPropertiesToUpdate){ - //Filter out non special properties which does not have Enum + for (GroupProperty gp : groupPropertiesToUpdate) { + // Filter out non special properties which does not have Enum final PropertyNames gpEnum = PropertyNames.findName(gp.getName()); - if( gpEnum != null ){ + if (gpEnum != null) { nameValueMap.put(gpEnum, gp.getValue()); } } - - if ( !MapUtils.isEmpty(nameValueMap) ) { - if (nameValueMap.containsKey(PropertyNames.INITIAL_COUNT) || nameValueMap.containsKey(PropertyNames.MAX_INSTANCES) - || nameValueMap.containsKey(PropertyNames.MIN_INSTANCES)) { - - + if (!MapUtils.isEmpty(nameValueMap)) { + + if (nameValueMap.containsKey(PropertyNames.INITIAL_COUNT) || nameValueMap.containsKey(PropertyNames.MAX_INSTANCES) || nameValueMap.containsKey(PropertyNames.MIN_INSTANCES)) { + Map oldValueMap = prepareMapWithOriginalProperties(originalGroup); - - Either eitherValid = validateMinMaxAndInitialCountPropertyLogicVF(nameValueMap, - oldValueMap); + + Either eitherValid = validateMinMaxAndInitialCountPropertyLogicVF(nameValueMap, oldValueMap); if (eitherValid.isRight()) { ret = Either.right(eitherValid.right().value()); } } - if (ret.isLeft() && (nameValueMap.containsKey(PropertyNames.VF_MODULE_DESCRIPTION) - || nameValueMap.containsKey(PropertyNames.VF_MODULE_LABEL))) { + if (ret.isLeft() && (nameValueMap.containsKey(PropertyNames.VF_MODULE_DESCRIPTION) || nameValueMap.containsKey(PropertyNames.VF_MODULE_LABEL))) { - Optional optionalError = - //Stream of group Properties + Optional optionalError = + // Stream of group Properties groupPropertiesToUpdate.stream(). - //Filter in only properties that needs text validation - filter(e -> enumHasValueFilter(e.getName(), - enumName -> PropertyNames.findName(enumName), - PropertyNames.VF_MODULE_DESCRIPTION, PropertyNames.VF_MODULE_LABEL)). - //validate text properties - map( e -> validateFreeText(e)). - //filter in only errors if exist - filter( e -> e.isRight()). - //map the Either value to the Error - map( e -> e.right().value()) - //collect - .findFirst(); - if( optionalError.isPresent() ){ + // Filter in only properties that needs text validation + filter(e -> enumHasValueFilter(e.getName(), enumName -> PropertyNames.findName(enumName), PropertyNames.VF_MODULE_DESCRIPTION, PropertyNames.VF_MODULE_LABEL)). + // validate text properties + map(e -> validateFreeText(e)). + // filter in only errors if exist + filter(e -> e.isRight()). + // map the Either value to the Error + map(e -> e.right().value()) + // collect + .findFirst(); + if (optionalError.isPresent()) { ret = Either.right(optionalError.get()); } - + } } @@ -674,83 +614,77 @@ public class GroupBusinessLogic extends BaseBusinessLogic { private Map prepareMapWithOriginalProperties(GroupDefinition originalGroup) { Map oldValueMap = new HashMap<>(); - PropertyNames[] propertiesToCheck = new PropertyNames[] { PropertyNames.INITIAL_COUNT, - PropertyNames.MAX_INSTANCES, PropertyNames.MIN_INSTANCES }; - - for(GroupProperty gp : originalGroup.convertToGroupProperties()){ - if( enumHasValueFilter(gp.getName(), enumName -> PropertyNames.findName(enumName), propertiesToCheck)){ + PropertyNames[] propertiesToCheck = new PropertyNames[] { PropertyNames.INITIAL_COUNT, PropertyNames.MAX_INSTANCES, PropertyNames.MIN_INSTANCES }; + + for (GroupProperty gp : originalGroup.convertToGroupProperties()) { + if (enumHasValueFilter(gp.getName(), enumName -> PropertyNames.findName(enumName), propertiesToCheck)) { oldValueMap.put(PropertyNames.findName(gp.getName()), gp.getValue()); } } - if( StringUtils.isEmpty(oldValueMap.get(PropertyNames.MAX_INSTANCES)) ){ + if (StringUtils.isEmpty(oldValueMap.get(PropertyNames.MAX_INSTANCES))) { oldValueMap.put(PropertyNames.MAX_INSTANCES, String.valueOf(Integer.MAX_VALUE)); } return oldValueMap; } - - private Either, ResponseFormat> validateOnlyValueChanged( - List groupPropertiesToUpdate, GroupDefinition originalGroup) { - + + private Either, ResponseFormat> validateOnlyValueChanged(List groupPropertiesToUpdate, GroupDefinition originalGroup) { + Either, ResponseFormat> ret = Either.left(groupPropertiesToUpdate); - if( CollectionUtils.isEmpty(groupPropertiesToUpdate) ){ + if (CollectionUtils.isEmpty(groupPropertiesToUpdate)) { ret = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, StringUtils.EMPTY)); - } - else if (CollectionUtils.isEmpty(originalGroup.getProperties())) { - ret = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, - groupPropertiesToUpdate.get(NumberUtils.INTEGER_ZERO).getName())); + } else if (CollectionUtils.isEmpty(originalGroup.getProperties())) { + ret = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, groupPropertiesToUpdate.get(NumberUtils.INTEGER_ZERO).getName())); } else { - Map namePropertyMap = - //Original Group Properties Stream + Map namePropertyMap = + // Original Group Properties Stream originalGroup.convertToGroupProperties().stream(). - //Collect to map with name as key - collect(Collectors.toMap(e -> e.getName(), e -> e)); - - Optional optionalMissingProperty = - //Group Properties to be updated Stream + // Collect to map with name as key + collect(Collectors.toMap(e -> e.getName(), e -> e)); + + Optional optionalMissingProperty = + // Group Properties to be updated Stream groupPropertiesToUpdate.stream(). - //Filter in property that is not contained in original if there is such - filter(e -> !namePropertyMap.containsKey(e.getName())). - //collect - findFirst(); - + // Filter in property that is not contained in original if there is such + filter(e -> !namePropertyMap.containsKey(e.getName())). + // collect + findFirst(); + if (optionalMissingProperty.isPresent()) { - ret = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, - optionalMissingProperty.get().getName())); - } - else{ - Optional optionalNonValueChange = - //groups to be updated stream + ret = Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_NOT_FOUND, optionalMissingProperty.get().getName())); + } else { + Optional optionalNonValueChange = + // groups to be updated stream groupPropertiesToUpdate.stream(). - //filter in only properties with non-value (illegal) change - filter( e -> !isOnlyGroupPropertyValueChanged(e, namePropertyMap.get(e.getName()))). - //Collect - findFirst(); + // filter in only properties with non-value (illegal) change + filter(e -> !isOnlyGroupPropertyValueChanged(e, namePropertyMap.get(e.getName()))). + // Collect + findFirst(); if (optionalNonValueChange.isPresent()) { - ret = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY, - optionalNonValueChange.get().getName())); + ret = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY, optionalNonValueChange.get().getName())); } } - + } return ret; } /** * if groupProperty are the same or if only value is different returns true, otherwise returns false. + * * @param groupProperty * @param groupProperty2 * @return */ private boolean isOnlyGroupPropertyValueChanged(GroupProperty groupProperty, GroupProperty groupProperty2) { - //Create 2 duplicates for groupPropery and reset their values + // Create 2 duplicates for groupPropery and reset their values Gson gson = new GsonBuilder().setPrettyPrinting().create(); try { GroupProperty groupPropertyDuplicate = new GroupProperty(groupProperty); groupPropertyDuplicate.setValue(null); groupPropertyDuplicate.setSchema(null); groupPropertyDuplicate.setParentUniqueId(null); -// GroupProperty groupProperty2Duplicate = gson.fromJson(JsonParserUtils.jsonToString(groupProperty2), GroupProperty.class); + // GroupProperty groupProperty2Duplicate = gson.fromJson(JsonParserUtils.jsonToString(groupProperty2), GroupProperty.class); GroupProperty groupProperty2Duplicate = new GroupProperty(groupProperty2); groupProperty2Duplicate.setValue(null); groupProperty2Duplicate.setSchema(null); @@ -759,8 +693,9 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } catch (Exception e) { log.debug("Failed validate group properties. ", e); return false; - } + } } + /** * Validate and update GroupDefinition metadata * @@ -864,183 +799,105 @@ public class GroupBusinessLogic extends BaseBusinessLogic { * @param inTransaction * @return */ - /*public Either, ResponseFormat> associateArtifactsToGroup(String componentId, String userId, ComponentTypeEnum componentType, List groups, boolean shouldLockComp, boolean inTransaction) { - - Either, ResponseFormat> result = null; - - if (shouldLockComp == true && inTransaction == true) { - BeEcompErrorManager.getInstance().logInternalFlowError("dissociateArtifactsFromGroup", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); - // Cannot lock component since we are in a middle of another - // transaction. - ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; - result = Either.right(componentsUtils.getResponseFormat(actionStatus)); - return result; - } - - Component component = null; - try { - - if (groups == null || groups.isEmpty()) { - return Either.right(componentsUtils.getResponseFormat(ActionStatus.OK)); - } - - Either validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, userId, componentType, groups, inTransaction); - if (validateGroupsBeforeUpdate.isRight()) { - result = Either.right(validateGroupsBeforeUpdate.right().value()); - return result; - } - - component = validateGroupsBeforeUpdate.left().value(); - - if (shouldLockComp) { - Either lockComponent = lockComponent(component, "Group - Associate Artifacts"); - if (lockComponent.isRight()) { - return Either.right(lockComponent.right().value()); - } - } - - List updatedGroups = new ArrayList<>(); - - List componentGroups = component.getGroups(); - - // per group, associate to it the artifacts - for (GroupDefinition groupDefinition : groups) { - - GroupDefinition componentGroup = componentGroups.stream().filter(p -> p.getUniqueId().equals(groupDefinition.getUniqueId())).findFirst().orElse(null); - if (componentGroup != null) { - List componentArtifacts = componentGroup.getArtifacts(); - int artifactsSizeInGroup = componentArtifacts == null ? 0 : componentArtifacts.size(); - if (artifactsSizeInGroup > 0) { - List artifactsToAssociate = groupDefinition.getArtifacts(); - - // if no artifcats sent - if (artifactsToAssociate == null || true == artifactsToAssociate.isEmpty()) { - continue; - } - - boolean isChanged = componentArtifacts.removeAll(artifactsToAssociate); - if (isChanged) {// I.e. At least one artifact is already - // associated to the group - log.debug("Some of the artifacts already associated to group {}" , groupDefinition.getUniqueId()); - return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ARTIFACT_ALREADY_ASSOCIATED, componentGroup.getName())); - } - } - } - - Either associateArtifactsToGroup = groupOperation.associateArtifactsToGroup(groupDefinition.getUniqueId(), groupDefinition.getArtifacts(), true); - - if (associateArtifactsToGroup.isRight()) { - ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(associateArtifactsToGroup.right().value()); - result = Either.right(componentsUtils.getResponseFormat(actionStatus)); - log.debug("Failed to update group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); - return result; - } - updatedGroups.add(associateArtifactsToGroup.left().value()); - - } - - result = Either.left(updatedGroups); - return result; - - } finally { - - if (false == inTransaction) { - - if (result == null || result.isRight()) { - log.debug("Going to execute rollback on create group."); - titanDao.rollback(); - } else { - log.debug("Going to execute commit on create group."); - titanDao.commit(); - } - - } - - // unlock resource - if (shouldLockComp && component != null) { - graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); - } - - } - }*/ - - /*public Either, ResponseFormat> associateMembersToGroup(String componentId, String userId, ComponentTypeEnum componentType, List groups, boolean shouldLockComp, boolean inTransaction) { - - Either, ResponseFormat> result = null; - - if (shouldLockComp == true && inTransaction == true) { - BeEcompErrorManager.getInstance().logInternalFlowError("dissociateArtifactsFromGroup", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); - // Cannot lock component since we are in a middle of another - // transaction. - ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; - result = Either.right(componentsUtils.getResponseFormat(actionStatus)); - return result; - } - - Component component = null; - try { - - if (groups == null || groups.isEmpty()) { - return Either.right(componentsUtils.getResponseFormat(ActionStatus.OK)); - } - - Either validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, userId, componentType, groups, inTransaction); - if (validateGroupsBeforeUpdate.isRight()) { - result = Either.right(validateGroupsBeforeUpdate.right().value()); - return result; - } - - component = validateGroupsBeforeUpdate.left().value(); - - if (shouldLockComp) { - Either lockComponent = lockComponent(component, "Group - Associate Members"); - if (lockComponent.isRight()) { - return Either.right(lockComponent.right().value()); - } - } - - List updatedGroups = new ArrayList<>(); - - // per group, associate to it the members - for (GroupDefinition groupDefinition : groups) { - - Either associateMembersToGroup = groupOperation.associateMembersToGroup(groupDefinition.getUniqueId(), groupDefinition.getMembers(), true); - - if (associateMembersToGroup.isRight()) { - ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(associateMembersToGroup.right().value()); - result = Either.right(componentsUtils.getResponseFormat(actionStatus)); - log.debug("Failed to update group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); - return result; - } else { - updatedGroups.add(associateMembersToGroup.left().value()); - } - - } - - result = Either.left(updatedGroups); - return result; - - } finally { - - if (false == inTransaction) { - - if (result == null || result.isRight()) { - log.debug("Going to execute rollback on create group."); - titanDao.rollback(); - } else { - log.debug("Going to execute commit on create group."); - titanDao.commit(); - } - - } - - // unlock resource - if (shouldLockComp && component != null) { - graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); - } + /* + * public Either, ResponseFormat> associateArtifactsToGroup(String componentId, String userId, ComponentTypeEnum componentType, List groups, boolean shouldLockComp, boolean inTransaction) { + * + * Either, ResponseFormat> result = null; + * + * if (shouldLockComp == true && inTransaction == true) { BeEcompErrorManager.getInstance().logInternalFlowError("dissociateArtifactsFromGroup", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); // Cannot lock + * component since we are in a middle of another // transaction. ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; result = Either.right(componentsUtils.getResponseFormat(actionStatus)); return result; } + * + * Component component = null; try { + * + * if (groups == null || groups.isEmpty()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.OK)); } + * + * Either validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, userId, componentType, groups, inTransaction); if (validateGroupsBeforeUpdate.isRight()) { result = + * Either.right(validateGroupsBeforeUpdate.right().value()); return result; } + * + * component = validateGroupsBeforeUpdate.left().value(); + * + * if (shouldLockComp) { Either lockComponent = lockComponent(component, "Group - Associate Artifacts"); if (lockComponent.isRight()) { return Either.right(lockComponent.right().value()); } } + * + * List updatedGroups = new ArrayList<>(); + * + * List componentGroups = component.getGroups(); + * + * // per group, associate to it the artifacts for (GroupDefinition groupDefinition : groups) { + * + * GroupDefinition componentGroup = componentGroups.stream().filter(p -> p.getUniqueId().equals(groupDefinition.getUniqueId())).findFirst().orElse(null); if (componentGroup != null) { List componentArtifacts = + * componentGroup.getArtifacts(); int artifactsSizeInGroup = componentArtifacts == null ? 0 : componentArtifacts.size(); if (artifactsSizeInGroup > 0) { List artifactsToAssociate = groupDefinition.getArtifacts(); + * + * // if no artifcats sent if (artifactsToAssociate == null || true == artifactsToAssociate.isEmpty()) { continue; } + * + * boolean isChanged = componentArtifacts.removeAll(artifactsToAssociate); if (isChanged) {// I.e. At least one artifact is already // associated to the group log.debug("Some of the artifacts already associated to group {}" , + * groupDefinition.getUniqueId()); return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ARTIFACT_ALREADY_ASSOCIATED, componentGroup.getName())); } } } + * + * Either associateArtifactsToGroup = groupOperation.associateArtifactsToGroup(groupDefinition.getUniqueId(), groupDefinition.getArtifacts(), true); + * + * if (associateArtifactsToGroup.isRight()) { ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(associateArtifactsToGroup.right().value()); result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + * log.debug("Failed to update group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); return result; } updatedGroups.add(associateArtifactsToGroup.left().value()); + * + * } + * + * result = Either.left(updatedGroups); return result; + * + * } finally { + * + * if (false == inTransaction) { + * + * if (result == null || result.isRight()) { log.debug("Going to execute rollback on create group."); titanDao.rollback(); } else { log.debug("Going to execute commit on create group."); titanDao.commit(); } + * + * } + * + * // unlock resource if (shouldLockComp && component != null) { graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); } + * + * } } + */ - } - }*/ + /* + * public Either, ResponseFormat> associateMembersToGroup(String componentId, String userId, ComponentTypeEnum componentType, List groups, boolean shouldLockComp, boolean inTransaction) { + * + * Either, ResponseFormat> result = null; + * + * if (shouldLockComp == true && inTransaction == true) { BeEcompErrorManager.getInstance().logInternalFlowError("dissociateArtifactsFromGroup", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); // Cannot lock + * component since we are in a middle of another // transaction. ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; result = Either.right(componentsUtils.getResponseFormat(actionStatus)); return result; } + * + * Component component = null; try { + * + * if (groups == null || groups.isEmpty()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.OK)); } + * + * Either validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, userId, componentType, groups, inTransaction); if (validateGroupsBeforeUpdate.isRight()) { result = + * Either.right(validateGroupsBeforeUpdate.right().value()); return result; } + * + * component = validateGroupsBeforeUpdate.left().value(); + * + * if (shouldLockComp) { Either lockComponent = lockComponent(component, "Group - Associate Members"); if (lockComponent.isRight()) { return Either.right(lockComponent.right().value()); } } + * + * List updatedGroups = new ArrayList<>(); + * + * // per group, associate to it the members for (GroupDefinition groupDefinition : groups) { + * + * Either associateMembersToGroup = groupOperation.associateMembersToGroup(groupDefinition.getUniqueId(), groupDefinition.getMembers(), true); + * + * if (associateMembersToGroup.isRight()) { ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(associateMembersToGroup.right().value()); result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + * log.debug("Failed to update group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); return result; } else { updatedGroups.add(associateMembersToGroup.left().value()); } + * + * } + * + * result = Either.left(updatedGroups); return result; + * + * } finally { + * + * if (false == inTransaction) { + * + * if (result == null || result.isRight()) { log.debug("Going to execute rollback on create group."); titanDao.rollback(); } else { log.debug("Going to execute commit on create group."); titanDao.commit(); } + * + * } + * + * // unlock resource if (shouldLockComp && component != null) { graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); } + * + * } } + */ /** * associate artifacts to a given group @@ -1084,17 +941,16 @@ public class GroupBusinessLogic extends BaseBusinessLogic { component = validateComponent.left().value(); Either groupEither = findGroupOnComponent(component, groupId); - + if (groupEither.isRight()) { log.debug("Faild to find group {} under component {}", groupId, component.getUniqueId()); BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "group " + groupId + " not found under component " + component.getUniqueId(), ErrorSeverity.INFO); String componentTypeForResponse = getComponentTypeForResponse(component); result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, groupId, component.getSystemName(), componentTypeForResponse)); return result; - } + } GroupDefinition group = groupEither.left().value(); - - + Boolean isBase = null;// Constants.IS_BASE; List props = group.convertToGroupProperties(); if (props != null && !props.isEmpty()) { @@ -1114,14 +970,14 @@ public class GroupBusinessLogic extends BaseBusinessLogic { List artifacts = new ArrayList<>(); List artifactsFromComponent = new ArrayList<>(); List artifactsIds = group.getArtifacts(); - + Map deploymentArtifacts = null; - if(MapUtils.isNotEmpty(component.getDeploymentArtifacts())){ + if (MapUtils.isNotEmpty(component.getDeploymentArtifacts())) { deploymentArtifacts = component.getDeploymentArtifacts().values().stream().collect(Collectors.toMap(a -> a.getUniqueId(), a -> a)); } - + if (artifactsIds != null && !artifactsIds.isEmpty()) { - for(String id: artifactsIds){ + for (String id : artifactsIds) { if (MapUtils.isEmpty(deploymentArtifacts) || !deploymentArtifacts.containsKey(id)) { log.debug("Failed to get artifact {} . Status is {} ", id, StorageOperationStatus.NOT_FOUND); ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.NOT_FOUND)); @@ -1166,15 +1022,15 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } private Either findGroupOnComponent(Component component, String groupId) { - + Either result = null; - if(CollectionUtils.isNotEmpty(component.getGroups())){ + if (CollectionUtils.isNotEmpty(component.getGroups())) { Optional foundGroup = component.getGroups().stream().filter(g -> g.getUniqueId().equals(groupId)).findFirst(); - if(foundGroup.isPresent()){ - result = Either.left(foundGroup.get()); + if (foundGroup.isPresent()) { + result = Either.left(foundGroup.get()); } } - if(result == null){ + if (result == null) { result = Either.right(StorageOperationStatus.NOT_FOUND); } return result; @@ -1260,399 +1116,231 @@ public class GroupBusinessLogic extends BaseBusinessLogic { List currentGroups = component.getGroups(); boolean found = false; - List updatedGroupsName = groups.stream().map(getByParam).collect(Collectors.toList()); - - List missingGroupNames = updatedGroupsName; - - if (currentGroups != null && false == currentGroups.isEmpty()) { - List currentGroupsName = currentGroups.stream().map(getByParam).collect(Collectors.toList()); - - if (currentGroupsName.containsAll(updatedGroupsName)) { - found = true; - } else { - currentGroupsName.removeAll(currentGroupsName); - missingGroupNames = currentGroupsName; - } - } - if (false == found) { - String componentTypeForResponse = getComponentTypeForResponse(component); - String listOfGroups = getAsString(missingGroupNames); - result = componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, listOfGroups, component.getSystemName(), componentTypeForResponse); - return result; - } - - return null; - } - - public String getAsString(List list) { - - if (list == null || list.isEmpty()) { - return ""; - } - StringBuilder builder = new StringBuilder(); - list.forEach(p -> builder.append(p + ",")); - - String result = builder.toString(); - return result.substring(0, result.length()); - - } - - /** - * dissociate artifacts from a given group - * - * @param componentId - * @param userId - * @param componentType - * @param groups - * @param shouldLockComp - * @param inTransaction - * @return - */ - /*public Either, ResponseFormat> dissociateArtifactsFromGroup(String componentId, String userId, ComponentTypeEnum componentType, List groups, boolean shouldLockComp, boolean inTransaction) { - - Either, ResponseFormat> result = null; - - if (shouldLockComp == true && inTransaction == true) { - BeEcompErrorManager.getInstance().logInternalFlowError("dissociateArtifactsFromGroup", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); - // Cannot lock component since we are in a middle of another - // transaction. - ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; - result = Either.right(componentsUtils.getResponseFormat(actionStatus)); - return result; - } - - Component component = null; - - try { - - if (groups == null || groups.isEmpty()) { - return Either.right(componentsUtils.getResponseFormat(ActionStatus.OK)); - } - - Either validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, userId, componentType, groups, inTransaction); - if (validateGroupsBeforeUpdate.isRight()) { - result = Either.right(validateGroupsBeforeUpdate.right().value()); - return result; - } - - component = validateGroupsBeforeUpdate.left().value(); - - if (shouldLockComp) { - Either lockComponent = lockComponent(component, "Group - Dissociate Artifacts"); - if (lockComponent.isRight()) { - return Either.right(lockComponent.right().value()); - } - } - - List updatedGroups = new ArrayList<>(); - - List componentGroups = component.getGroups(); - // per group, associate to it the artifacts - for (GroupDefinition groupDefinition : groups) { - - GroupDefinition componentGroup = componentGroups.stream().filter(p -> p.getUniqueId().equals(groupDefinition.getUniqueId())).findFirst().orElse(null); - if (componentGroup != null) { - List componentArtifacts = componentGroup.getArtifacts(); - int artifactsSizeInGroup = componentArtifacts == null ? 0 : componentArtifacts.size(); - List artifactsToDissociate = groupDefinition.getArtifacts(); - - // if no artifcats sent - if (artifactsToDissociate == null || true == artifactsToDissociate.isEmpty()) { - continue; - } - - if (artifactsSizeInGroup > 0) { - - boolean containsAll = componentArtifacts.containsAll(artifactsToDissociate); - if (false == containsAll) { // At least one artifact is - // not associated to the - // group - log.debug("Some of the artifacts already dissociated to group {}" , groupDefinition.getUniqueId()); - return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ARTIFACT_ALREADY_DISSOCIATED, componentGroup.getName())); - } - } else { - if (artifactsSizeInGroup == 0) { - if (artifactsToDissociate != null && false == artifactsToDissociate.isEmpty()) { - log.debug("No artifact is found under the group {}" , groupDefinition.getUniqueId()); - return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ARTIFACT_ALREADY_DISSOCIATED, componentGroup.getName())); - } - } - } - } - - Either associateArtifactsToGroup = groupOperation.dissociateArtifactsFromGroup(groupDefinition.getUniqueId(), groupDefinition.getArtifacts(), true); - - if (associateArtifactsToGroup.isRight()) { - ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(associateArtifactsToGroup.right().value()); - result = Either.right(componentsUtils.getResponseFormat(actionStatus)); - log.debug("Failed to update group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); - return result; - } - updatedGroups.add(associateArtifactsToGroup.left().value()); - - } - - result = Either.left(updatedGroups); - return result; - - } finally { - - if (false == inTransaction) { - - if (result == null || result.isRight()) { - log.debug("Going to execute rollback on create group."); - titanDao.rollback(); - } else { - log.debug("Going to execute commit on create group."); - titanDao.commit(); - } - - } - // unlock resource - if (shouldLockComp && component != null) { - graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); - } - - } - - }*/ - - /*public Either, ResponseFormat> createGroups(String componentId, String userId, ComponentTypeEnum componentType, List groupDefinitions, boolean shouldLockComp, boolean inTransaction) { - - Either, ResponseFormat> result = null; - - List groups = new ArrayList<>(); - org.openecomp.sdc.be.model.Component component = null; - try { - - if (groupDefinitions != null && !groupDefinitions.isEmpty()) { - - if (shouldLockComp && inTransaction) { - BeEcompErrorManager.getInstance().logInternalFlowError("createGroups", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); - // Cannot lock component since we are in a middle of another - // transaction. - ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; - result = Either.right(componentsUtils.getResponseFormat(actionStatus)); - return result; - } - - Either validateUserExists = validateUserExists(userId, CREATE_GROUP, true); - if (validateUserExists.isRight()) { - result = Either.right(validateUserExists.right().value()); - return result; - } - - User user = validateUserExists.left().value(); - - ComponentParametersView componentParametersView = new ComponentParametersView(); - componentParametersView.disableAll(); - componentParametersView.setIgnoreGroups(false); - componentParametersView.setIgnoreArtifacts(false); - componentParametersView.setIgnoreUsers(false); - componentParametersView.setIgnoreComponentInstances(false); - - Either validateComponent = validateComponentExists(componentId, componentType, componentParametersView); - - if (validateComponent.isRight()) { - result = Either.right(validateComponent.right().value()); - return result; - } - component = validateComponent.left().value(); - - if (shouldLockComp) { - Either lockComponent = lockComponent(component, "CreateGroups"); - if (lockComponent.isRight()) { - return Either.right(lockComponent.right().value()); - } - } - - Either canWork = validateCanWorkOnComponent(component, userId); - if (canWork.isRight()) { - result = Either.right(canWork.right().value()); - return result; - } - - for (GroupDefinition groupDefinition : groupDefinitions) { - Either createGroup = this.createGroup(component, user, componentType, groupDefinition, true); - if (createGroup.isRight()) { - log.debug("Failed to create group {}." , groupDefinition ); - result = Either.right(createGroup.right().value()); - return result; - } - GroupDefinition createdGroup = createGroup.left().value(); - groups.add(createdGroup); - } - } - - result = Either.left(groups); - return result; - - } finally { - - if (false == inTransaction) { - - if (result == null || result.isRight()) { - log.debug("Going to execute rollback on create group."); - titanDao.rollback(); - } else { - log.debug("Going to execute commit on create group."); - titanDao.commit(); - } - - } - // unlock resource - if (shouldLockComp && component != null) { - graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); - } - - } - - } - - public Either createGroup(Component component, User user, ComponentTypeEnum componentType, GroupDefinition groupDefinition, boolean inTransaction) { - - Either result = null; - - log.trace("Going to create group {}" , groupDefinition); - - try { - - // 3. verify group not already exist - List groups = component.getGroups(); - boolean found = false; - if (groups != null && false == groups.isEmpty()) { - - GroupDefinition existGroupDef = groups.stream().filter(p -> p.getName().equalsIgnoreCase(groupDefinition.getName())).findFirst().orElse(null); - - found = existGroupDef != null; - } - - if (true == found) { - String componentTypeForResponse = getComponentTypeForResponse(component); - result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ALREADY_EXIST, groupDefinition.getName(), component.getNormalizedName(), componentTypeForResponse)); - return result; - } - - // 4. verify type of group exist - String groupType = groupDefinition.getType(); - if (groupType == null || groupType.isEmpty()) { - result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_MISSING_GROUP_TYPE, groupDefinition.getName())); - return result; - } - Either getGroupType = groupTypeOperation.getLatestGroupTypeByType(groupType, true); - if (getGroupType.isRight()) { - StorageOperationStatus status = getGroupType.right().value(); - if (status == StorageOperationStatus.NOT_FOUND) { - BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "group type " + groupType + " cannot be found", ErrorSeverity.INFO); - result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, groupType)); - return result; - } else { - result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); - return result; - } - } - - // 6. verify the component instances type are allowed according to - // the member types in the group type - GroupTypeDefinition groupTypeDefinition = getGroupType.left().value(); - - Either areValidMembers = verifyComponentInstancesAreValidMembers(component, componentType, groupDefinition.getName(), groupType, groupDefinition.getMembers(), groupTypeDefinition.getMembers()); - - if (areValidMembers.isRight()) { - ResponseFormat responseFormat = areValidMembers.right().value(); - result = Either.right(responseFormat); - return result; - } - - // 7. verify the artifacts belongs to the component - Either areValidArtifacts = verifyArtifactsBelongsToComponent(component, groupDefinition.getArtifacts(), CREATE_GROUP); - if (areValidArtifacts.isRight()) { - ResponseFormat responseFormat = areValidArtifacts.right().value(); - result = Either.right(responseFormat); - return result; - } - - NodeTypeEnum nodeTypeEnum = componentType.getNodeType(); - - // add invariantUUID - String invariantUUID = UniqueIdBuilder.buildInvariantUUID(); - groupDefinition.setInvariantUUID(invariantUUID); - - // add groupUUID - String groupUUID = UniqueIdBuilder.generateUUID(); - groupDefinition.setGroupUUID(groupUUID); - - // add version - groupDefinition.setVersion(INITIAL_VERSION); + List updatedGroupsName = groups.stream().map(getByParam).collect(Collectors.toList()); - // set groupType uid - groupDefinition.setTypeUid(groupTypeDefinition.getUniqueId()); + List missingGroupNames = updatedGroupsName; - Either addGroupToGraph = groupOperation.addGroup(nodeTypeEnum, component.getUniqueId(), groupDefinition, true); + if (currentGroups != null && false == currentGroups.isEmpty()) { + List currentGroupsName = currentGroups.stream().map(getByParam).collect(Collectors.toList()); - if (addGroupToGraph.isRight()) { - StorageOperationStatus storageOperationStatus = addGroupToGraph.right().value(); - ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageOperationStatus); - result = Either.right(componentsUtils.getResponseFormat(actionStatus)); - log.debug("Failed to create group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); + if (currentGroupsName.containsAll(updatedGroupsName)) { + found = true; } else { - GroupDefinition groupDefinitionCreated = addGroupToGraph.left().value(); - result = Either.left(groupDefinitionCreated); + currentGroupsName.removeAll(currentGroupsName); + missingGroupNames = currentGroupsName; } - + } + if (false == found) { + String componentTypeForResponse = getComponentTypeForResponse(component); + String listOfGroups = getAsString(missingGroupNames); + result = componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, listOfGroups, component.getSystemName(), componentTypeForResponse); return result; + } - } finally { - - if (false == inTransaction) { - - if (result == null || result.isRight()) { - log.debug("Going to execute rollback on create group."); - titanDao.rollback(); - } else { - log.debug("Going to execute commit on create group."); - titanDao.commit(); - } + return null; + } - } + public String getAsString(List list) { + if (list == null || list.isEmpty()) { + return ""; } + StringBuilder builder = new StringBuilder(); + list.forEach(p -> builder.append(p + ",")); + + String result = builder.toString(); + return result.substring(0, result.length()); } - public Either, ResponseFormat> updateVfModuleGroupNames(String resourceSystemName, List groups, boolean inTransaction) { - List updatedGroups = new ArrayList<>(); - Either, ResponseFormat> updateGroupNamesRes = Either.left(updatedGroups); - Either updateGroupNameRes; - Either validateGenerateGroupNameRes; - int counter; - for (GroupDefinition group : groups) { - if (!group.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE) && !Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(group.getName()).matches()) { - continue; - } - counter = Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1]); - validateGenerateGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, group.getDescription(), counter); - if (validateGenerateGroupNameRes.isRight()) { - updateGroupNamesRes = Either.right(validateGenerateGroupNameRes.right().value()); - break; - } - updateGroupNameRes = groupOperation.updateGroupName(group.getUniqueId(), validateGenerateGroupNameRes.left().value(), inTransaction); - if (updateGroupNameRes.isRight()) { - ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(updateGroupNameRes.right().value()); - updateGroupNamesRes = Either.right(componentsUtils.getResponseFormat(actionStatus)); - break; - } - updatedGroups.add(updateGroupNameRes.left().value()); - } - return updateGroupNamesRes; - }*/ + /** + * dissociate artifacts from a given group + * + * @param componentId + * @param userId + * @param componentType + * @param groups + * @param shouldLockComp + * @param inTransaction + * @return + */ + /* + * public Either, ResponseFormat> dissociateArtifactsFromGroup(String componentId, String userId, ComponentTypeEnum componentType, List groups, boolean shouldLockComp, boolean inTransaction) { + * + * Either, ResponseFormat> result = null; + * + * if (shouldLockComp == true && inTransaction == true) { BeEcompErrorManager.getInstance().logInternalFlowError("dissociateArtifactsFromGroup", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); // Cannot lock + * component since we are in a middle of another // transaction. ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; result = Either.right(componentsUtils.getResponseFormat(actionStatus)); return result; } + * + * Component component = null; + * + * try { + * + * if (groups == null || groups.isEmpty()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.OK)); } + * + * Either validateGroupsBeforeUpdate = validateGroupsBeforeUpdate(componentId, userId, componentType, groups, inTransaction); if (validateGroupsBeforeUpdate.isRight()) { result = + * Either.right(validateGroupsBeforeUpdate.right().value()); return result; } + * + * component = validateGroupsBeforeUpdate.left().value(); + * + * if (shouldLockComp) { Either lockComponent = lockComponent(component, "Group - Dissociate Artifacts"); if (lockComponent.isRight()) { return Either.right(lockComponent.right().value()); } } + * + * List updatedGroups = new ArrayList<>(); + * + * List componentGroups = component.getGroups(); // per group, associate to it the artifacts for (GroupDefinition groupDefinition : groups) { + * + * GroupDefinition componentGroup = componentGroups.stream().filter(p -> p.getUniqueId().equals(groupDefinition.getUniqueId())).findFirst().orElse(null); if (componentGroup != null) { List componentArtifacts = + * componentGroup.getArtifacts(); int artifactsSizeInGroup = componentArtifacts == null ? 0 : componentArtifacts.size(); List artifactsToDissociate = groupDefinition.getArtifacts(); + * + * // if no artifcats sent if (artifactsToDissociate == null || true == artifactsToDissociate.isEmpty()) { continue; } + * + * if (artifactsSizeInGroup > 0) { + * + * boolean containsAll = componentArtifacts.containsAll(artifactsToDissociate); if (false == containsAll) { // At least one artifact is // not associated to the // group log.debug("Some of the artifacts already dissociated to group {}" , + * groupDefinition.getUniqueId()); return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ARTIFACT_ALREADY_DISSOCIATED, componentGroup.getName())); } } else { if (artifactsSizeInGroup == 0) { if (artifactsToDissociate != null && + * false == artifactsToDissociate.isEmpty()) { log.debug("No artifact is found under the group {}" , groupDefinition.getUniqueId()); return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ARTIFACT_ALREADY_DISSOCIATED, + * componentGroup.getName())); } } } } + * + * Either associateArtifactsToGroup = groupOperation.dissociateArtifactsFromGroup(groupDefinition.getUniqueId(), groupDefinition.getArtifacts(), true); + * + * if (associateArtifactsToGroup.isRight()) { ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(associateArtifactsToGroup.right().value()); result = Either.right(componentsUtils.getResponseFormat(actionStatus)); + * log.debug("Failed to update group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); return result; } updatedGroups.add(associateArtifactsToGroup.left().value()); + * + * } + * + * result = Either.left(updatedGroups); return result; + * + * } finally { + * + * if (false == inTransaction) { + * + * if (result == null || result.isRight()) { log.debug("Going to execute rollback on create group."); titanDao.rollback(); } else { log.debug("Going to execute commit on create group."); titanDao.commit(); } + * + * } // unlock resource if (shouldLockComp && component != null) { graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); } + * + * } + * + * } + */ + + /* + * public Either, ResponseFormat> createGroups(String componentId, String userId, ComponentTypeEnum componentType, List groupDefinitions, boolean shouldLockComp, boolean inTransaction) { + * + * Either, ResponseFormat> result = null; + * + * List groups = new ArrayList<>(); org.openecomp.sdc.be.model.Component component = null; try { + * + * if (groupDefinitions != null && !groupDefinitions.isEmpty()) { + * + * if (shouldLockComp && inTransaction) { BeEcompErrorManager.getInstance().logInternalFlowError("createGroups", "Cannot lock component since we are inside a transaction", ErrorSeverity.ERROR); // Cannot lock component since we are in a middle of + * another // transaction. ActionStatus actionStatus = ActionStatus.INVALID_CONTENT; result = Either.right(componentsUtils.getResponseFormat(actionStatus)); return result; } + * + * Either validateUserExists = validateUserExists(userId, CREATE_GROUP, true); if (validateUserExists.isRight()) { result = Either.right(validateUserExists.right().value()); return result; } + * + * User user = validateUserExists.left().value(); + * + * ComponentParametersView componentParametersView = new ComponentParametersView(); componentParametersView.disableAll(); componentParametersView.setIgnoreGroups(false); componentParametersView.setIgnoreArtifacts(false); + * componentParametersView.setIgnoreUsers(false); componentParametersView.setIgnoreComponentInstances(false); + * + * Either validateComponent = validateComponentExists(componentId, componentType, componentParametersView); + * + * if (validateComponent.isRight()) { result = Either.right(validateComponent.right().value()); return result; } component = validateComponent.left().value(); + * + * if (shouldLockComp) { Either lockComponent = lockComponent(component, "CreateGroups"); if (lockComponent.isRight()) { return Either.right(lockComponent.right().value()); } } + * + * Either canWork = validateCanWorkOnComponent(component, userId); if (canWork.isRight()) { result = Either.right(canWork.right().value()); return result; } + * + * for (GroupDefinition groupDefinition : groupDefinitions) { Either createGroup = this.createGroup(component, user, componentType, groupDefinition, true); if (createGroup.isRight()) { + * log.debug("Failed to create group {}." , groupDefinition ); result = Either.right(createGroup.right().value()); return result; } GroupDefinition createdGroup = createGroup.left().value(); groups.add(createdGroup); } } + * + * result = Either.left(groups); return result; + * + * } finally { + * + * if (false == inTransaction) { + * + * if (result == null || result.isRight()) { log.debug("Going to execute rollback on create group."); titanDao.rollback(); } else { log.debug("Going to execute commit on create group."); titanDao.commit(); } + * + * } // unlock resource if (shouldLockComp && component != null) { graphLockOperation.unlockComponent(componentId, componentType.getNodeType()); } + * + * } + * + * } + * + * public Either createGroup(Component component, User user, ComponentTypeEnum componentType, GroupDefinition groupDefinition, boolean inTransaction) { + * + * Either result = null; + * + * log.trace("Going to create group {}" , groupDefinition); + * + * try { + * + * // 3. verify group not already exist List groups = component.getGroups(); boolean found = false; if (groups != null && false == groups.isEmpty()) { + * + * GroupDefinition existGroupDef = groups.stream().filter(p -> p.getName().equalsIgnoreCase(groupDefinition.getName())).findFirst().orElse(null); + * + * found = existGroupDef != null; } + * + * if (true == found) { String componentTypeForResponse = getComponentTypeForResponse(component); result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ALREADY_EXIST, groupDefinition.getName(), component.getNormalizedName(), + * componentTypeForResponse)); return result; } + * + * // 4. verify type of group exist String groupType = groupDefinition.getType(); if (groupType == null || groupType.isEmpty()) { result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_MISSING_GROUP_TYPE, + * groupDefinition.getName())); return result; } Either getGroupType = groupTypeOperation.getLatestGroupTypeByType(groupType, true); if (getGroupType.isRight()) { StorageOperationStatus status = + * getGroupType.right().value(); if (status == StorageOperationStatus.NOT_FOUND) { BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "group type " + groupType + " cannot be found", ErrorSeverity.INFO); result = + * Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, groupType)); return result; } else { result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); return result; } } + * + * // 6. verify the component instances type are allowed according to // the member types in the group type GroupTypeDefinition groupTypeDefinition = getGroupType.left().value(); + * + * Either areValidMembers = verifyComponentInstancesAreValidMembers(component, componentType, groupDefinition.getName(), groupType, groupDefinition.getMembers(), groupTypeDefinition.getMembers()); + * + * if (areValidMembers.isRight()) { ResponseFormat responseFormat = areValidMembers.right().value(); result = Either.right(responseFormat); return result; } + * + * // 7. verify the artifacts belongs to the component Either areValidArtifacts = verifyArtifactsBelongsToComponent(component, groupDefinition.getArtifacts(), CREATE_GROUP); if (areValidArtifacts.isRight()) { + * ResponseFormat responseFormat = areValidArtifacts.right().value(); result = Either.right(responseFormat); return result; } + * + * NodeTypeEnum nodeTypeEnum = componentType.getNodeType(); + * + * // add invariantUUID String invariantUUID = UniqueIdBuilder.buildInvariantUUID(); groupDefinition.setInvariantUUID(invariantUUID); + * + * // add groupUUID String groupUUID = UniqueIdBuilder.generateUUID(); groupDefinition.setGroupUUID(groupUUID); + * + * // add version groupDefinition.setVersion(INITIAL_VERSION); + * + * // set groupType uid groupDefinition.setTypeUid(groupTypeDefinition.getUniqueId()); + * + * Either addGroupToGraph = groupOperation.addGroup(nodeTypeEnum, component.getUniqueId(), groupDefinition, true); + * + * if (addGroupToGraph.isRight()) { StorageOperationStatus storageOperationStatus = addGroupToGraph.right().value(); ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(storageOperationStatus); result = + * Either.right(componentsUtils.getResponseFormat(actionStatus)); log.debug("Failed to create group {} under component {}, error: {}", groupDefinition.getName(), component.getNormalizedName(), actionStatus.name()); } else { GroupDefinition + * groupDefinitionCreated = addGroupToGraph.left().value(); result = Either.left(groupDefinitionCreated); } + * + * return result; + * + * } finally { + * + * if (false == inTransaction) { + * + * if (result == null || result.isRight()) { log.debug("Going to execute rollback on create group."); titanDao.rollback(); } else { log.debug("Going to execute commit on create group."); titanDao.commit(); } + * + * } + * + * } + * + * } + * + * public Either, ResponseFormat> updateVfModuleGroupNames(String resourceSystemName, List groups, boolean inTransaction) { List updatedGroups = new ArrayList<>(); + * Either, ResponseFormat> updateGroupNamesRes = Either.left(updatedGroups); Either updateGroupNameRes; Either validateGenerateGroupNameRes; int counter; for + * (GroupDefinition group : groups) { if (!group.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE) && !Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(group.getName()).matches()) { continue; } counter = + * Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1]); validateGenerateGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, group.getDescription(), counter); if (validateGenerateGroupNameRes.isRight()) { + * updateGroupNamesRes = Either.right(validateGenerateGroupNameRes.right().value()); break; } updateGroupNameRes = groupOperation.updateGroupName(group.getUniqueId(), validateGenerateGroupNameRes.left().value(), inTransaction); if + * (updateGroupNameRes.isRight()) { ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(updateGroupNameRes.right().value()); updateGroupNamesRes = Either.right(componentsUtils.getResponseFormat(actionStatus)); break; } + * updatedGroups.add(updateGroupNameRes.left().value()); } return updateGroupNamesRes; } + */ - private Either, ResponseFormat> updateGroupPropertiesValue(String componentId, - GroupDefinition currentGroup, List groupPropertyToUpdate, boolean inTransaction) { + private Either, ResponseFormat> updateGroupPropertiesValue(String componentId, GroupDefinition currentGroup, List groupPropertyToUpdate, boolean inTransaction) { Either, ResponseFormat> result; - Either, StorageOperationStatus> eitherUpdate = groupsOperation - .updateGroupPropertiesOnComponent(componentId, currentGroup, groupPropertyToUpdate); + Either, StorageOperationStatus> eitherUpdate = groupsOperation.updateGroupPropertiesOnComponent(componentId, currentGroup, groupPropertyToUpdate); if (eitherUpdate.isRight()) { ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(eitherUpdate.right().value()); result = Either.right(componentsUtils.getResponseFormat(actionStatus)); @@ -1661,7 +1349,7 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } return result; } - + public Either validateGenerateVfModuleGroupNames(List allGroups, String resourceSystemName, int startGroupCounter) { Either validateGenerateGroupNamesRes = Either.left(true); Collections.sort(allGroups, (art1, art2) -> ArtifactTemplateInfo.compareByGroupName(art1, art2)); @@ -1768,53 +1456,38 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } newGroupName = newGroupNameRes.left().value(); group.setName(newGroupName); - + } updatedGroups.add(group); - + } result = Either.left(updatedGroups); return result; } - /*public Either, ResponseFormat> createGroups(Component component, User user, ComponentTypeEnum componentType, List groupDefinitions, boolean inTransaction) { - - List generatedGroups = new ArrayList<>(); - Either, ResponseFormat> result = Either.left(generatedGroups); - - try { - - if (groupDefinitions != null && false == groupDefinitions.isEmpty()) { - for (GroupDefinition groupDefinition : groupDefinitions) { - Either createGroup = this.createGroup(component, user, componentType, groupDefinition, true); - if (createGroup.isRight()) { - result = Either.right(createGroup.right().value()); - return result; - } - GroupDefinition generatedGroup = createGroup.left().value(); - generatedGroups.add(generatedGroup); - } - } - - return result; - } finally { - - if (false == inTransaction) { - - if (result == null || result.isRight()) { - log.debug("Going to execute rollback on create group."); - titanDao.rollback(); - } else { - log.debug("Going to execute commit on create group."); - titanDao.commit(); - } - - } - - } - - }*/ + /* + * public Either, ResponseFormat> createGroups(Component component, User user, ComponentTypeEnum componentType, List groupDefinitions, boolean inTransaction) { + * + * List generatedGroups = new ArrayList<>(); Either, ResponseFormat> result = Either.left(generatedGroups); + * + * try { + * + * if (groupDefinitions != null && false == groupDefinitions.isEmpty()) { for (GroupDefinition groupDefinition : groupDefinitions) { Either createGroup = this.createGroup(component, user, componentType, + * groupDefinition, true); if (createGroup.isRight()) { result = Either.right(createGroup.right().value()); return result; } GroupDefinition generatedGroup = createGroup.left().value(); generatedGroups.add(generatedGroup); } } + * + * return result; } finally { + * + * if (false == inTransaction) { + * + * if (result == null || result.isRight()) { log.debug("Going to execute rollback on create group."); titanDao.rollback(); } else { log.debug("Going to execute commit on create group."); titanDao.commit(); } + * + * } + * + * } + * + * } + */ public Either getGroupInstWithArtifactsById(ComponentTypeEnum componentType, String componentId, String componentInstanceId, String groupInstId, String userId, boolean inTransaction) { Either result = null; @@ -1833,7 +1506,7 @@ public class GroupBusinessLogic extends BaseBusinessLogic { try { ComponentParametersView componentParametersView = new ComponentParametersView(); - componentParametersView.disableAll(); + componentParametersView.disableAll(); componentParametersView.setIgnoreUsers(false); componentParametersView.setIgnoreComponentInstances(false); componentParametersView.setIgnoreArtifacts(false); @@ -1845,7 +1518,7 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } component = validateComponent.left().value(); Either, StorageOperationStatus> findComponentInstanceAndGroupInstanceRes = findComponentInstanceAndGroupInstanceOnComponent(component, componentInstanceId, groupInstId); - + if (findComponentInstanceAndGroupInstanceRes.isRight()) { log.debug("Failed to get group {} . Status is {} ", groupInstId, findComponentInstanceAndGroupInstanceRes.right().value()); ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(findComponentInstanceAndGroupInstanceRes.right().value())); @@ -1855,7 +1528,7 @@ public class GroupBusinessLogic extends BaseBusinessLogic { GroupInstance group = findComponentInstanceAndGroupInstanceRes.left().value().getRight(); ComponentInstance componentInstance = findComponentInstanceAndGroupInstanceRes.left().value().getLeft(); - + Boolean isBase = null;// Constants.IS_BASE; List props = group.convertToGroupInstancesProperties(); if (props != null && !props.isEmpty()) { @@ -1871,30 +1544,33 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } } - + List artifacts = new ArrayList<>(); - List artifactsFromComponent = new ArrayList<>(); List artifactsIds = group.getArtifacts(); if (artifactsIds != null && !artifactsIds.isEmpty()) { - - for(String id: artifactsIds){ - Either artifactEither = artifactsOperation.getArtifactById(componentInstance.getComponentUid(), id); - if (artifactEither.isRight()) { - log.debug("Failed to get artifact {} . Status is {} ", id, artifactEither.right().value()); - ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(artifactEither.right().value())); - result = Either.right(responseFormat); - return result; - } - artifactsFromComponent.add(artifactEither.left().value()); - } - if (!artifactsFromComponent.isEmpty()) { - for (ArtifactDefinition artifactDefinition : artifactsFromComponent) { - ArtifactDefinitionInfo artifactDefinitionInfo = new ArtifactDefinitionInfo(artifactDefinition); - artifacts.add(artifactDefinitionInfo); + + List instances = component.getComponentInstances(); + if (instances != null) { + Optional findFirst = instances.stream().filter(i -> i.getUniqueId().equals(componentInstanceId)).findFirst(); + if (findFirst.isPresent()) { + ComponentInstance ci = findFirst.get(); + Map deploymentArtifacts = ci.getDeploymentArtifacts(); + for (String id : artifactsIds) { + Optional artOp = deploymentArtifacts.values().stream().filter(a -> a.getUniqueId().equals(id)).findFirst(); + if (artOp.isPresent()) { + artifacts.add(new ArtifactDefinitionInfo(artOp.get())); + } + } + List instArtifactsIds = group.getGroupInstanceArtifacts(); + for (String id : instArtifactsIds) { + Optional artOp = deploymentArtifacts.values().stream().filter(a -> a.getUniqueId().equals(id)).findFirst(); + if (artOp.isPresent()) { + artifacts.add(new ArtifactDefinitionInfo(artOp.get())); + } + } } + } - - } GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group); resultInfo.setIsBase(isBase); @@ -1905,7 +1581,6 @@ public class GroupBusinessLogic extends BaseBusinessLogic { return result; - } finally { if (false == inTransaction) { @@ -1922,250 +1597,230 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } } - + private Either, StorageOperationStatus> findComponentInstanceAndGroupInstanceOnComponent(Component component, String componentInstanceId, String groupInstId) { - - Either, StorageOperationStatus> result = null; - if(CollectionUtils.isNotEmpty(component.getComponentInstances())){ + + Either, StorageOperationStatus> result = null; + if (CollectionUtils.isNotEmpty(component.getComponentInstances())) { Optional foundGroup; Optional foundComponent = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(componentInstanceId)).findFirst(); - if(foundComponent.isPresent() && CollectionUtils.isNotEmpty(foundComponent.get().getGroupInstances())){ + if (foundComponent.isPresent() && CollectionUtils.isNotEmpty(foundComponent.get().getGroupInstances())) { foundGroup = foundComponent.get().getGroupInstances().stream().filter(gi -> gi.getUniqueId().equals(groupInstId)).findFirst(); - if(foundGroup.isPresent()){ + if (foundGroup.isPresent()) { result = Either.left(new ImmutablePair<>(foundComponent.get(), foundGroup.get())); } } } - if(result == null){ + if (result == null) { result = Either.right(StorageOperationStatus.NOT_FOUND); } return result; } - private int getLatestIntProperty(Map newValues, Map parentValues, - PropertyNames propertyKey) { + private int getLatestIntProperty(Map newValues, Map parentValues, PropertyNames propertyKey) { String value; - if( newValues.containsKey(propertyKey) ){ + if (newValues.containsKey(propertyKey)) { value = newValues.get(propertyKey); - } - else{ + } else { value = parentValues.get(propertyKey); } return Integer.valueOf(value); } - private boolean isPropertyChanged(Map newValues, Map parentValues, - final PropertyNames minInstances) { + private boolean isPropertyChanged(Map newValues, Map parentValues, final PropertyNames minInstances) { return newValues.containsKey(minInstances) && newValues.containsKey(minInstances) && !newValues.get(minInstances).equals(parentValues.get(minInstances)); } - private Either validateMinMaxAndInitialCountPropertyLogicVF( - Map newValues, Map parentValues) { - + private Either validateMinMaxAndInitialCountPropertyLogicVF(Map newValues, Map parentValues) { + int latestMaxInstances = getLatestIntProperty(newValues, parentValues, PropertyNames.MAX_INSTANCES); int latestInitialCount = getLatestIntProperty(newValues, parentValues, PropertyNames.INITIAL_COUNT); int latestMinInstances = getLatestIntProperty(newValues, parentValues, PropertyNames.MIN_INSTANCES); Either result = Either.left(true); - + if (isPropertyChanged(newValues, parentValues, PropertyNames.INITIAL_COUNT) && result.isLeft()) { if (latestInitialCount > latestMaxInstances || latestInitialCount < latestMinInstances) { - result = Either.right( - componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_INITIAL_COUNT_PROPERTY_VALUE, - PropertyNames.INITIAL_COUNT.getPropertyName(), String.valueOf(latestMinInstances), - String.valueOf(latestMaxInstances))); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_INITIAL_COUNT_PROPERTY_VALUE, PropertyNames.INITIAL_COUNT.getPropertyName(), String.valueOf(latestMinInstances), String.valueOf(latestMaxInstances))); } } if (isPropertyChanged(newValues, parentValues, PropertyNames.MAX_INSTANCES) && result.isLeft()) { if (latestMaxInstances < latestInitialCount) { - result = Either.right(componentsUtils.getResponseFormat( - ActionStatus.INVALID_GROUP_PROPERTY_VALUE_LOWER_HIGHER, - PropertyNames.MAX_INSTANCES.getPropertyName(), "higher", String.valueOf(latestInitialCount))); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_PROPERTY_VALUE_LOWER_HIGHER, PropertyNames.MAX_INSTANCES.getPropertyName(), "higher", String.valueOf(latestInitialCount))); } } if (isPropertyChanged(newValues, parentValues, PropertyNames.MIN_INSTANCES) && result.isLeft()) { if (latestMinInstances > latestInitialCount) { - result = Either.right(componentsUtils.getResponseFormat( - ActionStatus.INVALID_GROUP_PROPERTY_VALUE_LOWER_HIGHER, - PropertyNames.MIN_INSTANCES.getPropertyName(), "lower", String.valueOf(latestInitialCount))); + result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_PROPERTY_VALUE_LOWER_HIGHER, PropertyNames.MIN_INSTANCES.getPropertyName(), "lower", String.valueOf(latestInitialCount))); } } return result; } + private Either validateMinMaxAndInitialCountPropertyLogic(Map newValues, Map currValues, Map parentValues) { - + Either result; - for(Entry entry : newValues.entrySet()){ + for (Entry entry : newValues.entrySet()) { PropertyNames currPropertyName = entry.getKey(); - if(currPropertyName == PropertyNames.MIN_INSTANCES){ + if (currPropertyName == PropertyNames.MIN_INSTANCES) { String minValue = parentValues.get(PropertyNames.MIN_INSTANCES); String maxValue = newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MAX_INSTANCES) : currValues.get(PropertyNames.INITIAL_COUNT); - result = validateValueInRange(new ImmutablePair(currPropertyName, entry.getValue()), - new ImmutablePair(PropertyNames.MIN_INSTANCES, minValue), + result = validateValueInRange(new ImmutablePair(currPropertyName, entry.getValue()), new ImmutablePair(PropertyNames.MIN_INSTANCES, minValue), new ImmutablePair(PropertyNames.MAX_INSTANCES, maxValue)); - if(result.isRight()){ + if (result.isRight()) { return result; } - } - else if(currPropertyName == PropertyNames.INITIAL_COUNT){ + } else if (currPropertyName == PropertyNames.INITIAL_COUNT) { String minValue = newValues.containsKey(PropertyNames.MIN_INSTANCES) ? newValues.get(PropertyNames.MIN_INSTANCES) : currValues.get(PropertyNames.MIN_INSTANCES); String maxValue = newValues.containsKey(PropertyNames.MAX_INSTANCES) ? newValues.get(PropertyNames.MAX_INSTANCES) : currValues.get(PropertyNames.MAX_INSTANCES); - result = validateValueInRange(new ImmutablePair(currPropertyName, entry.getValue()), - new ImmutablePair(PropertyNames.MIN_INSTANCES,minValue), + result = validateValueInRange(new ImmutablePair(currPropertyName, entry.getValue()), new ImmutablePair(PropertyNames.MIN_INSTANCES, minValue), new ImmutablePair(PropertyNames.MAX_INSTANCES, maxValue)); - if(result.isRight()){ + if (result.isRight()) { return result; } - } - else if(currPropertyName == PropertyNames.MAX_INSTANCES){ + } else if (currPropertyName == PropertyNames.MAX_INSTANCES) { String minValue = newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MIN_INSTANCES) : currValues.get(PropertyNames.INITIAL_COUNT); String maxValue = parentValues.get(PropertyNames.MAX_INSTANCES); - result = validateValueInRange(new ImmutablePair(currPropertyName, entry.getValue()), - new ImmutablePair(PropertyNames.MIN_INSTANCES, minValue), + result = validateValueInRange(new ImmutablePair(currPropertyName, entry.getValue()), new ImmutablePair(PropertyNames.MIN_INSTANCES, minValue), new ImmutablePair(PropertyNames.MAX_INSTANCES, maxValue)); - if(result.isRight()){ + if (result.isRight()) { return result; } } } - return Either.left(true); + return Either.left(true); } - private Either validateValueInRange(ImmutablePair newValue, ImmutablePair min, ImmutablePair max) { + private Either validateValueInRange(ImmutablePair newValue, ImmutablePair min, ImmutablePair max) { Either result; final String warnMessage = "Failed to validate {} as property value of {}. It must be not higher than {}, and not lower than {}."; int newValueInt = parseIntValue(newValue.getValue(), newValue.getKey()); int minInt = parseIntValue(min.getValue(), min.getKey()); int maxInt = parseIntValue(max.getValue(), max.getKey()); - if(newValueInt < 0 || minInt < 0 || maxInt < 0){ + if (newValueInt < 0 || minInt < 0 || maxInt < 0) { result = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_PROPERTY)); - } - else if (newValueInt < minInt || newValueInt > maxInt) { + } else if (newValueInt < minInt || newValueInt > maxInt) { log.debug(warnMessage, newValue.getValue(), newValue.getKey().getPropertyName(), min.getValue(), max.getValue()); - result = Either.right(componentsUtils.getResponseFormat( - ActionStatus.INVALID_GROUP_MIN_MAX_INSTANCES_PROPERTY_VALUE, - newValue.getKey().getPropertyName(), maxInt == Integer.MAX_VALUE ? Constants.UNBOUNDED : max.getValue(), min.getValue())); - }else{ + result = Either + .right(componentsUtils.getResponseFormat(ActionStatus.INVALID_GROUP_MIN_MAX_INSTANCES_PROPERTY_VALUE, newValue.getKey().getPropertyName(), maxInt == Integer.MAX_VALUE ? Constants.UNBOUNDED : max.getValue(), min.getValue())); + } else { result = Either.left(true); } return result; } - - private int parseIntValue(String value, PropertyNames propertyName) { + + private int parseIntValue(String value, PropertyNames propertyName) { int result; - if(propertyName == PropertyNames.MAX_INSTANCES ){ + if (propertyName == PropertyNames.MAX_INSTANCES) { result = convertIfUnboundMax(value); } else if (NumberUtils.isNumber(value)) { result = Integer.parseInt(value); - } else{ + } else { result = -1; } return result; } -/** - * validates received new property values and updates group instance in case of success - * @param oldGroupInstance - * @param groupInstanceId - * @param newProperties - * @param inTransaction - * @return - */ + /** + * validates received new property values and updates group instance in case of success + * + * @param oldGroupInstance + * @param groupInstanceId + * @param newProperties + * @param inTransaction + * @return + */ public Either validateAndUpdateGroupInstancePropertyValues(String componentId, String instanceId, GroupInstance oldGroupInstance, List newProperties, boolean inTransaction) { - + Either actionResult = null; Either updateGroupInstanceResult = null; Either, ResponseFormat> validateRes = validateReduceGroupInstancePropertiesBeforeUpdate(oldGroupInstance, newProperties); - if(validateRes.isRight()){ + if (validateRes.isRight()) { log.debug("Failed to validate group instance {} properties before update. ", oldGroupInstance.getName()); - actionResult = Either.right(validateRes.right().value()); + actionResult = Either.right(validateRes.right().value()); } - if(actionResult == null){ + if (actionResult == null) { List validatedReducedNewProperties = validateRes.left().value(); updateGroupInstanceResult = groupsOperation.updateGroupInstancePropertyValuesOnGraph(componentId, instanceId, oldGroupInstance, validatedReducedNewProperties); - if(updateGroupInstanceResult.isRight()){ + if (updateGroupInstanceResult.isRight()) { log.debug("Failed to update group instance {} property values. ", oldGroupInstance.getName()); - actionResult = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateGroupInstanceResult.right().value()))); + actionResult = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateGroupInstanceResult.right().value()))); } } - if(actionResult == null){ + if (actionResult == null) { actionResult = Either.left(updateGroupInstanceResult.left().value()); } return actionResult; } - + private Either, ResponseFormat> validateReduceGroupInstancePropertiesBeforeUpdate(GroupInstance oldGroupInstance, List newProperties) { - + Either validationRes = null; Either, ResponseFormat> actionResult; - Map existingProperties = oldGroupInstance.convertToGroupInstancesProperties().stream().collect(Collectors.toMap(p->p.getName(),p->p)); + Map existingProperties = oldGroupInstance.convertToGroupInstancesProperties().stream().collect(Collectors.toMap(p -> p.getName(), p -> p)); Map newPropertyValues = new EnumMap<>(PropertyNames.class); List reducedProperties = new ArrayList<>(); String currPropertyName; - try{ - for(GroupInstanceProperty currNewProperty : newProperties){ + try { + for (GroupInstanceProperty currNewProperty : newProperties) { currPropertyName = currNewProperty.getName(); validationRes = handleAndAddProperty(reducedProperties, newPropertyValues, currNewProperty, existingProperties.get(currPropertyName)); - if(validationRes.isRight()){ + if (validationRes.isRight()) { log.debug("Failed to handle property {} of group instance {}. ", currPropertyName, oldGroupInstance.getName()); break; } } - if(validationRes == null || validationRes.isLeft()){ + if (validationRes == null || validationRes.isLeft()) { Map existingPropertyValues = new EnumMap<>(PropertyNames.class); Map parentPropertyValues = new EnumMap<>(PropertyNames.class); fillValuesAndParentValuesFromExistingProperties(existingProperties, existingPropertyValues, parentPropertyValues); validationRes = validateMinMaxAndInitialCountPropertyLogic(newPropertyValues, existingPropertyValues, parentPropertyValues); } - if(validationRes.isLeft()){ + if (validationRes.isLeft()) { actionResult = Either.left(reducedProperties); } else { actionResult = Either.right(validationRes.right().value()); } - } catch( Exception e){ + } catch (Exception e) { log.error("Exception occured during validation and reducing group instance properties. The message is {}", e.getMessage(), e); actionResult = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); } return actionResult; } - private void fillValuesAndParentValuesFromExistingProperties(Map existingProperties, - Map propertyValues, Map parentPropertyValues) { + private void fillValuesAndParentValuesFromExistingProperties(Map existingProperties, Map propertyValues, Map parentPropertyValues) { PropertyNames[] allPropertyNames = PropertyNames.values(); - for(PropertyNames name : allPropertyNames){ - if(isUpdatable(name)){ + for (PropertyNames name : allPropertyNames) { + if (isUpdatable(name)) { propertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getValue())); parentPropertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getParentValue())); } } } - private Either handleAndAddProperty(List reducedProperties, Map newPropertyValues, - GroupInstanceProperty currNewProperty, GroupInstanceProperty currExistingProperty) { + private Either handleAndAddProperty(List reducedProperties, Map newPropertyValues, GroupInstanceProperty currNewProperty, GroupInstanceProperty currExistingProperty) { Either validationRes = null; String currPropertyName = currNewProperty.getName(); PropertyNames propertyName = PropertyNames.findName(currPropertyName); - try{ - if(currExistingProperty == null){ + try { + if (currExistingProperty == null) { log.warn("The value of property with the name {} cannot be updated. The property not found on group instance. ", currPropertyName); - } - else if(isUpdatable(propertyName)){ + } else if (isUpdatable(propertyName)) { validationRes = validateAndUpdatePropertyValue(currNewProperty, currExistingProperty); - if(validationRes.isRight()){ - log.debug("Failed to validate property value {} of property {}. ", currNewProperty.getValue() , currPropertyName); + if (validationRes.isRight()) { + log.debug("Failed to validate property value {} of property {}. ", currNewProperty.getValue(), currPropertyName); } else { addPropertyUpdatedValues(reducedProperties, propertyName, newPropertyValues, currNewProperty, currExistingProperty); } - } - else{ + } else { validateImmutableProperty(currExistingProperty, currNewProperty); } - if(validationRes == null){ + if (validationRes == null) { validationRes = Either.left(true); } - } catch( Exception e){ + } catch (Exception e) { log.error("Exception occured during handle and adding property. The message is {}", e.getMessage(), e); validationRes = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); } @@ -2173,76 +1828,73 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } private boolean isUpdatable(PropertyNames updatablePropertyName) { - return updatablePropertyName != null && - updatablePropertyName.getUpdateBehavior().getLevelNumber() >= GroupInstancePropertyValueUpdateBehavior.UPDATABLE_ON_SERVICE_LEVEL.getLevelNumber(); + return updatablePropertyName != null && updatablePropertyName.getUpdateBehavior().getLevelNumber() >= GroupInstancePropertyValueUpdateBehavior.UPDATABLE_ON_SERVICE_LEVEL.getLevelNumber(); } - private void addPropertyUpdatedValues(List reducedProperties, PropertyNames propertyName, Map newPropertyValues, - GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) { - - String newValue = newProperty.getValue(); - if(!newValue.equals(String.valueOf(existingProperty.getValue()))){ + private void addPropertyUpdatedValues(List reducedProperties, PropertyNames propertyName, Map newPropertyValues, GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) { + + String newValue = newProperty.getValue(); + if (!newValue.equals(String.valueOf(existingProperty.getValue()))) { newProperty.setValueUniqueUid(existingProperty.getValueUniqueUid()); reducedProperties.add(newProperty); } - if(!isEmptyMinInitialCountValue(propertyName, newValue)){ + if (!isEmptyMinInitialCountValue(propertyName, newValue)) { newPropertyValues.put(propertyName, newValue); } } - + private boolean isEmptyMinInitialCountValue(PropertyNames propertyName, String newValue) { boolean result = false; - if((propertyName == PropertyNames.MIN_INSTANCES || propertyName == PropertyNames.INITIAL_COUNT) && !NumberUtils.isNumber(newValue)){ + if ((propertyName == PropertyNames.MIN_INSTANCES || propertyName == PropertyNames.INITIAL_COUNT) && !NumberUtils.isNumber(newValue)) { result = true; } return result; } private int convertIfUnboundMax(String value) { - + int result; - if(!NumberUtils.isNumber(value)){ + if (!NumberUtils.isNumber(value)) { result = Integer.MAX_VALUE; - } - else{ + } else { result = Integer.parseInt(value); } return result; } private Either validateAndUpdatePropertyValue(GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) { - + Either validationRes = null; String parentValue = existingProperty.getParentValue(); - + newProperty.setParentValue(parentValue); - if(StringUtils.isEmpty(newProperty.getValue())){ + if (StringUtils.isEmpty(newProperty.getValue())) { newProperty.setValue(parentValue); } - if(StringUtils.isEmpty(existingProperty.getValue())){ + if (StringUtils.isEmpty(existingProperty.getValue())) { existingProperty.setValue(parentValue); } - StorageOperationStatus status = groupOperation.validateAndUpdatePropertyValue(newProperty); - if(status != StorageOperationStatus.OK){ + StorageOperationStatus status = groupOperation.validateAndUpdatePropertyValue(newProperty); + if (status != StorageOperationStatus.OK) { log.debug("Failed to validate property value {} of property with name {}. Status is {}. ", newProperty.getValue(), newProperty.getName(), status); validationRes = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(status))); } - if(validationRes == null){ + if (validationRes == null) { validationRes = Either.left(true); } return validationRes; } private void validateImmutableProperty(GroupProperty oldProperty, GroupProperty newProperty) { - if(oldProperty.getValue() == null && newProperty.getValue() != null || oldProperty.getValue()!=null && !oldProperty.getValue().equals(newProperty.getValue())){ - log.warn("The value of property with the name {} cannot be updated on service level. Going to ignore new property value {}. ",oldProperty.getName(), newProperty.getValue()); + if (oldProperty.getValue() == null && newProperty.getValue() != null || oldProperty.getValue() != null && !oldProperty.getValue().equals(newProperty.getValue())) { + log.warn("The value of property with the name {} cannot be updated on service level. Going to ignore new property value {}. ", oldProperty.getName(), newProperty.getValue()); } } public Either, ResponseFormat> createGroups(Component component, User user, ComponentTypeEnum componentType, List groupDefinitions) { - Map groups = new HashMap<>(); - //Map groupsPropertiesMap = new HashMap<>(); + Map groups = new HashMap<>(); + // Map groupsPropertiesMap = new HashMap<>(); Either, ResponseFormat> result = null; Either, StorageOperationStatus> createGroupsResult = null; Either, TitanOperationStatus> allDataTypes = dataTypeCache.getAll(); @@ -2253,38 +1905,37 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } - //handle groups and convert to tosca data + // handle groups and convert to tosca data if (groupDefinitions != null && !groupDefinitions.isEmpty()) { for (GroupDefinition groupDefinition : groupDefinitions) { - Either handleGroupRes = handleGroup(component, user, componentType, groupDefinition, allDataTypes.left().value()); + Either handleGroupRes = handleGroup(component, user, componentType, groupDefinition, allDataTypes.left().value()); if (handleGroupRes.isRight()) { result = Either.right(handleGroupRes.right().value()); break; } GroupDefinition handledGroup = handleGroupRes.left().value(); groups.put(handledGroup.getName(), new GroupDataDefinition(handledGroup)); - + } } - if(result == null){ + if (result == null) { createGroupsResult = groupsOperation.createGroups(component, user, componentType, groups); - if(createGroupsResult.isRight()){ + if (createGroupsResult.isRight()) { result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value()))); } } - if(result == null){ + if (result == null) { result = Either.left(createGroupsResult.left().value()); } return result; } - + public Either, ResponseFormat> addGroups(Component component, User user, ComponentTypeEnum componentType, List groupDefinitions) { - Either, ResponseFormat> result = null; Either, StorageOperationStatus> createGroupsResult = null; List groups = new ArrayList<>(); - + Either, TitanOperationStatus> allDataTypes = dataTypeCache.getAll(); if (allDataTypes.isRight()) { TitanOperationStatus status = allDataTypes.right().value(); @@ -2293,10 +1944,10 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } - //handle groups and convert to tosca data + // handle groups and convert to tosca data if (groupDefinitions != null && !groupDefinitions.isEmpty()) { for (GroupDefinition groupDefinition : groupDefinitions) { - Either handleGroupRes = handleGroup(component, user, componentType, groupDefinition, allDataTypes.left().value()); + Either handleGroupRes = handleGroup(component, user, componentType, groupDefinition, allDataTypes.left().value()); if (handleGroupRes.isRight()) { result = Either.right(handleGroupRes.right().value()); break; @@ -2305,35 +1956,34 @@ public class GroupBusinessLogic extends BaseBusinessLogic { groups.add(new GroupDataDefinition(handledGroup)); } } - if(result == null){ + if (result == null) { createGroupsResult = groupsOperation.addGroups(component, user, componentType, groups); - if(createGroupsResult.isRight()){ + if (createGroupsResult.isRight()) { result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value()))); } } - if(result == null){ + if (result == null) { result = Either.left(createGroupsResult.left().value()); } return result; } - + public Either, ResponseFormat> deleteGroups(Component component, User user, ComponentTypeEnum componentType, List groupDefinitions) { - Either, ResponseFormat> result = null; Either, StorageOperationStatus> createGroupsResult = null; - - createGroupsResult = groupsOperation.deleteGroups(component, user, componentType, groupDefinitions.stream().map(x-> new GroupDataDefinition(x)).collect(Collectors.toList())); - if(createGroupsResult.isRight()){ - result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value()))); - } - - if(result == null){ + + createGroupsResult = groupsOperation.deleteGroups(component, user, componentType, groupDefinitions.stream().map(x -> new GroupDataDefinition(x)).collect(Collectors.toList())); + if (createGroupsResult.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value()))); + } + + if (result == null) { result = Either.left(createGroupsResult.left().value()); } return result; } - + /** * Update specific group version * @@ -2341,34 +1991,34 @@ public class GroupBusinessLogic extends BaseBusinessLogic { * @param inTransaction * @return */ - public Either, ResponseFormat> updateGroups(Component component, ComponentTypeEnum componentType, List groupDefinitions) { + public Either, ResponseFormat> updateGroups(Component component, ComponentTypeEnum componentType, List groupDefinitions) { Either, ResponseFormat> result = null; Either, StorageOperationStatus> createGroupsResult = null; - - createGroupsResult = groupsOperation.updateGroups(component, componentType, groupDefinitions.stream().map(x-> new GroupDataDefinition(x)).collect(Collectors.toList())); - if(createGroupsResult.isRight()){ - result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value()))); - } - - if(result == null){ + + createGroupsResult = groupsOperation.updateGroups(component, componentType, groupDefinitions.stream().map(x -> new GroupDataDefinition(x)).collect(Collectors.toList())); + if (createGroupsResult.isRight()) { + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value()))); + } + + if (result == null) { result = Either.left(createGroupsResult.left().value()); } return result; } - + public Either handleGroup(Component component, User user, ComponentTypeEnum componentType, GroupDefinition groupDefinition, Map allDAtaTypes) { - + Either result = null; - - log.trace("Going to create group {}" , groupDefinition); + + log.trace("Going to create group {}", groupDefinition); // 3. verify group not already exist List groups = component.getGroups(); boolean found = false; if (groups != null && false == groups.isEmpty()) { - + GroupDefinition existGroupDef = groups.stream().filter(p -> p.getName().equalsIgnoreCase(groupDefinition.getName())).findFirst().orElse(null); - + found = existGroupDef != null; } if (true == found) { @@ -2413,7 +2063,7 @@ public class GroupBusinessLogic extends BaseBusinessLogic { return result; } List groupTypeProperties = groupTypeDefinition.getProperties(); - + List properties = groupDefinition.convertToGroupProperties(); List updatedGroupTypeProperties = new ArrayList<>(); if (properties != null && false == properties.isEmpty()) { @@ -2429,20 +2079,20 @@ public class GroupBusinessLogic extends BaseBusinessLogic { int i = 1; for (GroupProperty prop : properties) { addPropertyResult = handleProperty(prop, groupTypePropertiesMap.get(prop.getName()), i, allDAtaTypes); - if(addPropertyResult.isRight()){ + if (addPropertyResult.isRight()) { BeEcompErrorManager.getInstance().logInvalidInputError(ADDING_GROUP, "failed to validate property", ErrorSeverity.INFO); return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertTitanStatusToStorageStatus(addPropertyResult.right().value())))); } updatedGroupTypeProperties.add(addPropertyResult.left().value()); - + i++; } } - if(groupDefinition.getUniqueId() == null){ + if (groupDefinition.getUniqueId() == null) { String uid = UniqueIdBuilder.buildGroupingUid(component.getUniqueId(), groupDefinition.getName()); groupDefinition.setUniqueId(uid); } - groupDefinition.convertFromGroupProperties(updatedGroupTypeProperties); + groupDefinition.convertFromGroupProperties(updatedGroupTypeProperties); groupDefinition.setInvariantUUID(UniqueIdBuilder.buildInvariantUUID()); groupDefinition.setGroupUUID(UniqueIdBuilder.generateUUID()); groupDefinition.setVersion(INITIAL_VERSION); @@ -2450,9 +2100,7 @@ public class GroupBusinessLogic extends BaseBusinessLogic { return Either.left(groupDefinition); } - - - + public Either handleProperty(GroupProperty groupProperty, PropertyDefinition prop, Integer index, Map allDataTypes) { if (prop == null) { @@ -2471,7 +2119,6 @@ public class GroupBusinessLogic extends BaseBusinessLogic { String innerType = checkInnerType.left().value(); - log.debug("Before validateAndUpdatePropertyValue"); Either isValid = propertyOperation.validateAndUpdatePropertyValue(propertyType, value, innerType, allDataTypes); log.debug("After validateAndUpdatePropertyValue. isValid = {}", isValid); @@ -2490,24 +2137,19 @@ public class GroupBusinessLogic extends BaseBusinessLogic { } String uniqueId = UniqueIdBuilder.buildGroupPropertyValueUid((String) prop.getUniqueId(), index); - + groupProperty.setUniqueId(uniqueId); groupProperty.setValue(newValue); - groupProperty.setType(prop.getType()); + groupProperty.setType(prop.getType()); groupProperty.setDefaultValue(prop.getDefaultValue()); groupProperty.setDescription(prop.getDescription()); groupProperty.setSchema(prop.getSchema()); groupProperty.setPassword(prop.isPassword()); groupProperty.setParentUniqueId(prop.getUniqueId()); - log.debug("Before adding property value to graph {}", groupProperty); - return Either.left(groupProperty); } - - - - + } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java index 33390e7e98..1ff22dd17f 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ImportUtils.java @@ -33,7 +33,6 @@ import java.util.function.Function; import org.apache.commons.lang3.StringEscapeUtils; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.HeatParameterDefinition; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.LifecycleStateEnum; @@ -103,7 +102,7 @@ public final class ImportUtils { } public enum ResultStatusEnum { - ELEMENT_NOT_FOUND, GENERAL_ERROR, OK, INVALID_PROPERTY_DEFAULT_VALUE, INVALID_PROPERTY_TYPE, INVALID_PROPERTY_VALUE, MISSING_ENTRY_SCHEMA_TYPE + ELEMENT_NOT_FOUND, GENERAL_ERROR, OK, INVALID_PROPERTY_DEFAULT_VALUE, INVALID_PROPERTY_TYPE, INVALID_PROPERTY_VALUE, MISSING_ENTRY_SCHEMA_TYPE, INVALID_PROPERTY_NAME } public enum ToscaElementTypeEnum { @@ -346,9 +345,9 @@ public final class ImportUtils { return inputDef; } - public static AttributeDefinition createModuleAttribute(Map attributeMap) { + public static PropertyDefinition createModuleAttribute(Map attributeMap) { - AttributeDefinition attributeDef = new AttributeDefinition(); + PropertyDefinition attributeDef = new PropertyDefinition(); ImportUtils.setField(attributeMap, ToscaTagNamesEnum.TYPE, type -> attributeDef.setType(type)); ImportUtils.setField(attributeMap, ToscaTagNamesEnum.DESCRIPTION, desc -> attributeDef.setDescription(desc)); ImportUtils.setField(attributeMap, ToscaTagNamesEnum.STATUS, status -> attributeDef.setStatus(status)); @@ -374,7 +373,7 @@ public final class ImportUtils { } - private static void setAttributeFieldStatus(Map propertyValue, AttributeDefinition propertyDef) { + private static void setAttributeFieldStatus(Map propertyValue, PropertyDefinition propertyDef) { Either propertyFieldIsStatus = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.STATUS); if (propertyFieldIsStatus.isLeft()) { propertyDef.setStatus(propertyFieldIsStatus.left().value()); @@ -392,7 +391,7 @@ public final class ImportUtils { } - private static void setAttributeScheme(Map propertyValue, AttributeDefinition propertyDefinition) { + private static void setAttributeScheme(Map propertyValue, PropertyDefinition propertyDefinition) { Either eitherSchema = getSchema(propertyValue); if (eitherSchema.isLeft()) { SchemaDefinition schemaDef = new SchemaDefinition(); @@ -465,7 +464,7 @@ public final class ImportUtils { return ResultStatusEnum.OK; } - private static ResultStatusEnum setAttributeFieldDefaultValue(Map propertyValue, AttributeDefinition dataDefinition) { + private static ResultStatusEnum setAttributeFieldDefaultValue(Map propertyValue, PropertyDefinition dataDefinition) { Either propertyFieldDefaultValue = findToscaElement(propertyValue, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL); Gson gson = GsonFactory.getGson(); if (propertyFieldDefaultValue.isLeft()) { @@ -519,7 +518,7 @@ public final class ImportUtils { } } - private static void setAttributeFieldType(Map propertyValue, AttributeDefinition dataDefinition) { + private static void setAttributeFieldType(Map propertyValue, PropertyDefinition dataDefinition) { Either propertyFieldType = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.TYPE); if (propertyFieldType.isLeft()) { dataDefinition.setType(propertyFieldType.left().value()); @@ -533,7 +532,7 @@ public final class ImportUtils { } } - private static void setAttributeFieldDescription(Map propertyValue, AttributeDefinition dataDefinition) { + private static void setAttributeFieldDescription(Map propertyValue, PropertyDefinition dataDefinition) { Either propertyFieldDescription = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.DESCRIPTION); if (propertyFieldDescription.isLeft()) { dataDefinition.setDescription(propertyFieldDescription.left().value()); @@ -556,9 +555,9 @@ public final class ImportUtils { } - public static Either, ResultStatusEnum> getAttributes(Map toscaJson) { - Function elementGenByName = elementName -> createAttribute(elementName); - Function, AttributeDefinition> func = map -> createModuleAttribute(map); + public static Either, ResultStatusEnum> getAttributes(Map toscaJson) { + Function elementGenByName = elementName -> createAttribute(elementName); + Function, PropertyDefinition> func = map -> createModuleAttribute(map); return getElements(toscaJson, ToscaTagNamesEnum.ATTRIBUTES, elementGenByName, func); } @@ -595,8 +594,8 @@ public final class ImportUtils { } - private static AttributeDefinition createAttribute(String name) { - AttributeDefinition attribute = new AttributeDefinition(); + private static PropertyDefinition createAttribute(String name) { + PropertyDefinition attribute = new PropertyDefinition(); attribute.setName(name); return attribute; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java index 8ffee1fd34..a2809b44cf 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java @@ -50,6 +50,7 @@ import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; import org.openecomp.sdc.be.impl.ComponentsUtils; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.ComponentInstInputsMap; @@ -551,7 +552,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic { return result; } - Either>, StorageOperationStatus> addciInputsEither = toscaOperationFacade.addComponentInstanceInputsToComponent(inputsValueToCreateMap, component.getUniqueId()); + Either>, StorageOperationStatus> addciInputsEither = toscaOperationFacade.addComponentInstanceInputsToComponent(component, inputsValueToCreateMap); if(addciInputsEither.isRight()){ log.debug("Failed to add inputs values under component {}. Status is {}", component.getUniqueId(), assotiateInputsEither.right().value()); result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(assotiateInputsEither.right().value()))); @@ -621,6 +622,8 @@ public class InputsBusinessLogic extends BaseBusinessLogic { input.setImmutable(oldInput.isImmutable()); input.setDefinition(oldInput.isDefinition()); input.setRequired(oldInput.isRequired()); + input.setOwnerId(null); + input.setParentUniqueId(null); inputsToCreate.put(input.getName(), input); @@ -739,7 +742,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } if (resourceProperties != null) { Map generatedInputs = resourceProperties.stream().collect(Collectors.toMap(i -> i.getName(), i -> i)); - Either, String> mergeEither = PropertyDataDefinition.mergeProperties(generatedInputs, inputs, false); + Either, String> mergeEither = ToscaDataDefinition.mergeDataMaps(generatedInputs, inputs); if(mergeEither.isRight()){ return Either.right(componentsUtils.getResponseFormat(ActionStatus.PROPERTY_ALREADY_EXIST, mergeEither.right().value())); } @@ -808,6 +811,8 @@ public class InputsBusinessLogic extends BaseBusinessLogic { if (!optionalInput.isPresent()) { return Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUT_IS_NOT_CHILD_OF_COMPONENT, inputId, componentId)); } + + InputDefinition inputForDelete = optionalInput.get(); // Lock component Either lockResultEither = lockComponent(componentId, component, "deleteInput"); @@ -818,8 +823,6 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } // Delete input operations - - InputDefinition inputForDelete = optionalInput.get(); try { StorageOperationStatus status = toscaOperationFacade.deleteInputOfResource(component, inputForDelete.getName()); if(status != StorageOperationStatus.OK){ @@ -863,7 +866,9 @@ public class InputsBusinessLogic extends BaseBusinessLogic { resetInputName(mappedToscaTemplate, inputForDelete.getName()); - value = gson.toJson(mappedToscaTemplate); + value = ""; + if(!mappedToscaTemplate.isEmpty()) + value = gson.toJson(mappedToscaTemplate); propertyValue.setValue(value); String compInstId = propertyValue.getComponentInstanceId(); propertyValue.setRules(null); @@ -1159,6 +1164,8 @@ public class InputsBusinessLogic extends BaseBusinessLogic { if (properties != null && !properties.isEmpty()) { for (ComponentInstancePropInput propInput : properties) { + propInput.setOwnerId(null); + propInput.setParentUniqueId(null); Either createInputRes = createInputForComponentInstance(component, origComponent,ci, inputsToCreate, propertiesToCreate, dataTypes, inputName, propInput); if (createInputRes.isRight()) { @@ -1260,6 +1267,10 @@ public class InputsBusinessLogic extends BaseBusinessLogic { inputsToCreate.put(input.getName(), input); + List propertiesList = new ArrayList<>(); // adding the property with the new value for UI + propertiesList.add(prop); + input.setProperties(propertiesList); + return Either.left(input); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java index ffcb87c99c..587be4d169 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java @@ -74,7 +74,6 @@ import org.openecomp.sdc.be.impl.WebAppContextWrapper; import org.openecomp.sdc.be.info.ArtifactTemplateInfo; import org.openecomp.sdc.be.info.MergedArtifactInfo; import org.openecomp.sdc.be.model.ArtifactDefinition; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.CapabilityTypeDefinition; import org.openecomp.sdc.be.model.Component; @@ -542,8 +541,15 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { try { Either, ResponseFormat> prepareForUpdate = null; Resource preparedResource = null; - - Either>>, ResponseFormat> findNodeTypesArtifactsToHandleRes = findNodeTypesArtifactsToHandle(csar.left().value(), csarUUID, yamlFileName, oldRresource, user, true); + Either uploadComponentInstanceInfoMap = parseResourceInfoFromYaml(yamlFileName, newRresource, toscaYamlCsarStatus.left().value().getValue(), user); + if (uploadComponentInstanceInfoMap.isRight()) { + ResponseFormat responseFormat = uploadComponentInstanceInfoMap.right().value(); + componentsUtils.auditResource(responseFormat, user, newRresource, "", "", updateResource, null); + result = Either.right(responseFormat); + return result; + } + Map instances = uploadComponentInstanceInfoMap.left().value().getInstances(); + Either>>, ResponseFormat> findNodeTypesArtifactsToHandleRes = findNodeTypesArtifactsToHandle(csar.left().value(), csarUUID, yamlFileName, oldRresource, user, true, instances); if (findNodeTypesArtifactsToHandleRes.isRight()) { log.debug("failed to find node types for update with artifacts during import csar {}. ", csarUUID); result = Either.right(findNodeTypesArtifactsToHandleRes.right().value()); @@ -571,14 +577,6 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { return result; } - Either uploadComponentInstanceInfoMap = parseResourceInfoFromYaml(yamlFileName, preparedResource, yamlFileContents, user); - if (uploadComponentInstanceInfoMap.isRight()) { - ResponseFormat responseFormat = uploadComponentInstanceInfoMap.right().value(); - componentsUtils.auditResource(responseFormat, user, preparedResource, "", "", updateResource, null); - result = Either.right(responseFormat); - return result; - } - Map inputs = uploadComponentInstanceInfoMap.left().value().getInputs(); Either createInputsOnResource = createInputsOnResource(preparedResource, user, inputs, true); if (createInputsOnResource.isRight()) { @@ -590,7 +588,6 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { } preparedResource = createInputsOnResource.left().value(); - Map instances = uploadComponentInstanceInfoMap.left().value().getInstances(); Either createResourcesInstancesEither = createResourceInstances(user, yamlFileName, preparedResource, instances, true, false, parseNodeTypeInfoYamlEither.left().value()); if (createResourcesInstancesEither.isRight()) { log.debug("failed to create resource instances status is {}", createResourcesInstancesEither.right().value()); @@ -677,7 +674,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { } private Either>>, ResponseFormat> findNodeTypesArtifactsToHandle(Map csar, String csarUUID, String yamlFileName, Resource oldResource, User user, - boolean inTransaction) { + boolean inTransaction, Map uploadComponentInstanceInfoMap) { Map> extractedVfcsArtifacts = CsarUtils.extractVfcsArtifactsFromCsar(csar); Map>> nodeTypesArtifactsToHandle = new HashMap<>(); @@ -685,7 +682,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { try { nodeTypesArtifactsToHandleRes = Either.left(nodeTypesArtifactsToHandle); - List>, String>> extractedVfcToscaNames = extractVfcToscaNames(csar, yamlFileName, oldResource.getSystemName()); + List>, String>> extractedVfcToscaNames = extractVfcToscaNames(csar, yamlFileName, oldResource.getSystemName(), uploadComponentInstanceInfoMap); validateNodeTypeIdentifiers(extractedVfcsArtifacts, extractedVfcToscaNames); Either>, ResponseFormat> curNodeTypeArtifactsToHandleRes = null; EnumMap> curNodeTypeArtifactsToHandle = null; @@ -913,7 +910,8 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { return handleNodeTypeArtifactsRes; } - private List>, String>> extractVfcToscaNames(Map csar, String yamlFileName, String vfResourceName) { + @SuppressWarnings("unchecked") + private List>, String>> extractVfcToscaNames(Map csar, String yamlFileName, String vfResourceName, Map uploadComponentInstanceInfoMap) { List>, String>> vfcToscaNames = new ArrayList<>(); Map nodeTypes; if (csar != null) { @@ -921,12 +919,20 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { putNodeTypesFromYaml(csar, yamlFileName, nodeTypes); putNodeTypesFromYaml(csar, Constants.GLOBAL_SUBSTITUTION_TYPES_SERVICE_TEMPLATE, nodeTypes); putNodeTypesFromYaml(csar, Constants.ABSTRACT_SUBSTITUTE_GLOBAL_TYPES_SERVICE_TEMPLATE, nodeTypes); - + Map nestedServiceTemplatesMap = new HashMap<>(); + for(UploadComponentInstanceInfo ci : uploadComponentInstanceInfoMap.values()){ + if(ci.getProperties() != null && ci.getProperties().containsKey("service_template_filter")){ + String tempName = CsarUtils.DEFINITIONS_PATH + ((Map)ci.getProperties().get("service_template_filter").get(0).getValue()).get("substitute_service_template"); + putNodeTypesFromYaml(csar,tempName, nodeTypes); + nestedServiceTemplatesMap.put(ci.getType(), tempName); + } + } + if (!nodeTypes.isEmpty()) { Iterator> nodesNameEntry = nodeTypes.entrySet().iterator(); while (nodesNameEntry.hasNext()) { Entry nodeType = nodesNameEntry.next(); - addVfcToscaNameFindSubstitutes(csar, vfResourceName, vfcToscaNames, nodeType.getKey()); + addVfcToscaNameFindSubstitutes(csar, vfResourceName, vfcToscaNames, nodeType.getKey(), nestedServiceTemplatesMap); } } } @@ -947,20 +953,23 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { } } - private void addVfcToscaNameFindSubstitutes(Map csar, String vfResourceName, List>, String>> vfcToscaNames, String nodeTypeFullName) { + private void addVfcToscaNameFindSubstitutes(Map csar, String vfResourceName, List>, String>> vfcToscaNames, String nodeTypeFullName, Map nestedServiceTemplatesMap) { String toscaResourceName = buildNestedVfcToscaResourceName(vfResourceName, nodeTypeFullName); - String nodeTypeTemplateYamlName = buildNestedSubstituteYamlName(nodeTypeFullName); + String nodeTypeTemplateYamlName =null; + if(nestedServiceTemplatesMap.containsKey(nodeTypeFullName)){ + nodeTypeTemplateYamlName = nestedServiceTemplatesMap.get(nodeTypeFullName); + } List relatedVfcsToscaNameSpaces = new ArrayList<>(); relatedVfcsToscaNameSpaces.add(buildNestedVfcToscaNamespace(nodeTypeFullName)); - if (csar.containsKey(nodeTypeTemplateYamlName)) { - addSubstituteToscaNamespacesRecursively(csar, nodeTypeTemplateYamlName, relatedVfcsToscaNameSpaces); + if (nodeTypeTemplateYamlName!=null && csar.containsKey(nodeTypeTemplateYamlName)) { + addSubstituteToscaNamespacesRecursively(csar, nodeTypeTemplateYamlName, relatedVfcsToscaNameSpaces, nestedServiceTemplatesMap); } ImmutablePair> toscaNameSpacesHierarchy = new ImmutablePair<>(nodeTypeFullName, relatedVfcsToscaNameSpaces); vfcToscaNames.add(new ImmutablePair<>(toscaNameSpacesHierarchy, toscaResourceName)); } - private void addSubstituteToscaNamespacesRecursively(Map csar, String yamlFileName, List toscaNameSpaces) { + private void addSubstituteToscaNamespacesRecursively(Map csar, String yamlFileName, List toscaNameSpaces, Map nestedServiceTemplatesMap) { Map nodeTypes = new HashMap<>(); @@ -978,10 +987,13 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { } toscaNameSpaces.add(toscaNameSpace); - String nodeTypeTemplateYamlName = buildNestedSubstituteYamlName(nodeTypeFullName); + String nodeTypeTemplateYamlName =null; + if(nestedServiceTemplatesMap.containsKey(nodeTypeFullName)){ + nodeTypeTemplateYamlName = nestedServiceTemplatesMap.get(nodeTypeFullName); + } - if (csar.containsKey(nodeTypeTemplateYamlName)) { - addSubstituteToscaNamespacesRecursively(csar, nodeTypeTemplateYamlName, toscaNameSpaces); + if (nodeTypeTemplateYamlName!=null && csar.containsKey(nodeTypeTemplateYamlName)) { + addSubstituteToscaNamespacesRecursively(csar, nodeTypeTemplateYamlName, toscaNameSpaces, nestedServiceTemplatesMap); } } } @@ -1651,7 +1663,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { Either result; Either createResourcesInstancesEither; - Map>> nodeTypesArtifactsToCreate = findNodeTypeArtifactsToCreate(csar, yamlName, resource); + Map>> nodeTypesArtifactsToCreate = findNodeTypeArtifactsToCreate(csar, yamlName, resource, uploadComponentInstanceInfoMap); log.debug("************* Going to create all nodes {}", yamlName); Either, ResponseFormat> createdResourcesFromdNodeTypeMap = this.handleNodeTypes(yamlName, resource, user, topologyTemplateYaml, csar, false, nodeTypesArtifactsToCreate, nodeTypesNewCreatedArtifacts); @@ -1694,10 +1706,10 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { return result; } - private Map>> findNodeTypeArtifactsToCreate(Map csar, String yamlName, Resource resource) { + private Map>> findNodeTypeArtifactsToCreate(Map csar, String yamlName, Resource resource, Map uploadComponentInstanceInfoMap) { Map> extractedVfcsArtifacts = CsarUtils.extractVfcsArtifactsFromCsar(csar); - List>, String>> extractedVfcToscaNames = extractVfcToscaNames(csar, yamlName, resource.getSystemName()); + List>, String>> extractedVfcToscaNames = extractVfcToscaNames(csar, yamlName, resource.getSystemName(), uploadComponentInstanceInfoMap); validateNodeTypeIdentifiers(extractedVfcsArtifacts, extractedVfcToscaNames); Map>> nodeTypesArtifactsToHandle = null; if (!extractedVfcsArtifacts.isEmpty() && !extractedVfcToscaNames.isEmpty()) { @@ -3429,7 +3441,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { Map>> instCapabilties = new HashMap<>(); Map>> instRequirements = new HashMap<>(); Map> instArtifacts = new HashMap<>(); - Map> instAttributes = new HashMap<>(); + Map> instAttributes = new HashMap<>(); Map originCompMap = new HashMap<>(); List relations = new ArrayList<>(); @@ -4321,7 +4333,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { List getInputList = (List) getInput; getInputInfo.setPropName(propName); getInputInfo.setInputName((String) getInputList.get(0)); - if (getInputList.size() >= 1) { + if (getInputList.size() > 1) { Object indexObj = getInputList.get(1); if (indexObj instanceof Integer) { getInputInfo.setIndexValue((Integer) indexObj); @@ -5838,7 +5850,7 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { return Either.left(true); } - // Tal G for extending inheritance US815447 + // for extending inheritance US815447 private Either validateDerivedFromExtending(User user, Resource currentResource, Resource updateInfoResource, AuditingActionEnum actionEnum) { // If updated resource is not deriving, should fail validation /* @@ -6633,12 +6645,6 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { return toscaResourceName; } - private String buildNestedSubstituteYamlName(String nodeTypeFullName) { - String[] nodeTypeFullNameParsed = nodeTypeFullName.split("\\."); - String nodeTypeActualName = nodeTypeFullNameParsed[nodeTypeFullNameParsed.length - 1]; - return CsarUtils.DEFINITIONS_PATH + nodeTypeActualName + Constants.SERVICE_TEMPLATE_FILE_POSTFIX; - } - public ICacheMangerOperation getCacheManagerOperation() { return cacheManagerOperation; } @@ -6726,6 +6732,11 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { Either resourceResultEither = toscaOperationFacade.getToscaElement(resourceId, paramsToRetuen); if (resourceResultEither.isRight()) { + if(resourceResultEither.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + log.debug("Failed to found resource with id {} ", resourceId); + Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceId)); + } + log.debug("failed to get resource by id {} with filters {}", resourceId, dataParamsToReturn.toString()); return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(resourceResultEither.right().value()), "")); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java index f35515f8fe..b157b635b4 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceImportManager.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.function.Function; +import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.servlet.ServletContext; @@ -46,12 +47,12 @@ import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; import org.openecomp.sdc.be.impl.ComponentsUtils; import org.openecomp.sdc.be.impl.WebAppContextWrapper; import org.openecomp.sdc.be.model.ArtifactDefinition; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.InterfaceDefinition; @@ -101,7 +102,9 @@ public class ResourceImportManager { @Autowired protected ResourceOperation resourceOperation; - + + public final static Pattern PROPERTY_NAME_PATTERN_IGNORE_LENGTH = Pattern + .compile("[\\w\\-\\_\\d\\:]+"); @Autowired protected CapabilityTypeOperation capabilityTypeOperation; @Autowired @@ -289,7 +292,9 @@ public class ResourceImportManager { eitherResult = setCapabilities(toscaJson, resource, parentResource); if (eitherResult.isRight()) return eitherResult; - setProperties(toscaJson, resource); + eitherResult = setProperties(toscaJson, resource); + if (eitherResult.isRight()) + return eitherResult; eitherResult = setRequirements(toscaJson, resource, parentResource); if (eitherResult.isRight()) return eitherResult; @@ -467,10 +472,10 @@ public class ResourceImportManager { return result; } - private ResultStatusEnum setProperties(Map toscaJson, Resource resource) { + private Either setProperties(Map toscaJson, Resource resource) { Map reducedToscaJson = new HashMap<>(toscaJson); ImportUtils.removeElementFromJsonMap(reducedToscaJson, "capabilities"); - ResultStatusEnum result = ResultStatusEnum.OK; + Either result = Either.left(true); Either, ResultStatusEnum> properties = ImportUtils.getProperties(reducedToscaJson); if (properties.isLeft()) { List propertiesList = new ArrayList<>(); @@ -478,28 +483,32 @@ public class ResourceImportManager { if (value != null) { for (Entry entry : value.entrySet()) { String name = entry.getKey(); + if(!PROPERTY_NAME_PATTERN_IGNORE_LENGTH.matcher(name).matches()){ + log.debug("The property with invalid name {} occured upon import resource {}. ", name, resource.getName()); + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromResultStatusEnum(ResultStatusEnum.INVALID_PROPERTY_NAME, JsonPresentationFields.PROPERTY))); + } PropertyDefinition propertyDefinition = entry.getValue(); propertyDefinition.setName(name); propertiesList.add(propertyDefinition); } } resource.setProperties(propertiesList); - } else { - result = properties.right().value(); + } else if(properties.right().value() != ResultStatusEnum.ELEMENT_NOT_FOUND){ + result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromResultStatusEnum(properties.right().value(), JsonPresentationFields.PROPERTY))); } return result; } private ResultStatusEnum setAttributes(Map toscaJson, Resource resource) { ResultStatusEnum result = ResultStatusEnum.OK; - Either, ResultStatusEnum> attributes = ImportUtils.getAttributes(toscaJson); + Either, ResultStatusEnum> attributes = ImportUtils.getAttributes(toscaJson); if (attributes.isLeft()) { - List attributeList = new ArrayList<>(); - Map value = attributes.left().value(); + List attributeList = new ArrayList<>(); + Map value = attributes.left().value(); if (value != null) { - for (Entry entry : value.entrySet()) { + for (Entry entry : value.entrySet()) { String name = entry.getKey(); - AttributeDefinition attributeDef = entry.getValue(); + PropertyDefinition attributeDef = entry.getValue(); attributeDef.setName(name); attributeList.add(attributeDef); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java index 1f481a7b5a..bc1c6e5910 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java @@ -1390,7 +1390,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { } Collections.sort(vfModulePayloadForCurrVF, (art1, art2) -> VfModuleArtifactPayload.compareByGroupName(art1, art2)); // Update Payload With Heat Env - vfModulePayloadForCurrVF.stream().forEach(e -> addHeatEnvArtifactsToVFModulePayload(e, currVFInstance)); +// vfModulePayloadForCurrVF.stream().forEach(e -> addHeatEnvArtifactsToVFModulePayload(e, currVFInstance)); final Gson gson = new GsonBuilder().setPrettyPrinting().create(); @@ -1436,7 +1436,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { vfModuleAertifact = getVfModuleInstArtifactForCompInstance(currVFInstance, service, modifier, groupsForCurrVF, payloadWrapper, responseWrapper); } if (responseWrapper.isEmpty() && vfModuleAertifact != null) { - vfModuleAertifact = fillVfModulePayload(modifier, currVFInstance, vfModuleAertifact, shouldLock, payloadWrapper, responseWrapper); + vfModuleAertifact = fillVfModulePayload(modifier, currVFInstance, vfModuleAertifact, shouldLock, payloadWrapper, responseWrapper, service); } Either result; @@ -1449,21 +1449,21 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { return result; } - private ArtifactDefinition fillVfModulePayload(User modifier, ComponentInstance currVF, ArtifactDefinition vfModuleArtifact, boolean shouldLock, Wrapper payloadWrapper, Wrapper responseWrapper) { + private ArtifactDefinition fillVfModulePayload(User modifier, ComponentInstance currVF, ArtifactDefinition vfModuleArtifact, boolean shouldLock, Wrapper payloadWrapper, Wrapper responseWrapper, Service service) { ArtifactDefinition result = null; - final Either eitherResource = toscaOperationFacade.getToscaElement(currVF.getComponentUid()); - if (eitherResource.isRight()) { - responseWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(eitherResource.right().value()))); - } else if (!payloadWrapper.isEmpty()) { - Resource resource = eitherResource.left().value(); - Either eitherPayload = artifactsBusinessLogic.generateArtifactPayload(vfModuleArtifact, resource.getComponentType(), resource, currVF.getName(), modifier, shouldLock, () -> System.currentTimeMillis(), +// final Either eitherResource = toscaOperationFacade.getToscaElement(currVF.getComponentUid()); +// if (eitherResource.isRight()) { +// responseWrapper.setInnerElement(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(eitherResource.right().value()))); +// } else if (!payloadWrapper.isEmpty()) { +// Resource resource = eitherResource.left().value(); + Either eitherPayload = artifactsBusinessLogic.generateArtifactPayload(vfModuleArtifact, ComponentTypeEnum.RESOURCE_INSTANCE, service, currVF.getName(), modifier, shouldLock, () -> System.currentTimeMillis(), () -> Either.left(artifactsBusinessLogic.createEsArtifactData(vfModuleArtifact, payloadWrapper.getInnerElement().getBytes(StandardCharsets.UTF_8))), currVF.getUniqueId()); if (eitherPayload.isLeft()) { result = eitherPayload.left().value(); } else { responseWrapper.setInnerElement(eitherPayload.right().value()); } - } +// } if (result == null) { result = vfModuleArtifact; } @@ -1962,13 +1962,18 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { return result; } - public Either getUiComponentDataTransferByComponentId(String resourceId, List dataParamsToReturn) { + public Either getUiComponentDataTransferByComponentId(String serviceId, List dataParamsToReturn) { ComponentParametersView paramsToRetuen = new ComponentParametersView(dataParamsToReturn); - Either serviceResultEither = toscaOperationFacade.getToscaElement(resourceId, paramsToRetuen); + Either serviceResultEither = toscaOperationFacade.getToscaElement(serviceId, paramsToRetuen); if (serviceResultEither.isRight()) { - log.debug("failed to get resource by id {} with filters {}", resourceId, dataParamsToReturn.toString()); + if(serviceResultEither.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + log.debug("Failed to found service with id {} ", serviceId); + Either.right(componentsUtils.getResponseFormat(ActionStatus.SERVICE_NOT_FOUND, serviceId)); + } + + log.debug("failed to get service by id {} with filters {}", serviceId, dataParamsToReturn.toString()); return Either.right(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(serviceResultEither.right().value()), "")); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java index d6cbd3663c..14f54e4c19 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java @@ -21,7 +21,10 @@ package org.openecomp.sdc.be.components.lifecycle; import java.util.Arrays; +import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; import org.openecomp.sdc.be.config.BeEcompErrorManager; @@ -29,16 +32,22 @@ import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.jsongraph.TitanDao; import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum; import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum; +import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.MapPropertiesDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; +import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.impl.ComponentsUtils; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; import org.openecomp.sdc.be.model.LifecycleStateEnum; import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.jsontitan.datamodel.TopologyTemplate; import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElement; +import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElementTypeEnum; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaElementLifecycleOperation; +import org.openecomp.sdc.be.model.jsontitan.operations.ToscaElementOperation; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; @@ -97,6 +106,7 @@ public class CheckoutTransition extends LifeCycleTransition { ResponseFormat responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType); result = Either.right(responseFormat); } else { + Component clonedComponent = ModelConverter.convertFromToscaElement(checkoutResourceResult.left().value()); result = Either.left(clonedComponent); Either upgradeToLatestGeneric = componentBl.shouldUpgradeToLatestGeneric(clonedComponent); @@ -132,7 +142,7 @@ public class CheckoutTransition extends LifeCycleTransition { private StorageOperationStatus upgradeToLatestGenericData(Component clonedComponent) { - StorageOperationStatus updateStatus = null; + StorageOperationStatus updateStatus = StorageOperationStatus.OK; Either updateEither = toscaOperationFacade.updateToscaElement(clonedComponent); if (updateEither.isRight()) updateStatus = updateEither.right().value(); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/UiComponentDataConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/UiComponentDataConverter.java index 46505b843e..6edfe81fee 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/UiComponentDataConverter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/UiComponentDataConverter.java @@ -11,6 +11,7 @@ import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.Service; import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer; +import org.openecomp.sdc.be.ui.model.UiComponentMetadata; import org.openecomp.sdc.be.ui.model.UiResourceDataTransfer; import org.openecomp.sdc.be.ui.model.UiResourceMetadata; import org.openecomp.sdc.be.ui.model.UiServiceDataTransfer; @@ -215,4 +216,20 @@ public class UiComponentDataConverter { return dataTransfer; } + + public static UiComponentMetadata convertToUiComponentMetadata(Component component) { + + UiComponentMetadata uiComponentMetadata = null; + switch (component.getComponentType()) { + case RESOURCE: + Resource resource = (Resource)component; + uiComponentMetadata = new UiResourceMetadata(component.getCategories(), resource.getDerivedFrom(), (ResourceMetadataDataDefinition) resource.getComponentMetadataDefinition().getMetadataDataDefinition()); + break; + case SERVICE: + uiComponentMetadata = new UiServiceMetadata(component.getCategories(), (ServiceMetadataDataDefinition) component.getComponentMetadataDefinition().getMetadataDataDefinition()); + default: + + } + return uiComponentMetadata; + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/EcompIntImpl.java b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/EcompIntImpl.java index 7b49d3fcea..c88ec87d58 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/EcompIntImpl.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/EcompIntImpl.java @@ -26,7 +26,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import org.openecomp.portalsdk.core.onboarding.crossapi.IPortalRestAPIService; -import org.openecomp.portalsdk.core.onboarding.crossapi.PortalAPIException; +import org.openecomp.portalsdk.core.onboarding.exception.PortalAPIException; import org.openecomp.portalsdk.core.restful.domain.EcompRole; import org.openecomp.portalsdk.core.restful.domain.EcompUser; import org.openecomp.sdc.be.config.BeEcompErrorManager; @@ -37,6 +37,7 @@ import org.openecomp.sdc.be.ecomp.converters.EcompUserConverter; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.user.Role; import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.api.Constants; import org.openecomp.sdc.exception.ResponseFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -378,4 +379,28 @@ public class EcompIntImpl implements IPortalRestAPIService { UserBusinessLogic userBusinessLogic = (UserBusinessLogic) ctx.getBean("userBusinessLogic"); return userBusinessLogic; } + + /** + * Gets and returns the userId for the logged-in user based on the request. + * If any error occurs, the method should throw PortalApiException with an + * appropriate message. The FW library will catch the exception and send an + * appropriate response to Portal. + * + * As a guideline for AT&T specific implementation, see the sample apps + * repository + * https://codecloud.web.att.com/projects/EP_SDK/repos/ecomp_portal_sdk_third_party/ + * for a sample implementation for on-boarded applications using EPSDK-FW. + * However, the app can always choose to have a custom implementation of + * this method. For Open-source implementation, for example, the app will + * have a totally different implementation for this method. + * + * @param request + * @return true if the request contains appropriate credentials, else false. + * @throws PortalAPIException + * If an unexpected error occurs while processing the request. + */ + @Override + public String getUserId(HttpServletRequest request) throws PortalAPIException { + return request.getHeader(Constants.USER_ID_HEADER); + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetMetadataConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/converters/AssetMetadataConverter.java similarity index 99% rename from catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetMetadataConverter.java rename to catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/converters/AssetMetadataConverter.java index 2c7de7032c..2e94dfc554 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetMetadataConverter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/ecomp/converters/AssetMetadataConverter.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.openecomp.sdc.be.externalapi.servlet; +package org.openecomp.sdc.be.ecomp.converters; import java.util.Collection; import java.util.HashMap; @@ -47,7 +47,6 @@ import org.openecomp.sdc.be.model.Service; import org.openecomp.sdc.be.model.category.CategoryDefinition; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; -import org.openecomp.sdc.be.model.operations.impl.ResourceOperation; import org.openecomp.sdc.exception.ResponseFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServlet.java index 552ad163ec..b0947c67f9 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServlet.java @@ -68,6 +68,7 @@ import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter; import org.openecomp.sdc.be.externalapi.servlet.representation.AssetMetadata; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java index ea2582cd1b..a6415dc9b9 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java @@ -37,12 +37,14 @@ import org.codehaus.jackson.map.JsonDeserializer; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.module.SimpleModule; import org.openecomp.sdc.be.auditing.api.IAuditingManager; +import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; import org.openecomp.sdc.be.components.impl.ResponseFormatManager; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.graph.datatype.AdditionalInformationEnum; import org.openecomp.sdc.be.datatypes.elements.AdditionalInfoParameterInfo; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.ArtifactDefinition; import org.openecomp.sdc.be.model.CapabilityTypeDefinition; @@ -1254,6 +1256,31 @@ public class ComponentsUtils { log.debug("convert storage response {} to action response {}", storageResponse.name(), responseEnum.name()); return responseEnum; } + + public ActionStatus convertFromResultStatusEnum(ResultStatusEnum resultStatus, JsonPresentationFields elementType) { + ActionStatus responseEnum = ActionStatus.GENERAL_ERROR; + switch (resultStatus) { + case OK: + responseEnum = ActionStatus.OK; + break; + case ELEMENT_NOT_FOUND: + if(elementType!= null && elementType == JsonPresentationFields.PROPERTY){ + responseEnum = ActionStatus.PROPERTY_NOT_FOUND; + } + break; + case INVALID_PROPERTY_DEFAULT_VALUE: + case INVALID_PROPERTY_TYPE: + case INVALID_PROPERTY_VALUE: + case INVALID_PROPERTY_NAME: + case MISSING_ENTRY_SCHEMA_TYPE: + responseEnum = ActionStatus.INVALID_PROPERTY; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + return responseEnum; + } public ResponseFormat getResponseFormatAdditionalProperty(ActionStatus actionStatus, AdditionalInfoParameterInfo additionalInfoParameterInfo, NodeTypeEnum nodeType, AdditionalInformationEnum labelOrValue) { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/listen/BEAppContextListener.java b/catalog-be/src/main/java/org/openecomp/sdc/be/listen/BEAppContextListener.java index 38629ab7a1..436b2319e9 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/listen/BEAppContextListener.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/listen/BEAppContextListener.java @@ -29,11 +29,7 @@ import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import org.openecomp.portalsdk.core.onboarding.ueb.UebException; -import org.openecomp.portalsdk.core.onboarding.ueb.UebManager; -import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.config.ConfigurationManager; -import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; import org.openecomp.sdc.be.impl.DownloadArtifactLogic; import org.openecomp.sdc.be.impl.WebAppContextWrapper; import org.openecomp.sdc.be.model.operations.api.IResourceOperation; @@ -49,9 +45,7 @@ public class BEAppContextListener extends AppContextListener implements ServletC private static final String MANIFEST_FILE_NAME = "/META-INF/MANIFEST.MF"; private static Logger log = LoggerFactory.getLogger(BEAppContextListener.class.getName()); - - private static UebManager uebManager = null; - + public void contextInitialized(ServletContextEvent context) { super.contextInitialized(context); @@ -73,34 +67,10 @@ public class BEAppContextListener extends AppContextListener implements ServletC BeMonitoringService bms = new BeMonitoringService(context.getServletContext()); bms.start(configurationManager.getConfiguration().getSystemMonitoring().getProbeIntervalInSeconds(15)); - initUebManager(); - log.debug("After executing {}", this.getClass()); } - - private void initUebManager() { - try { - if (uebManager == null) { - uebManager = UebManager.getInstance(); - uebManager.initListener(null); - } - } catch (UebException ex) { - log.debug("Failed to initialize UebManager", ex); - BeEcompErrorManager.getInstance().logInternalConnectionError("InitUebManager", "Failed to initialize listener of UebManager", ErrorSeverity.ERROR); - } - log.debug("After init listener of UebManager"); - } - - public void contextDestroyed(ServletContextEvent context) { - if (uebManager != null) { - uebManager.shutdown(); - uebManager = null; - } - super.contextDestroyed(context); - - } - + private IResourceOperation getResourceOperationManager(Class clazz, WebApplicationContext webContext) { return webContext.getBean(clazz); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AbstractValidationsServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AbstractValidationsServlet.java index d8f834c970..6b16e71e82 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AbstractValidationsServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AbstractValidationsServlet.java @@ -278,7 +278,7 @@ public abstract class AbstractValidationsServlet extends BeGenericServlet { } else { if (!resourceAuthorityEnum.isBackEndImport()) { isValid = resourceInfoObject.getPayloadName() != null && !resourceInfoObject.getPayloadName().isEmpty(); - //Tal only resource name is checked + //only resource name is checked } else { isValid = true; } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AttributeServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AttributeServlet.java index c7bc481119..0c5961daeb 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AttributeServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/AttributeServlet.java @@ -38,7 +38,7 @@ import javax.ws.rs.core.Response; import org.openecomp.sdc.be.components.impl.AttributeBusinessLogic; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; -import org.openecomp.sdc.be.model.AttributeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.common.api.Constants; import org.openecomp.sdc.common.datastructure.Wrapper; @@ -96,13 +96,13 @@ public class AttributeServlet extends AbstractValidationsServlet { try { Wrapper errorWrapper = new Wrapper<>(); - Wrapper attributesWrapper = new Wrapper<>(); + Wrapper attributesWrapper = new Wrapper<>(); // convert json to AttributeDefinition buildAttributeFromString(data, attributesWrapper, errorWrapper); if (errorWrapper.isEmpty()) { AttributeBusinessLogic businessLogic = getClassFromWebAppContext(context, () -> AttributeBusinessLogic.class); - Either createAttribute = businessLogic.createAttribute(resourceId, attributesWrapper.getInnerElement(), userId); + Either createAttribute = businessLogic.createAttribute(resourceId, attributesWrapper.getInnerElement(), userId); if (createAttribute.isRight()) { errorWrapper.setInnerElement(createAttribute.right().value()); } else { @@ -115,7 +115,7 @@ public class AttributeServlet extends AbstractValidationsServlet { log.info("Failed to create Attribute. Reason - ", errorWrapper.getInnerElement()); response = buildErrorResponse(errorWrapper.getInnerElement()); } else { - AttributeDefinition createdAttDef = attributesWrapper.getInnerElement(); + PropertyDefinition createdAttDef = attributesWrapper.getInnerElement(); log.debug("Attribute {} created successfully with id {}", createdAttDef.getName(), createdAttDef.getUniqueId()); ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.CREATED); response = buildOkResponse(responseFormat, RepresentationUtils.toRepresentation(createdAttDef)); @@ -165,14 +165,14 @@ public class AttributeServlet extends AbstractValidationsServlet { try { // convert json to PropertyDefinition Wrapper errorWrapper = new Wrapper<>(); - Wrapper attributesWrapper = new Wrapper<>(); + Wrapper attributesWrapper = new Wrapper<>(); // convert json to AttributeDefinition buildAttributeFromString(data, attributesWrapper, errorWrapper); if (errorWrapper.isEmpty()) { AttributeBusinessLogic businessLogic = getClassFromWebAppContext(context, () -> AttributeBusinessLogic.class); - Either eitherUpdateAttribute = businessLogic.updateAttribute(resourceId, attributeId, attributesWrapper.getInnerElement(), userId); + Either eitherUpdateAttribute = businessLogic.updateAttribute(resourceId, attributeId, attributesWrapper.getInnerElement(), userId); // update property if (eitherUpdateAttribute.isRight()) { errorWrapper.setInnerElement(eitherUpdateAttribute.right().value()); @@ -186,7 +186,7 @@ public class AttributeServlet extends AbstractValidationsServlet { log.info("Failed to update Attribute. Reason - ", errorWrapper.getInnerElement()); response = buildErrorResponse(errorWrapper.getInnerElement()); } else { - AttributeDefinition updatedAttribute = attributesWrapper.getInnerElement(); + PropertyDefinition updatedAttribute = attributesWrapper.getInnerElement(); log.debug("Attribute id {} updated successfully ", updatedAttribute.getUniqueId()); ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK); response = buildOkResponse(responseFormat, RepresentationUtils.toRepresentation(updatedAttribute)); @@ -232,12 +232,12 @@ public class AttributeServlet extends AbstractValidationsServlet { // delete the property AttributeBusinessLogic businessLogic = getClassFromWebAppContext(context, () -> AttributeBusinessLogic.class); - Either eitherAttribute = businessLogic.deleteAttribute(resourceId, attributeId, userId); + Either eitherAttribute = businessLogic.deleteAttribute(resourceId, attributeId, userId); if (eitherAttribute.isRight()) { log.debug("Failed to delete Attribute. Reason - ", eitherAttribute.right().value()); return buildErrorResponse(eitherAttribute.right().value()); } - AttributeDefinition attributeDefinition = eitherAttribute.left().value(); + PropertyDefinition attributeDefinition = eitherAttribute.left().value(); String name = attributeDefinition.getName(); log.debug("Attribute {} deleted successfully with id {}", name, attributeDefinition.getUniqueId()); @@ -253,11 +253,11 @@ public class AttributeServlet extends AbstractValidationsServlet { } } - private void buildAttributeFromString(String data, Wrapper attributesWrapper, Wrapper errorWrapper) { + private void buildAttributeFromString(String data, Wrapper attributesWrapper, Wrapper errorWrapper) { try { Gson gson = new GsonBuilder().setPrettyPrinting().create(); - final AttributeDefinition attribute = gson.fromJson(data, AttributeDefinition.class); + final PropertyDefinition attribute = gson.fromJson(data, PropertyDefinition.class); if (attribute == null) { log.info("Attribute content is invalid - {}", data); ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java index 2d5402f709..4278378bbc 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java @@ -49,7 +49,7 @@ import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.api.IElementDAO; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; -import org.openecomp.sdc.be.externalapi.servlet.AssetMetadataConverter; +import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter; import org.openecomp.sdc.be.impl.ComponentsUtils; import org.openecomp.sdc.be.impl.WebAppContextWrapper; import org.openecomp.sdc.be.model.User; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java index 6a7ecbb5fe..e509078c5c 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInstanceServlet.java @@ -51,7 +51,6 @@ import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.info.CreateAndAssotiateInfo; import org.openecomp.sdc.be.info.GroupDefinitionInfo; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; import org.openecomp.sdc.be.model.ComponentInstanceInput; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.InputDefinition; @@ -191,7 +190,6 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet { } - // TODO Tal New Multiple Instance API @POST @Path("/{containerComponentType}/{componentId}/resourceInstance/multipleComponentInstance") @Consumes(MediaType.APPLICATION_JSON) @@ -618,13 +616,13 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet { Wrapper errorWrapper = new Wrapper<>(); Wrapper dataWrapper = new Wrapper<>(); - Wrapper attributeWrapper = new Wrapper<>(); + Wrapper attributeWrapper = new Wrapper<>(); Wrapper blWrapper = new Wrapper<>(); validateInputStream(request, dataWrapper, errorWrapper); if (errorWrapper.isEmpty()) { - validateClassParse(dataWrapper.getInnerElement(), attributeWrapper, () -> ComponentInstanceAttribute.class, errorWrapper); + validateClassParse(dataWrapper.getInnerElement(), attributeWrapper, () -> ComponentInstanceProperty.class, errorWrapper); } if (errorWrapper.isEmpty()) { @@ -635,7 +633,7 @@ public class ComponentInstanceServlet extends AbstractValidationsServlet { ComponentInstanceBusinessLogic componentInstanceLogic = blWrapper.getInnerElement(); ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(containerComponentType); log.debug("Start handle request of ComponentInstanceAttribute. Received attribute is {}", attributeWrapper.getInnerElement()); - Either eitherAttribute = componentInstanceLogic.createOrUpdateAttributeValue(componentTypeEnum, componentId, componentInstanceId, attributeWrapper.getInnerElement(), userId); + Either eitherAttribute = componentInstanceLogic.createOrUpdateAttributeValue(componentTypeEnum, componentId, componentInstanceId, attributeWrapper.getInnerElement(), userId); if (eitherAttribute.isRight()) { errorWrapper.setInnerElement(eitherAttribute.right().value()); } else { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentServlet.java index b28700ace4..3a40e9626e 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentServlet.java @@ -87,12 +87,12 @@ public class ComponentServlet extends BeGenericServlet { private static Logger log = LoggerFactory.getLogger(ComponentServlet.class.getName()); @GET - @Path("/{componentType}/{componentId}/conformanceLevelValidation") + @Path("/{componentType}/{componentUuid}/conformanceLevelValidation") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @ApiOperation(value = "Validate Component Conformance Level", httpMethod = "GET", notes = "Returns the result according to conformance level in BE config", response = Resource.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "Component found"), @ApiResponse(code = 403, message = "Restricted operation"), @ApiResponse(code = 404, message = "Component not found") }) - public Response conformanceLevelValidation(@PathParam("componentType") final String componentType, @PathParam("componentId") final String componentId, @Context final HttpServletRequest request, + public Response conformanceLevelValidation(@PathParam("componentType") final String componentType, @PathParam("componentUuid") final String componentUuid, @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { Response response; ServletContext context = request.getSession().getServletContext(); @@ -103,7 +103,7 @@ public class ComponentServlet extends BeGenericServlet { ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); if (componentTypeEnum != null) { ComponentBusinessLogic compBL = getComponentBL(componentTypeEnum, context); - Either eitherConformanceLevel = compBL.validateConformanceLevel(componentId, componentTypeEnum, userId); + Either eitherConformanceLevel = compBL.validateConformanceLevel(componentUuid, componentTypeEnum, userId); if (eitherConformanceLevel.isRight()) { response = buildErrorResponse(eitherConformanceLevel.right().value()); } else { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LifecycleServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LifecycleServlet.java index 019a6ba8fd..d8b0a0ec39 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LifecycleServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LifecycleServlet.java @@ -39,11 +39,13 @@ import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoBase; import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datamodel.utils.UiComponentDataConverter; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.LifeCycleTransitionEnum; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.ui.model.UiComponentMetadata; import org.openecomp.sdc.common.api.Constants; import org.openecomp.sdc.common.config.EcompErrorName; import org.openecomp.sdc.exception.ResponseFormat; @@ -138,7 +140,8 @@ public class LifecycleServlet extends BeGenericServlet { } log.debug("change state successful !!!"); - Object value = RepresentationUtils.toRepresentation(actionResponse.left().value()); + UiComponentMetadata componentMetatdata = UiComponentDataConverter.convertToUiComponentMetadata(actionResponse.left().value()); + Object value = RepresentationUtils.toRepresentation(componentMetatdata); response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), value); return response; } else { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/UserAdminServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/UserAdminServlet.java index a477bcf4fb..d1e3d02907 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/UserAdminServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/UserAdminServlet.java @@ -43,7 +43,6 @@ import javax.ws.rs.core.Response; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; -import org.openecomp.sdc.be.model.FunctionalMenuInfo; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; import org.openecomp.sdc.be.user.UserBusinessLogic; @@ -474,41 +473,4 @@ public class UserAdminServlet extends BeGenericServlet { return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); } } - - @GET - @Path("/{userId}/functionalmenu") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @ApiOperation(value = "retrieve user details", httpMethod = "GET", notes = "Returns user details according to userId", response = User.class) - @ApiResponses(value = { @ApiResponse(code = 200, message = "Returns user Ok"), @ApiResponse(code = 404, message = "User not found"), @ApiResponse(code = 405, message = "Method Not Allowed"), - @ApiResponse(code = 500, message = "Internal Server Error") }) - public Response getFunctionalMenu(@ApiParam(value = "userId of user to get", required = true) @PathParam("userId") final String userId, @Context final HttpServletRequest request) { - - String url = request.getMethod() + " " + request.getRequestURI(); - log.debug("(get) Start handle request of {}", url); - - UserBusinessLogic userAdminManager = getUserAdminManager(request.getSession().getServletContext()); - - try { - Either functionalMenuResp = userAdminManager.getFunctionalMenu(userId); - - if (functionalMenuResp.isRight()) { - return buildErrorResponse(getComponentsUtils().getResponseFormatByUserId(functionalMenuResp.right().value(), userId)); - } else { - FunctionalMenuInfo functionalMenuInfo = functionalMenuResp.left().value(); - if (functionalMenuInfo != null && functionalMenuInfo.getFunctionalMenu() != null) { - log.debug("Functional menu fetched is {}", functionalMenuInfo.getFunctionalMenu()); - return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), functionalMenuInfo.getFunctionalMenu()); - } else { - log.debug("Functional menu is null"); - return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); - } - } - } catch (Exception e) { - BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get User"); - log.debug("get user failed with unexpected error: {}", e); - return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); - } - } - } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java index 3c0c80666c..b18cbc9adc 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java @@ -20,16 +20,12 @@ package org.openecomp.sdc.be.tosca; -import java.io.File; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumMap; -import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; @@ -41,13 +37,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.lang.WordUtils; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -79,7 +73,7 @@ import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.operations.impl.LifecycleOperation; import org.openecomp.sdc.be.resources.data.ESArtifactData; -import org.openecomp.sdc.be.resources.data.ESSdcSchemaFilesData; +import org.openecomp.sdc.be.resources.data.SdcSchemaFilesData; import org.openecomp.sdc.be.tosca.model.ToscaTemplate; import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; import org.openecomp.sdc.common.api.ArtifactTypeEnum; @@ -143,8 +137,9 @@ public class CsarUtils { private static final String TOSCA_META_PATH_FILE_NAME = "TOSCA-Metadata/TOSCA.meta"; private static final String TOSCA_META_VERSION = "1.0"; private static final String CSAR_VERSION = "1.1"; - - public static final String VFC_NODE_TYPE_ARTIFACTS_PATH_PATTERN = ARTIFACTS_PATH + ImportUtils.Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX + "([\\w\\_\\-\\.\\s]+)(/)([\\w\\_\\-\\.\\s]+)(/)([\\w\\_\\-\\.\\s\\/]+)"; + private static String versionFirstThreeOctates; + + public static final String VFC_NODE_TYPE_ARTIFACTS_PATH_PATTERN = ARTIFACTS_PATH + ImportUtils.Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX + "([\\d\\w\\_\\-\\.\\s]+)(/)([\\d\\w\\_\\-\\.\\s]+)(/)([\\d\\w\\_\\-\\.\\s\\/]+)"; public static final String VF_NODE_TYPE_ARTIFACTS_PATH_PATTERN = ARTIFACTS_PATH + // Artifact Group (i.e Deployment/Informational) @@ -155,6 +150,16 @@ public class CsarUtils { "([\\w\\_\\-\\.\\s]+)"; public static final String ARTIFACT_CREATED_FROM_CSAR = "Artifact created from csar"; + public CsarUtils() { + if(SDC_VERSION != null && !SDC_VERSION.isEmpty()){ + Matcher matcher = Pattern.compile("(?!\\.)(\\d+(\\.\\d+)+)(?![\\d\\.])").matcher(SDC_VERSION); + matcher.find(); + versionFirstThreeOctates = matcher.group(0); + } else { + versionFirstThreeOctates = ""; + } + } + /** * * @param component @@ -301,39 +306,40 @@ public class CsarUtils { } //add inner components to CSAR - innerComponentsCache.forEach((childUid, innerComponentTriple) -> { - Component innerComponent = innerComponentTriple.getRight(); - String icFileName = innerComponentTriple.getMiddle(); - - try { - //add component to zip - Either entryData = getEntryData(innerComponentTriple.getLeft(), innerComponent); - byte[] content = entryData.left().value(); - zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + icFileName)); - zip.write(content); - - } catch (IOException e) { + + for (Entry> innerComponentTripleEntry : innerComponentsCache.entrySet()) { + + ImmutableTriple innerComponentTriple = innerComponentTripleEntry.getValue(); - } + Component innerComponent = innerComponentTriple.getRight(); + String icFileName = innerComponentTriple.getMiddle(); - //add component interface to zip - if(!ToscaUtils.isAtomicType(innerComponent)) { - writeComponentInterface(innerComponent, zip, icFileName); - } - }); + // add component to zip + Either entryData = getEntryData(innerComponentTriple.getLeft(), innerComponent); + byte[] content = entryData.left().value(); + zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + icFileName)); + zip.write(content); + + // add component interface to zip + if (!ToscaUtils.isAtomicType(innerComponent)) { + writeComponentInterface(innerComponent, zip, icFileName); + } + } } - /*Either latestSchemaFilesFromCassandra = getLatestSchemaFilesFromCassandra(); + //retrieve SDC.zip from Cassandra + Either latestSchemaFilesFromCassandra = getLatestSchemaFilesFromCassandra(); if(latestSchemaFilesFromCassandra.isRight()){ - return null; - }*/ + log.error("Error retrieving SDC Schema files from cassandra" ); + return Either.right(latestSchemaFilesFromCassandra.right().value()); + } - //TODO Tal G this is quick solution until Cassandra US is alligned - Either addSchemaFilesFromConfig = addSchemaFilesFromConfig(zip); + //add files from retireved SDC.zip to Definitions folder in CSAR + Either addSchemaFilesFromCassandra = addSchemaFilesFromCassandra(zip, latestSchemaFilesFromCassandra.left().value()); - if(addSchemaFilesFromConfig.isRight()){ - return addSchemaFilesFromConfig; + if(addSchemaFilesFromCassandra.isRight()){ + return addSchemaFilesFromCassandra; } // Artifact Generation @@ -371,36 +377,47 @@ public class CsarUtils { return writeAllFilesToScar(component, collectedComponentCsarDefinition.left().value(), zip, isInCertificationRequest); } - - private Either addSchemaFilesFromConfig(ZipOutputStream zip) throws ZipException, IOException { - final String pathAndFile = "config/SDC.zip"; + + private Either addSchemaFilesFromCassandra(ZipOutputStream zip, byte[] schemaFileZip){ - File file = new File(pathAndFile); - if(!file.exists()){ - log.debug("SDC.zip schema files archive not found"); - return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); - } + final int initSize = 2048; - try(ZipFile zipFile = new ZipFile(new File(pathAndFile));){ - Enumeration entries = zipFile.entries(); + log.debug("Starting coppy from Schema file zip to CSAR zip"); + + try (ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(schemaFileZip)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + BufferedOutputStream bos = new BufferedOutputStream(out, initSize);) { - while(entries.hasMoreElements()){ - ZipEntry nextElement = entries.nextElement(); - InputStream inputStream = zipFile.getInputStream(nextElement); - byte[] byteArray = IOUtils.toByteArray(inputStream); - - zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + nextElement.getName())); - zip.write(byteArray); + ZipEntry entry = null; + + while ((entry = zipStream.getNextEntry()) != null) { + + String entryName = entry.getName(); + int readSize = initSize; + byte[] entryData = new byte[initSize]; + + while ((readSize = zipStream.read(entryData, 0, readSize)) != -1) { + bos.write(entryData, 0, readSize); + } + + bos.flush(); + out.flush(); + zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + entryName)); + zip.write(out.toByteArray()); + zip.flush(); + out.reset(); } - zipFile.close(); - }catch (Exception e) { - log.debug("Error in writing SDC.zip schema files to CSAR"); + } catch (IOException e) { + log.error("Error while writing the SDC schema file to the CSAR {}", e); return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); } + log.debug("Finished coppy from Schema file zip to CSAR zip"); + return Either.left(zip); } + private void insertInnerComponentsToCache(Map> componentCache, Component childComponent) { @@ -705,25 +722,24 @@ public class CsarUtils { return Either.left(content); } - private Either getLatestSchemaFilesFromCassandra() { - Matcher matcher = Pattern.compile("(?!\\.)(\\d+(\\.\\d+)+)(?![\\d\\.])").matcher(SDC_VERSION); - matcher.find(); - final String VERSION_FIRST_THREE_OCTATES = matcher.group(0); - Either, ActionStatus> specificSchemaFiles = sdcSchemaFilesCassandraDao.getSpecificSchemaFiles(VERSION_FIRST_THREE_OCTATES, CONFORMANCE_LEVEL); + private Either getLatestSchemaFilesFromCassandra() { + Either, CassandraOperationStatus> specificSchemaFiles = sdcSchemaFilesCassandraDao.getSpecificSchemaFiles(versionFirstThreeOctates, CONFORMANCE_LEVEL); - if(specificSchemaFiles.isRight()){ - log.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}", VERSION_FIRST_THREE_OCTATES, CONFORMANCE_LEVEL); - return Either.right(specificSchemaFiles.right().value()); + if(specificSchemaFiles.isRight()){ + log.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}", versionFirstThreeOctates, CONFORMANCE_LEVEL); + StorageOperationStatus storageStatus = DaoStatusConverter.convertCassandraStatusToStorageStatus(specificSchemaFiles.right().value()); + ActionStatus convertedFromStorageResponse = componentsUtils.convertFromStorageResponse(storageStatus); + return Either.right(componentsUtils.getResponseFormat(convertedFromStorageResponse)); } - List listOfSchemas = specificSchemaFiles.left().value(); + List listOfSchemas = specificSchemaFiles.left().value(); if(listOfSchemas.isEmpty()){ - log.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}", VERSION_FIRST_THREE_OCTATES, CONFORMANCE_LEVEL); - return Either.right(ActionStatus.GENERAL_ERROR); + log.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}", versionFirstThreeOctates, CONFORMANCE_LEVEL); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_SCHEMA_FILES_NOT_FOUND, versionFirstThreeOctates, CONFORMANCE_LEVEL)); } - ESSdcSchemaFilesData schemaFile = listOfSchemas.iterator().next(); + SdcSchemaFilesData schemaFile = listOfSchemas.iterator().next(); return Either.left(schemaFile.getPayloadAsArray()); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java index 072861ba3a..8be5b0b4b3 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java @@ -336,10 +336,9 @@ public class ToscaExportHandler { Resource resource = (Resource) component; toscaMetadata.setType(resource.getResourceType().name()); toscaMetadata.setSubcategory(categoryDefinition.getSubcategories().get(0).getName()); - if (!isInstance) { - toscaMetadata.setResourceVendor(resource.getVendorName()); - toscaMetadata.setResourceVendorRelease(resource.getVendorRelease()); - } + toscaMetadata.setResourceVendor(resource.getVendorName()); + toscaMetadata.setResourceVendorRelease(resource.getVendorRelease()); + break; case SERVICE: toscaMetadata.setType(component.getComponentType().getValue()); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/user/IUserBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/user/IUserBusinessLogic.java index 54ba9bf571..6bec3fa938 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/user/IUserBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/user/IUserBusinessLogic.java @@ -25,7 +25,6 @@ import java.util.List; import javax.servlet.ServletContext; import org.openecomp.sdc.be.dao.api.ActionStatus; -import org.openecomp.sdc.be.model.FunctionalMenuInfo; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.exception.ResponseFormat; @@ -50,7 +49,4 @@ public interface IUserBusinessLogic { public Either deActivateUser(User modifier, String userUniuqeIdToDeactive); public Either authorize(User authUser); - - public Either getFunctionalMenu(String userId); - } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserBusinessLogic.java index c90cc6118f..7135bfb62e 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/user/UserBusinessLogic.java @@ -28,18 +28,14 @@ import java.util.Map; import javax.annotation.Resource; import javax.servlet.ServletContext; -import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.tinkerpop.gremlin.structure.Edge; -import org.openecomp.portalsdk.core.onboarding.ueb.FunctionalMenu; -import org.openecomp.portalsdk.core.onboarding.ueb.UebException; import org.openecomp.sdc.be.config.BeEcompErrorManager; -import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.dao.titan.TitanGenericDao; import org.openecomp.sdc.be.dao.utils.UserStatusEnum; +import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; import org.openecomp.sdc.be.impl.ComponentsUtils; -import org.openecomp.sdc.be.model.FunctionalMenuInfo; import org.openecomp.sdc.be.model.LifecycleStateEnum; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.operations.api.IUserAdminOperation; @@ -249,16 +245,17 @@ public class UserBusinessLogic implements IUserBusinessLogic { // comment until admin will be able to do do check-in/check-out from the // UI - Either, StorageOperationStatus> userPendingTasksReq = getPandingUserPandingTasksWithCommit(userToUpdate); + Either, StorageOperationStatus> userPendingTasksReq = getPendingUserPendingTasksWithCommit(userToUpdate); if (userPendingTasksReq.isRight()) { - log.debug("updateUserRole method - failed to get user pending tasks list", userIdToUpdate); + log.debug("updateUserRole method - failed to get user pending tasks list userId {}", userIdToUpdate); return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(userPendingTasksReq.right().value()))); } List userPendingTasks = userPendingTasksReq.left().value(); - if (userPendingTasks.size() > 0) { - log.debug("updateUserRole method - User canot be updated, user have panding projects", userIdToUpdate); - String userTasksStatusForErrorMessage = getUserPandingTaskStatusByRole(UserRoleEnum.valueOf(userToUpdate.getRole())); + if (!userPendingTasks.isEmpty()) { + log.debug("updateUserRole method - User canot be updated, user have pending projects userId {}", userIdToUpdate); + + String userTasksStatusForErrorMessage = getUserPendingTaskStatusByRole(UserRoleEnum.valueOf(userToUpdate.getRole())); String userInfo = userToUpdate.getFirstName() + " " + userToUpdate.getLastName() + '(' + userToUpdate.getUserId() + ')'; responseFormat = componentsUtils.getResponseFormat(ActionStatus.CANNOT_UPDATE_USER_WITH_ACTIVE_ELEMENTS, userInfo, userTasksStatusForErrorMessage); handleAuditing(modifier, userToUpdate, userToUpdate, responseFormat, AuditingActionEnum.UPDATE_USER); @@ -413,7 +410,7 @@ public class UserBusinessLogic implements IUserBusinessLogic { return Either.right(responseFormat); } - Either, StorageOperationStatus> userPendingTasksReq = getPandingUserPandingTasksWithCommit(userToDeactivate); + Either, StorageOperationStatus> userPendingTasksReq = getPendingUserPendingTasksWithCommit(userToDeactivate); if (userPendingTasksReq.isRight()) { log.debug("deActivateUser method - failed to get user pending tasks list", userUniuqeIdToDeactive); return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(userPendingTasksReq.right().value()))); @@ -421,9 +418,9 @@ public class UserBusinessLogic implements IUserBusinessLogic { List userPendingTasks = userPendingTasksReq.left().value(); if (userPendingTasks.size() > 0) { - log.debug("deActivateUser method - User canot be deleted, user have panding projects", userUniuqeIdToDeactive); + log.debug("deActivateUser method - User canot be deleted, user have pending projects", userUniuqeIdToDeactive); - String userTasksStatusForErrorMessage = getUserPandingTaskStatusByRole(UserRoleEnum.valueOf(userToDeactivate.getRole())); + String userTasksStatusForErrorMessage = getUserPendingTaskStatusByRole(UserRoleEnum.valueOf(userToDeactivate.getRole())); String userInfo = userToDeactivate.getFirstName() + " " + userToDeactivate.getLastName() + '(' + userToDeactivate.getUserId() + ')'; responseFormat = componentsUtils.getResponseFormat(ActionStatus.CANNOT_DELETE_USER_WITH_ACTIVE_ELEMENTS, userInfo, userTasksStatusForErrorMessage); handleAuditing(modifier, userToDeactivate, userToDeactivate, responseFormat, AuditingActionEnum.DELETE_USER); @@ -589,7 +586,7 @@ public class UserBusinessLogic implements IUserBusinessLogic { return Either.left(updatedUser); } - private Either, StorageOperationStatus> getPandingUserPandingTasksWithCommit(User user) { + private Either, StorageOperationStatus> getPendingUserPendingTasksWithCommit(User user) { Either, StorageOperationStatus> result = null; @@ -601,21 +598,21 @@ public class UserBusinessLogic implements IUserBusinessLogic { case PRODUCT_STRATEGIST: case PRODUCT_MANAGER: properties.put(GraphPropertiesDictionary.STATE.getProperty(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); - return userAdminOperation.getUserPandingTasksList(user, properties); + return userAdminOperation.getUserPendingTasksList(user, properties); case TESTER: properties.put(GraphPropertiesDictionary.STATE.getProperty(), LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); - return userAdminOperation.getUserPandingTasksList(user, properties); + return userAdminOperation.getUserPendingTasksList(user, properties); case ADMIN: properties.put(GraphPropertiesDictionary.STATE.getProperty(), LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); properties.put(GraphPropertiesDictionary.STATE.getProperty(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); - return userAdminOperation.getUserPandingTasksList(user, properties); + return userAdminOperation.getUserPendingTasksList(user, properties); default: return Either.left(new ArrayList<>()); } } finally { // commit will be perform outside!!! if (result == null || result.isRight()) { - log.debug("getUserPandingTasksList failed to perform fetching"); + log.debug("getUserPendingTasksList failed to perform fetching"); titanDao.rollback(); } else { titanDao.commit(); @@ -623,7 +620,7 @@ public class UserBusinessLogic implements IUserBusinessLogic { } } - private String getUserPandingTaskStatusByRole(UserRoleEnum role) { + private String getUserPendingTaskStatusByRole(UserRoleEnum role) { switch (role) { case DESIGNER: @@ -639,77 +636,4 @@ public class UserBusinessLogic implements IUserBusinessLogic { return ""; } } - - /** - * return the functional menu of a given user - * - * @param userId - * @param inTransaction - * @return - */ - public Either getFunctionalMenu(String userId) { - - boolean toCommit = false; - - FunctionalMenuInfo functionalMenuInfo = new FunctionalMenuInfo(); - - try { - - Either, ActionStatus> userResult = userAdminOperation.getUserDataWithFunctionalMenu(userId); - if (userResult.isRight()) { - ActionStatus actionStatus = userResult.right().value(); - if (actionStatus == ActionStatus.USER_NOT_FOUND) { - actionStatus = ActionStatus.INVALID_USER_ID; - } - return Either.right(actionStatus); - } - - ImmutablePair immutablePair = userResult.left().value(); - FunctionalMenuInfo currentFunctionalMenu = immutablePair.right; - String currentMenuStr = currentFunctionalMenu != null ? currentFunctionalMenu.getFunctionalMenu() : null; - - String functionalMenu = getFunctionalMenuFromUeb(userId); - - // functionalMenu can be null or since we catch UebException - if (functionalMenu != null && false == functionalMenu.isEmpty()) { - functionalMenuInfo.setFunctionalMenu(functionalMenu); - if (false == functionalMenu.equals(currentMenuStr)) { - log.debug("Going to update functional menu of user {}. Functional menu is {}", userId, functionalMenu); - userAdminOperation.createOrUpdateFunctionalMenu(userId, functionalMenu); - } - } else { - String menu = currentMenuStr; - if (menu == null) { - menu = "[]"; - } - log.debug("Fetch functional menu from old request. Functional menu is {}", menu); - functionalMenuInfo.setFunctionalMenu(menu); - } - - toCommit = true; - - } finally { - if (toCommit) { - titanDao.commit(); - } else { - titanDao.rollback(); - } - } - - return Either.left(functionalMenuInfo); - } - - private String getFunctionalMenuFromUeb(String userId) { - String functionalMenu = null; - try { - log.debug("Before calling to FunctionalMenu method for user {}", userId); - functionalMenu = FunctionalMenu.get(userId); - log.debug("Functional menu fetched is {}", functionalMenu); - - } catch (UebException e) { - log.debug("Failed to fetch 'functional menu' of user {} from ecomp portal(via UEB)", userId, e); - BeEcompErrorManager.getInstance().logInternalFlowError("FetchFunctionalMenu", "Failed to fetch 'functional menu'", ErrorSeverity.ERROR); - } - return functionalMenu; - } } diff --git a/catalog-be/src/main/resources/application-context.xml b/catalog-be/src/main/resources/application-context.xml index 702c63ea81..6c44b270c2 100644 --- a/catalog-be/src/main/resources/application-context.xml +++ b/catalog-be/src/main/resources/application-context.xml @@ -57,7 +57,7 @@ - + diff --git a/catalog-be/src/main/resources/config/SDC.zip b/catalog-be/src/main/resources/config/SDC.zip index dfb4be85fba5375c19d930e4680a3b39d133d25a..674f6f86b433619108eaccd6e1ab11fd2b36a156 100644 GIT binary patch delta 21034 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 diff --git a/catalog-be/src/main/resources/config/error-configuration.yaml b/catalog-be/src/main/resources/config/error-configuration.yaml index ef7a885678..0fb4e146d4 100644 --- a/catalog-be/src/main/resources/config/error-configuration.yaml +++ b/catalog-be/src/main/resources/config/error-configuration.yaml @@ -1765,7 +1765,7 @@ errors: # %4 – Artifact uuid ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION: { code: 400, - message: " Error: CSAR packaging failed for %1 %2. Artifact %3 [%4] was not found", + message: "Error: CSAR packaging failed for %1 %2. Artifact %3 [%4] was not found", messageId: "SVC4659" } #---------SVC4660------------------------------ @@ -1776,3 +1776,11 @@ errors: message: "Creation of %1 failed. Generic type %2 was not found", messageId: "SVC4660" } +#---------SVC4661------------------------------ +# %1 - assetType +# %2 - matching generic node type name + TOSCA_SCHEMA_FILES_NOT_FOUND: { + code: 400, + message: "Error: CSAR packaging failed. TOSCA schema files for SDC-Version: %1 and Conformance-Level %2 were not found", + messageId: "SVC4661" + } \ No newline at end of file diff --git a/catalog-be/src/main/resources/config/logback.xml b/catalog-be/src/main/resources/config/logback.xml index 8ba0a31944..ba16783536 100644 --- a/catalog-be/src/main/resources/config/logback.xml +++ b/catalog-be/src/main/resources/config/logback.xml @@ -1,8 +1,8 @@ - - + + diff --git a/catalog-be/src/main/resources/import/tosca/data-types/dataTypes.yml b/catalog-be/src/main/resources/import/tosca/data-types/dataTypes.yml index b4c442f3df..63d70c699e 100644 --- a/catalog-be/src/main/resources/import/tosca/data-types/dataTypes.yml +++ b/catalog-be/src/main/resources/import/tosca/data-types/dataTypes.yml @@ -21,6 +21,19 @@ map: json: derived_from: tosca.datatypes.Root + +scalar-unit: + derived_from: tosca.datatypes.Root + +scalar-unit.size: + derived_from: scalar-unit + +scalar-unit.time: + derived_from: scalar-unit + +scalar-unit.frequency: + derived_from: scalar-unit + tosca.datatypes.Credential: derived_from: tosca.datatypes.Root diff --git a/catalog-be/src/main/resources/import/tosca/data-types/dataTypes.zip b/catalog-be/src/main/resources/import/tosca/data-types/dataTypes.zip index 4f3e269c69db4f19aabd52af986ebbb54fe22ac4..9c5964df1df4fba94608f7d22ac8c437f874299a 100644 GIT binary patch delta 5253 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 delta 5219 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 d005tolR^|N294d75KGRJbrd271{44Q008 artifact1Map = Collections.singletonMap("key1", artifact1); + Map artifact2Map = Collections.singletonMap("key1", artifact2); + Map artifact3Map = Collections.singletonMap("key1", artifact3); + + resource.setDeploymentArtifacts(artifact1Map); + resource.setArtifacts(artifact2Map); + + service.setDeploymentArtifacts(artifact1Map); + service.setArtifacts(artifact2Map); + service.setServiceApiArtifacts(artifact3Map); + + componentInstance.setDeploymentArtifacts(artifact1Map); + componentInstance.setArtifacts(artifact2Map); + } + + @Test + public void findArtifactOnComponent_noArtifactsOnComponent() throws Exception { + assertNull(testInstance.findArtifactOnComponent(noArtifactsResource, ComponentTypeEnum.RESOURCE, "someId")); + assertNull(testInstance.findArtifactOnComponent(noArtifactsService, ComponentTypeEnum.SERVICE, "someId")); + } + + @Test + public void findArtifactOnComponent_resource() throws Exception { + assertNull(testInstance.findArtifactOnComponent(resource, ComponentTypeEnum.RESOURCE, "someId")); + assertNotNull(testInstance.findArtifactOnComponent(resource, ComponentTypeEnum.RESOURCE, "a1")); + assertNotNull(testInstance.findArtifactOnComponent(resource, ComponentTypeEnum.RESOURCE, "a2")); + } + + @Test + public void findArtifactOnComponent_service() throws Exception { + assertNull(testInstance.findArtifactOnComponent(service, ComponentTypeEnum.SERVICE, "someId")); + assertNotNull(testInstance.findArtifactOnComponent(service, ComponentTypeEnum.SERVICE, "a1")); + assertNotNull(testInstance.findArtifactOnComponent(service, ComponentTypeEnum.SERVICE, "a2")); + assertNotNull(testInstance.findArtifactOnComponent(service, ComponentTypeEnum.SERVICE, "a3")); + } + + @Test + public void findArtifactOnInstance_instanceHasNoArtifacts() throws Exception { + assertNull(testInstance.findArtifactOnComponentInstance(noArtifactsInstance, "someId")); + } + + @Test + public void findArtifactOnInstance() throws Exception { + assertNull(testInstance.findArtifactOnComponentInstance(componentInstance, "someId")); + assertNotNull(testInstance.findArtifactOnComponentInstance(componentInstance, "a1")); + assertNotNull(testInstance.findArtifactOnComponentInstance(componentInstance, "a2")); + } +} diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ImportUtilsTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ImportUtilsTest.java index 6dd19cce57..59d49de3a3 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ImportUtilsTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ImportUtilsTest.java @@ -42,7 +42,6 @@ import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum; import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.HeatParameterDefinition; import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.common.api.ArtifactTypeEnum; @@ -300,7 +299,7 @@ public class ImportUtilsTest { public void testGetAttributesFromYml() throws IOException { Map toscaJson = (Map) loadJsonFromFile("importToscaWithAttribute.yml"); - Either, ResultStatusEnum> actualAttributes = ImportUtils.getAttributes(toscaJson); + Either, ResultStatusEnum> actualAttributes = ImportUtils.getAttributes(toscaJson); assertTrue(actualAttributes.isLeft()); Map> expectedAttributes = getElements(toscaJson, ToscaTagNamesEnum.ATTRIBUTES); compareAttributes(expectedAttributes, actualAttributes.left().value()); @@ -318,10 +317,10 @@ public class ImportUtilsTest { } - private void compareAttributes(Map> expected, Map actual) { + private void compareAttributes(Map> expected, Map actual) { Map singleExpectedAttribute; - AttributeDefinition actualAttribute, expectedAttributeModel; + PropertyDefinition actualAttribute, expectedAttributeModel; // attributes of resource for (Map.Entry> expectedAttribute : expected.entrySet()) { diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServletTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServletTest.java index 2aa061a890..d6808da5d6 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServletTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/externalapi/servlet/AssetsDataServletTest.java @@ -52,6 +52,7 @@ import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic; import org.openecomp.sdc.be.components.impl.ResourceImportManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter; import org.openecomp.sdc.be.externalapi.servlet.representation.ResourceAssetMetadata; import org.openecomp.sdc.be.impl.ComponentsUtils; import org.openecomp.sdc.be.impl.ServletUtils; diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java index acd8563878..ee74a468fc 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java @@ -71,7 +71,7 @@ public enum ActionStatus { GROUP_MEMBER_EMPTY, GROUP_TYPE_ALREADY_EXIST, // CSAR - MISSING_CSAR_UUID, CSAR_INVALID, CSAR_INVALID_FORMAT, CSAR_NOT_FOUND, YAML_NOT_FOUND_IN_CSAR, VSP_ALREADY_EXISTS, RESOURCE_LINKED_TO_DIFFERENT_VSP, RESOURCE_FROM_CSAR_NOT_FOUND, AAI_ARTIFACT_GENERATION_FAILED, ASSET_NOT_FOUND_DURING_CSAR_CREATION, ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION, + MISSING_CSAR_UUID, CSAR_INVALID, CSAR_INVALID_FORMAT, CSAR_NOT_FOUND, YAML_NOT_FOUND_IN_CSAR, VSP_ALREADY_EXISTS, RESOURCE_LINKED_TO_DIFFERENT_VSP, RESOURCE_FROM_CSAR_NOT_FOUND, AAI_ARTIFACT_GENERATION_FAILED, ASSET_NOT_FOUND_DURING_CSAR_CREATION, ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION, TOSCA_SCHEMA_FILES_NOT_FOUND, // Group GROUP_HAS_CYCLIC_DEPENDENCY, GROUP_ALREADY_EXIST, GROUP_TYPE_IS_INVALID, GROUP_MISSING_GROUP_TYPE, GROUP_INVALID_COMPONENT_INSTANCE, GROUP_INVALID_TOSCA_NAME_OF_COMPONENT_INSTANCE, GROUP_IS_MISSING, GROUP_ARTIFACT_ALREADY_ASSOCIATED, GROUP_ARTIFACT_ALREADY_DISSOCIATED, GROUP_PROPERTY_NOT_FOUND, INVALID_VF_MODULE_NAME, INVALID_VF_MODULE_NAME_MODIFICATION, INVALID_VF_MODULE_TYPE, diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/SdcSchemaFilesAccessor.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/SdcSchemaFilesAccessor.java index e6843eab2f..1168bf4edf 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/SdcSchemaFilesAccessor.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/SdcSchemaFilesAccessor.java @@ -1,6 +1,6 @@ package org.openecomp.sdc.be.dao.cassandra; -import org.openecomp.sdc.be.resources.data.ESSdcSchemaFilesData; +import org.openecomp.sdc.be.resources.data.SdcSchemaFilesData; import com.datastax.driver.mapping.Result; import com.datastax.driver.mapping.annotations.Accessor; @@ -10,5 +10,5 @@ import com.datastax.driver.mapping.annotations.Query; @Accessor public interface SdcSchemaFilesAccessor { @Query("SELECT * FROM sdcartifact.sdcschemafiles WHERE SDCRELEASENUM = :sdcreleasenum AND CONFORMANCELEVEL = :conformancelevel") - Result getSpecificSdcSchemaFiles(@Param("sdcreleasenum") String sdcreleasenum, @Param("conformancelevel") String conformancelevel); + Result getSpecificSdcSchemaFiles(@Param("sdcreleasenum") String sdcreleasenum, @Param("conformancelevel") String conformancelevel); } diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/SdcSchemaFilesCassandraDao.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/SdcSchemaFilesCassandraDao.java index 1bb0f05898..d292c1ddeb 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/SdcSchemaFilesCassandraDao.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/SdcSchemaFilesCassandraDao.java @@ -1,13 +1,11 @@ package org.openecomp.sdc.be.dao.cassandra; -import java.util.LinkedList; import java.util.List; import javax.annotation.PostConstruct; import org.apache.commons.lang3.tuple.ImmutablePair; -import org.openecomp.sdc.be.dao.api.ActionStatus; -import org.openecomp.sdc.be.resources.data.ESSdcSchemaFilesData; +import org.openecomp.sdc.be.resources.data.SdcSchemaFilesData; import org.openecomp.sdc.be.resources.data.auditing.AuditingTypesConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,33 +48,41 @@ public class SdcSchemaFilesCassandraDao extends CassandraDao { } } - public CassandraOperationStatus saveArtifact(ESSdcSchemaFilesData artifact) { - return client.save(artifact, ESSdcSchemaFilesData.class, manager); + public CassandraOperationStatus saveSchemaFile(SdcSchemaFilesData schemaFileData) { + return client.save(schemaFileData, SdcSchemaFilesData.class, manager); } - public Either getArtifact(String artifactId) { - return client.getById(artifactId, ESSdcSchemaFilesData.class, manager); + public Either getSchemaFile(String schemaFileId) { + return client.getById(schemaFileId, SdcSchemaFilesData.class, manager); } - public CassandraOperationStatus deleteArtifact(String artifactId) { - return client.delete(artifactId, ESSdcSchemaFilesData.class, manager); + public CassandraOperationStatus deleteSchemaFile(String schemaFileId) { + return client.delete(schemaFileId, SdcSchemaFilesData.class, manager); } - public Either, ActionStatus> getSpecificSchemaFiles(String sdcreleasenum, String conformancelevel) { - Result specificSdcSchemaFiles = sdcSchemaFilesAccessor.getSpecificSdcSchemaFiles(sdcreleasenum, conformancelevel); + public Either, CassandraOperationStatus> getSpecificSchemaFiles(String sdcreleasenum, String conformancelevel) { + + Result specificSdcSchemaFiles = null; + try { + specificSdcSchemaFiles = sdcSchemaFilesAccessor.getSpecificSdcSchemaFiles(sdcreleasenum, conformancelevel); + } catch (Exception e) { + logger.debug("getSpecificSchemaFiles failed with exception {}", e); + return Either.right(CassandraOperationStatus.GENERAL_ERROR); + } if(specificSdcSchemaFiles == null) { logger.debug("not found specific SdcSchemaFiles for sdcreleasenum {}, conformancelevel {}", sdcreleasenum, conformancelevel); - return Either.left(new LinkedList()); + return Either.right(CassandraOperationStatus.NOT_FOUND); } + List list = specificSdcSchemaFiles.all(); if(logger.isDebugEnabled()){ - for (ESSdcSchemaFilesData esSdcSchemaFilesData : specificSdcSchemaFiles) { - logger.debug(esSdcSchemaFilesData.toString()); + for (SdcSchemaFilesData esSdcSchemaFilesData : list) { + logger.trace(esSdcSchemaFilesData.toString()); } } - return Either.left(specificSdcSchemaFiles.all()); + return Either.left(list); } /** diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/jsongraph/types/VertexTypeEnum.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/jsongraph/types/VertexTypeEnum.java index c485b238f4..cb9c7207d2 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/jsongraph/types/VertexTypeEnum.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/jsongraph/types/VertexTypeEnum.java @@ -16,7 +16,7 @@ public enum VertexTypeEnum { CAPABILTIES ("capabilities", ListCapabilityDataDefinition.class), CAPABILITIES_PROPERTIES ("capabilities_properties", MapPropertiesDataDefinition.class), REQUIREMENTS ("requirements", ListRequirementDataDefinition.class), - ATTRIBUTES ("attributes", AttributeDataDefinition.class), + ATTRIBUTES ("attributes", PropertyDataDefinition.class), RESOURCE_CATEGORY ("resourceNewCategory", null), RESOURCE_SUBCATEGORY ("resourceSubcategory", null), SERVICE_CATEGORY ("serviceNewCategory", null), @@ -24,7 +24,7 @@ public enum VertexTypeEnum { USER ("user", null), INPUTS ("inputs", PropertyDataDefinition.class), GROUPS ("groups", GroupDataDefinition.class), - INST_ATTRIBUTES ("instAttributes", MapAttributesDataDefinition.class), + INST_ATTRIBUTES ("instAttributes", MapPropertiesDataDefinition.class), INST_PROPERTIES ("instProperties", MapPropertiesDataDefinition.class), INST_INPUTS ("instInputs", MapPropertiesDataDefinition.class), INST_GROUPS ("instGroups", MapGroupsDataDefinition.class), diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java index 3ec9d0d3b9..2ff1567928 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java @@ -29,6 +29,7 @@ public enum GraphPropertiesDictionary { CONTACT_ID ("contactId", String.class, false, false), VENDOR_NAME ("vendorName", String.class, false, false), VENDOR_RELEASE ("vendorRelease", String.class, false, false), + CONFORMANCE_LEVEL ("conformanceLevel", String.class, false, false), ICON ("icon", String.class, false, false), TAGS ("tags", String.class, false, false), UUID ("uuid", String.class, false, true), diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/AttributeData.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/AttributeData.java index 16a8c8be60..a99529d950 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/AttributeData.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/AttributeData.java @@ -27,21 +27,21 @@ import java.util.Map; import org.openecomp.sdc.be.dao.graph.datatype.GraphNode; import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.dao.utils.Constants; -import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import com.google.gson.reflect.TypeToken; public class AttributeData extends GraphNode { - AttributeDataDefinition attributeDataDefinition; + PropertyDataDefinition attributeDataDefinition; public AttributeData() { super(NodeTypeEnum.Attribute); - attributeDataDefinition = new AttributeDataDefinition(); + attributeDataDefinition = new PropertyDataDefinition(); } - public AttributeData(AttributeDataDefinition attributeDataDefinition) { + public AttributeData(PropertyDataDefinition attributeDataDefinition) { super(NodeTypeEnum.Attribute); this.attributeDataDefinition = attributeDataDefinition; } @@ -56,11 +56,11 @@ public class AttributeData extends GraphNode { return attributeDataDefinition.getUniqueId(); } - public AttributeDataDefinition getAttributeDataDefinition() { + public PropertyDataDefinition getAttributeDataDefinition() { return attributeDataDefinition; } - public void setAttributeDataDefinition(AttributeDataDefinition attributeDataDefinition) { + public void setAttributeDataDefinition(PropertyDataDefinition attributeDataDefinition) { this.attributeDataDefinition = attributeDataDefinition; } diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ComponentMetadataData.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ComponentMetadataData.java index 0ad081832f..7e084eb021 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ComponentMetadataData.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ComponentMetadataData.java @@ -51,6 +51,7 @@ public abstract class ComponentMetadataData extends GraphNode { metadataDataDefinition.setUniqueId((String) properties.get(GraphPropertiesDictionary.UNIQUE_ID.getProperty())); metadataDataDefinition.setCreationDate((Long) properties.get(GraphPropertiesDictionary.CREATION_DATE.getProperty())); metadataDataDefinition.setDescription((String) properties.get(GraphPropertiesDictionary.DESCRIPTION.getProperty())); + metadataDataDefinition.setConformanceLevel((String) properties.get(GraphPropertiesDictionary.CONFORMANCE_LEVEL.getProperty())); metadataDataDefinition.setIcon((String) properties.get(GraphPropertiesDictionary.ICON.getProperty())); metadataDataDefinition.setHighestVersion((Boolean) properties.get(GraphPropertiesDictionary.IS_HIGHEST_VERSION.getProperty())); metadataDataDefinition.setLastUpdateDate((Long) properties.get(GraphPropertiesDictionary.LAST_UPDATE_DATE.getProperty())); @@ -87,6 +88,7 @@ public abstract class ComponentMetadataData extends GraphNode { addIfExists(map, GraphPropertiesDictionary.VERSION, metadataDataDefinition.getVersion()); addIfExists(map, GraphPropertiesDictionary.CREATION_DATE, metadataDataDefinition.getCreationDate()); addIfExists(map, GraphPropertiesDictionary.DESCRIPTION, metadataDataDefinition.getDescription()); + addIfExists(map, GraphPropertiesDictionary.CONFORMANCE_LEVEL, metadataDataDefinition.getConformanceLevel()); addIfExists(map, GraphPropertiesDictionary.ICON, metadataDataDefinition.getIcon()); addIfExists(map, GraphPropertiesDictionary.IS_HIGHEST_VERSION, metadataDataDefinition.isHighestVersion()); addIfExists(map, GraphPropertiesDictionary.LAST_UPDATE_DATE, metadataDataDefinition.getLastUpdateDate()); diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ESSdcSchemaFilesData.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/SdcSchemaFilesData.java similarity index 73% rename from catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ESSdcSchemaFilesData.java rename to catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/SdcSchemaFilesData.java index c6ab13bb3d..96ab5aedc8 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/ESSdcSchemaFilesData.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/resources/data/SdcSchemaFilesData.java @@ -3,18 +3,22 @@ package org.openecomp.sdc.be.resources.data; import java.nio.ByteBuffer; import java.util.Date; +import com.datastax.driver.mapping.annotations.ClusteringColumn; import com.datastax.driver.mapping.annotations.Column; +import com.datastax.driver.mapping.annotations.PartitionKey; import com.datastax.driver.mapping.annotations.Table; @Table(keyspace = "sdcartifact", name = "sdcschemafiles") -public class ESSdcSchemaFilesData { - +public class SdcSchemaFilesData { + @PartitionKey(0) @Column(name = "sdcreleasenum") private String sdcReleaseNum; - + + @ClusteringColumn @Column(name = "timestamp") private Date timestamp; - + + @PartitionKey(1) @Column(name = "conformanceLevel") private String conformanceLevel; @@ -27,19 +31,21 @@ public class ESSdcSchemaFilesData { @Column(name = "checksum") private String checksum; - public ESSdcSchemaFilesData() { + public SdcSchemaFilesData() { } - public ESSdcSchemaFilesData(String sdcReleaseNum, String conformanceLevel, String fileName, byte[] payload){ + public SdcSchemaFilesData(String sdcReleaseNum, Date timestamp, String conformanceLevel, String fileName, byte[] payload, String checksum){ this.sdcReleaseNum = sdcReleaseNum; + this.timestamp = timestamp; this.conformanceLevel = conformanceLevel; this.fileName = fileName; if(payload != null) { this.payload = ByteBuffer.wrap(payload.clone()); } + this.checksum = checksum; } - + public String getSdcReleaseNum() { return sdcReleaseNum; } @@ -99,4 +105,10 @@ public class ESSdcSchemaFilesData { public void setChecksum(String checksum) { this.checksum = checksum; } + + @Override + public String toString() { + return "SdcSchemaFilesData [sdcReleaseNum=" + sdcReleaseNum + ", timestamp=" + timestamp + ", conformanceLevel=" + + conformanceLevel + ", fileName=" + fileName + ", checksum=" + checksum + "]"; + } } diff --git a/catalog-fe/pom.xml b/catalog-fe/pom.xml index a3acabb41f..e5d4bdaf83 100644 --- a/catalog-fe/pom.xml +++ b/catalog-fe/pom.xml @@ -246,7 +246,7 @@ org.openecomp.ecompsdkos - ecompFW + epsdk-fw ${ecomp.version} compile diff --git a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java index 4eba2e5eb5..a743f98b18 100644 --- a/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java +++ b/catalog-fe/src/main/java/org/openecomp/sdc/fe/servlets/PortalServlet.java @@ -34,7 +34,9 @@ import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; -import org.openecomp.portalsdk.core.onboarding.crossapi.ECOMPSSO; +import org.openecomp.portalsdk.core.onboarding.util.CipherUtil; +import org.openecomp.portalsdk.core.onboarding.util.PortalApiConstants; +import org.openecomp.portalsdk.core.onboarding.util.PortalApiProperties; import org.openecomp.sdc.common.config.EcompErrorName; import org.openecomp.sdc.common.impl.MutableHttpServletRequest; import org.openecomp.sdc.fe.Constants; @@ -95,9 +97,8 @@ public class PortalServlet extends HttpServlet { if (null == userId) { // Authentication via ecomp portal try { - String valdiateECOMPSSO = ECOMPSSO.valdiateECOMPSSO(request); - String userIdFromCookie = ECOMPSSO.getUserIdFromCookie(request); - if (valdiateECOMPSSO == null || ("").equals(userIdFromCookie)) { + String userIdFromCookie = getUserIdFromCookie(request); + if (("").equals(userIdFromCookie)) { // This is probably a webseal request, so missing header in request should be printed. response.sendError(HttpServletResponse.SC_USE_PROXY, MISSING_HEADERS_MSG); } @@ -275,5 +276,20 @@ public class PortalServlet extends HttpServlet { } return newHeaderIsSet; } + + private static String getUserIdFromCookie(HttpServletRequest request) throws Exception { + String userId = ""; + Cookie[] cookies = request.getCookies(); + Cookie userIdcookie = null; + if (cookies != null) + for (Cookie cookie : cookies) + if (cookie.getName().equals(Constants.USER_ID)) + userIdcookie = cookie; + if (userIdcookie != null) { + userId = CipherUtil.decrypt(userIdcookie.getValue(), + PortalApiProperties.getProperty(PortalApiConstants.Decryption_Key)); + } + return userId; + } } diff --git a/catalog-fe/src/main/resources/config/logback.xml b/catalog-fe/src/main/resources/config/logback.xml index fd2e13ca43..d1e1c613d1 100644 --- a/catalog-fe/src/main/resources/config/logback.xml +++ b/catalog-fe/src/main/resources/config/logback.xml @@ -1,8 +1,8 @@ - - + + diff --git a/catalog-fe/src/test/resources/CI/originalResources/images/network.png b/catalog-fe/src/test/resources/CI/originalResources/images/network.png index c8bf18f31a2486332a6dd7895e071dbf7d4c9104..c98eef324ed15dc5b8ee28be01904f597504330b 100644 GIT binary patch literal 4214 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 literal 159707 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

sFH*fx<7q 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 componentInstancesProperties; - private Map> componentInstancesAttributes; + private Map> componentInstancesAttributes; private Map> capabilities; @@ -609,12 +609,12 @@ public abstract class Component implements Serializable { } } - public Map> getComponentInstancesAttributes() { + public Map> getComponentInstancesAttributes() { return componentInstancesAttributes; } public void setComponentInstancesAttributes( - Map> componentInstancesAttributes) { + Map> componentInstancesAttributes) { this.componentInstancesAttributes = componentInstancesAttributes; } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceAttribute.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceAttribute.java deleted file mode 100644 index 4e55152526..0000000000 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceAttribute.java +++ /dev/null @@ -1,78 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -package org.openecomp.sdc.be.model; - -import java.io.Serializable; - -public class ComponentInstanceAttribute extends AttributeDefinition - implements IComponentInstanceConnectedElement, Serializable { - - /** - * - */ - private static final long serialVersionUID = -496828411269235795L; - - private Boolean hidden; - - /** - * The unique id of the attribute value on graph - */ - private String valueUniqueUid; - - public ComponentInstanceAttribute() { - super(); - } - - public ComponentInstanceAttribute(AttributeDefinition pd, Boolean hidden, String valueUniqueUid) { - super(pd); - - this.hidden = hidden; - this.valueUniqueUid = valueUniqueUid; - setParentUniqueId(pd.getParentUniqueId()); - } - - public ComponentInstanceAttribute(AttributeDefinition attributeDefinition) { - super(attributeDefinition); - } - - public String getValueUniqueUid() { - return valueUniqueUid; - } - - public void setValueUniqueUid(String valueUniqueUid) { - this.valueUniqueUid = valueUniqueUid; - } - - @Override - public String toString() { - return "ComponentInstanceAttribute [ " + super.toString() + " , value=" + hidden + ", valueUniqueUid = " - + valueUniqueUid + " ]"; - } - - public Boolean isHidden() { - return hidden; - } - - public void setHidden(Boolean hidden) { - this.hidden = hidden; - } - -} diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceInput.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceInput.java index ca53db69d9..9347f326d1 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceInput.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceInput.java @@ -32,10 +32,6 @@ public class ComponentInstanceInput extends InputDefinition implements IComponen */ private static final long serialVersionUID = -3937554584759816724L; - /** - * Value of property - */ - private String value; /** * The unique id of the property value on graph @@ -58,14 +54,14 @@ public class ComponentInstanceInput extends InputDefinition implements IComponen String valueUniqueUid) { super(curPropertyDef); this.inputId = inputId; - this.value = value; + setValue(value); this.valueUniqueUid = valueUniqueUid; } public ComponentInstanceInput(InputDefinition pd, String value, String valueUniqueUid) { super(pd); - this.value = value; + setValue(value); this.valueUniqueUid = valueUniqueUid; } @@ -100,14 +96,6 @@ public class ComponentInstanceInput extends InputDefinition implements IComponen this.inputId = inputId; } - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - public String getValueUniqueUid() { return valueUniqueUid; } @@ -142,7 +130,7 @@ public class ComponentInstanceInput extends InputDefinition implements IComponen @Override public String toString() { - return "ComponentInstanceInput [ " + super.toString() + " , value=" + value + ", valueUniqueUid = " + return "ComponentInstanceInput [ " + super.toString() + " , value=" + getValue() + ", valueUniqueUid = " + valueUniqueUid + " , rules=" + rules + " , path=" + path + " ]"; } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceProperty.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceProperty.java index 17eb045630..8bd3a9c809 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceProperty.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/ComponentInstanceProperty.java @@ -87,6 +87,14 @@ public class ComponentInstanceProperty extends PropertyDefinition implements ICo this.setValue(value); this.valueUniqueUid = valueUniqueUid; } + + public ComponentInstanceProperty(Boolean hidden, PropertyDefinition pd, String valueUniqueUid) { + super(pd); + + this.hidden = hidden; + this.valueUniqueUid = valueUniqueUid; + setParentUniqueId(pd.getParentUniqueId()); + } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/PropertyDefinition.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/PropertyDefinition.java index b315d5c7fd..34ecdbf06d 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/PropertyDefinition.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/PropertyDefinition.java @@ -104,7 +104,7 @@ public class PropertyDefinition extends PropertyDataDefinition private List constraints; // private Schema schema; - private String status; + // private String status; @@ -120,7 +120,7 @@ public class PropertyDefinition extends PropertyDataDefinition public PropertyDefinition(PropertyDefinition pd) { super(pd); this.setConstraints(pd.getConstraints()); - status = pd.status; + //status = pd.status; } @@ -149,13 +149,13 @@ public class PropertyDefinition extends PropertyDataDefinition // return schema; // } - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } +// public String getStatus() { +// return status; +// } +// +// public void setStatus(String status) { +// this.status = status; +// } @@ -174,7 +174,7 @@ public class PropertyDefinition extends PropertyDataDefinition int result = super.hashCode(); result = prime * result + ((constraints == null) ? 0 : constraints.hashCode()); result = prime * result + ((getName() == null) ? 0 : getName().hashCode()); - result = prime * result + ((status == null) ? 0 : status.hashCode()); + //result = prime * result + ((status == null) ? 0 : status.hashCode()); return result; } @@ -197,11 +197,11 @@ public class PropertyDefinition extends PropertyDataDefinition return false; } else if (!getName().equals(other.getName())) return false; - if (status == null) { - if (other.status != null) - return false; - } else if (!status.equals(other.status)) - return false; +// if (status == null) { +// if (other.status != null) +// return false; +// } else if (!status.equals(other.status)) +// return false; return true; } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/Resource.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/Resource.java index 5e7983acea..a9c6b44324 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/Resource.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/Resource.java @@ -52,7 +52,7 @@ public class Resource extends Component implements Serializable { private List properties; - private List attributes; + private List attributes; // Later private Map interfaces; @@ -98,11 +98,11 @@ public class Resource extends Component implements Serializable { this.properties = properties; } - public List getAttributes() { + public List getAttributes() { return attributes; } - public void setAttributes(List attributes) { + public void setAttributes(List attributes) { this.attributes = attributes; } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/datamodel/NodeType.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/datamodel/NodeType.java index 7c6c207f74..c1b4129afc 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/datamodel/NodeType.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/datamodel/NodeType.java @@ -3,11 +3,11 @@ package org.openecomp.sdc.be.model.jsontitan.datamodel; import java.util.List; import java.util.Map; -import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition; import org.openecomp.sdc.be.datatypes.elements.InterfaceDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListCapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListRequirementDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapPropertiesDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; public class NodeType extends ToscaElement{ @@ -18,7 +18,7 @@ public class NodeType extends ToscaElement{ private List derivedFrom; private List derivedList; - private Map attributes; + private Map attributes; private Map capabilties; private Map capabiltiesProperties; private Map requirements; @@ -45,11 +45,11 @@ public class NodeType extends ToscaElement{ this.derivedFrom = derivedFrom; } - public Map getAttributes() { + public Map getAttributes() { return attributes; } - public void setAttributes(Map attributes) { + public void setAttributes(Map attributes) { this.attributes = attributes; } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/datamodel/TopologyTemplate.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/datamodel/TopologyTemplate.java index 74c4c30aa5..5b236e4b84 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/datamodel/TopologyTemplate.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/datamodel/TopologyTemplate.java @@ -9,7 +9,6 @@ import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition; import org.openecomp.sdc.be.datatypes.elements.CompositionDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapArtifactDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.MapAttributesDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapCapabiltyProperty; import org.openecomp.sdc.be.datatypes.elements.MapGroupsDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapListCapabiltyDataDefinition; @@ -28,7 +27,7 @@ public class TopologyTemplate extends ToscaElement{ private Map inputs; private Map instInputs; private Map heatParameters; - private Map instAttributes; + private Map instAttributes; private Map instProperties; private Map groups; private Map instGroups; @@ -64,10 +63,10 @@ public class TopologyTemplate extends ToscaElement{ public void setHeatParameters(Map heatParameters) { this.heatParameters = heatParameters; } - public Map getInstAttributes() { + public Map getInstAttributes() { return instAttributes; } - public void setInstAttributes(Map instAttributes) { + public void setInstAttributes(Map instAttributes) { this.instAttributes = instAttributes; } public Map getInstProperties() { @@ -163,7 +162,7 @@ public class TopologyTemplate extends ToscaElement{ getCompositions().get(JsonConstantKeysEnum.COMPOSITION.getValue()).getComponentInstances().put(componentInstance.getUniqueId(), componentInstance); } /** - * Returns map of component inctances from composition + * Returns map of component instances from composition * @return */ public Map getComponentInstances() { diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ArtifactsOperations.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ArtifactsOperations.java index 55853479d2..a3cb41f1c0 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ArtifactsOperations.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ArtifactsOperations.java @@ -30,6 +30,7 @@ import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; import org.openecomp.sdc.common.jsongraph.util.CommonUtility; import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum; import org.slf4j.Logger; @@ -45,7 +46,7 @@ public class ArtifactsOperations extends BaseOperation { public Either addArifactToComponent(ArtifactDefinition artifactInfo, String parentId, NodeTypeEnum type, boolean failIfExist, String instanceId) { - Either status = updateArtifactOnGraph(parentId, artifactInfo, type, artifactInfo.getUniqueId(), instanceId); + Either status = updateArtifactOnGraph(parentId, artifactInfo, type, artifactInfo.getUniqueId(), instanceId, false); if (status.isRight()) { log.debug("Failed to update artifact {} of {} {}. status is {}", artifactInfo.getArtifactName(), type.getName(), parentId, status.right().value()); @@ -64,7 +65,7 @@ public class ArtifactsOperations extends BaseOperation { public Either updateArifactOnResource(ArtifactDefinition artifactInfo, String id, String artifactId, NodeTypeEnum type, String instanceId) { - Either status = updateArtifactOnGraph(id, artifactInfo, type, artifactId, instanceId); + Either status = updateArtifactOnGraph(id, artifactInfo, type, artifactId, instanceId, true); if (status.isRight()) { log.debug("Failed to update artifact {} of {} {}. status is {}", artifactInfo.getArtifactName(), type.getName(), id, status.right().value()); @@ -211,11 +212,14 @@ public class ArtifactsOperations extends BaseOperation { } - public void updateUUID(ArtifactDataDefinition artifactData, String oldChecksum, String oldVesrion) { + public void updateUUID(ArtifactDataDefinition artifactData, String oldChecksum, String oldVesrion, boolean isUpdate) { if (oldVesrion == null || oldVesrion.isEmpty()) oldVesrion = "0"; String currentChecksum = artifactData.getArtifactChecksum(); + if(isUpdate && artifactData.getArtifactType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_ENV.getType())){ + generateUUID(artifactData, oldVesrion); + } if (oldChecksum == null || oldChecksum.isEmpty()) { if (currentChecksum != null) { generateUUID(artifactData, oldVesrion); @@ -259,7 +263,7 @@ public class ArtifactsOperations extends BaseOperation { } Map artifacts = artifactsEither.left().value(); - List envList = artifacts.values().stream().filter(a -> a.getGeneratedFromId().equals(artifactId)).collect(Collectors.toList()); + List envList = artifacts.values().stream().filter(a -> a.getGeneratedFromId()!= null && a.getGeneratedFromId().equals(artifactId)).collect(Collectors.toList()); if (envList != null && !envList.isEmpty()) { envList.forEach(a -> { a.setGeneratedFromId(newArtifactId); @@ -409,7 +413,7 @@ public class ArtifactsOperations extends BaseOperation { } - public Either updateArtifactOnGraph(String componentId, ArtifactDefinition artifactInfo, NodeTypeEnum type, String artifactId, String instanceId) { + public Either updateArtifactOnGraph(String componentId, ArtifactDefinition artifactInfo, NodeTypeEnum type, String artifactId, String instanceId, boolean isUpdate) { Either res = null; ArtifactDataDefinition artifactToUpdate = new ArtifactDataDefinition(artifactInfo); ArtifactGroupTypeEnum groupType = artifactInfo.getArtifactGroupType(); @@ -479,7 +483,7 @@ public class ArtifactsOperations extends BaseOperation { } } } - updateUUID(artifactToUpdate, oldChecksum, oldVersion); + updateUUID(artifactToUpdate, oldChecksum, oldVersion, isUpdate); if (artifactInfo.getPayloadData() == null) { if (!artifactToUpdate.getMandatory() || artifactToUpdate.getEsId() != null) { diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/BaseOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/BaseOperation.java index 629d9ecdd4..ed14bac8bb 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/BaseOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/BaseOperation.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; @@ -23,17 +24,24 @@ import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum; import org.openecomp.sdc.be.dao.jsongraph.utils.IdBuilderUtils; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.GroupInstanceDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.GroupDefinition; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElementTypeEnum; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.common.jsongraph.util.CommonUtility; import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum; +import org.openecomp.sdc.common.util.ValidationUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -948,7 +956,7 @@ public abstract class BaseOperation { if (result == null) { currMap.put(key, toscaDataBlock); } - return null; + return result; } @SuppressWarnings("unchecked") @@ -1248,9 +1256,9 @@ public abstract class BaseOperation { return result; } - private StorageOperationStatus handleToscaData(GraphVertex toscaElement, VertexTypeEnum vertexLabel, EdgeLabelEnum edgeLabel, GraphVertex toscaDataVertex, Map mergedToscaDataMap) { + protected StorageOperationStatus handleToscaData(GraphVertex toscaElement, VertexTypeEnum vertexLabel, EdgeLabelEnum edgeLabel, GraphVertex toscaDataVertex, Map mergedToscaDataMap) { - StorageOperationStatus result = null; + StorageOperationStatus result = StorageOperationStatus.OK; if (toscaDataVertex == null) { Either createRes = assosiateElementToData(toscaElement, vertexLabel, edgeLabel, mergedToscaDataMap); @@ -1312,5 +1320,41 @@ public abstract class BaseOperation { // } // return StorageOperationStatus.OK; // } + + protected GroupInstanceDataDefinition buildGroupInstanceDataDefinition(GroupDataDefinition group, ComponentInstanceDataDefinition componentInstance) { + + String componentInstanceName = componentInstance.getName(); + Long creationDate = System.currentTimeMillis(); + GroupInstanceDataDefinition groupInstance = new GroupInstanceDataDefinition(); + String groupUid = group.getUniqueId(); + + groupInstance.setGroupUid(groupUid); + groupInstance.setType(group.getType()); + groupInstance.setCustomizationUUID(generateCustomizationUUID()); + groupInstance.setCreationTime(creationDate); + groupInstance.setModificationTime(creationDate); + groupInstance.setName(buildGroupInstanceName(componentInstanceName, group.getName())); + groupInstance.setGroupName(group.getName()); + groupInstance.setNormalizedName(ValidationUtils.normalizeComponentInstanceName(groupInstance.getName())); + groupInstance.setUniqueId(UniqueIdBuilder.buildResourceInstanceUniuqeId(componentInstance.getUniqueId(), groupUid, groupInstance.getNormalizedName())); + groupInstance.setArtifacts(group.getArtifacts()); + groupInstance.setArtifactsUuid(group.getArtifactsUuid()); + groupInstance.setProperties(group.getProperties()); + groupInstance.setInvariantUUID(group.getInvariantUUID()); + groupInstance.setGroupUUID(group.getGroupUUID()); + groupInstance.setVersion(group.getVersion()); + + return groupInstance; + } + + protected String buildGroupInstanceName(String instanceName, String groupName) { + int groupNameIndex = groupName.indexOf(".."); + //turn group name from VFName..heatfile..module-n to VFiName..heatfile..module-n + return ValidationUtils.normaliseComponentName(instanceName) + groupName.substring(groupNameIndex); + } + + protected String generateCustomizationUUID() { + return UUID.randomUUID().toString(); + } } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/NodeTemplateOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/NodeTemplateOperation.java index a20f85ad7b..58ee914046 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/NodeTemplateOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/NodeTemplateOperation.java @@ -30,11 +30,11 @@ import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition; import org.openecomp.sdc.be.datatypes.elements.CompositionDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GroupInstanceDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListCapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListRequirementDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapArtifactDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.MapAttributesDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapCapabiltyProperty; import org.openecomp.sdc.be.datatypes.elements.MapDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapGroupsDataDefinition; @@ -343,7 +343,7 @@ public class NodeTemplateOperation extends BaseOperation { CompositionDataDefinition composition = container.getCompositions().get(JsonConstantKeysEnum.COMPOSITION.getValue()); if (composition != null) { Map relations = composition.getRelations(); - if (relations != null) { + if (MapUtils.isNotEmpty(relations)) { Either>, StorageOperationStatus> capResult = fetchContainerCalculatedCapability(containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES); if (capResult.isRight()) { return capResult.right().value(); @@ -397,6 +397,11 @@ public class NodeTemplateOperation extends BaseOperation { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to remove calculated capabilty for instance {} in container {}. error {] ", componentInstanceId, containerV.getUniqueId(), status); return status; } + status = deleteToscaDataDeepElementsBlockToToscaElement(containerV, EdgeLabelEnum.CALCULATED_CAP_PROPERTIES, VertexTypeEnum.CALCULATED_CAP_PROPERTIES, componentInstanceId); + if (status != StorageOperationStatus.OK && status != StorageOperationStatus.NOT_FOUND) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to remove calculated capabilty properties for instance {} in container {}. error {] ", componentInstanceId, containerV.getUniqueId(), status); + return status; + } status = deleteToscaDataDeepElementsBlockToToscaElement(containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS, VertexTypeEnum.CALCULATED_REQUIREMENTS, componentInstanceId); if (status != StorageOperationStatus.OK && status != StorageOperationStatus.NOT_FOUND) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to remove calculated requirement for instance {} in container {}. error {] ", componentInstanceId, containerV.getUniqueId(), status); @@ -414,12 +419,12 @@ public class NodeTemplateOperation extends BaseOperation { } status = deleteToscaDataDeepElementsBlockToToscaElement(containerV, EdgeLabelEnum.INST_ATTRIBUTES, VertexTypeEnum.INST_ATTRIBUTES, componentInstanceId); if (status != StorageOperationStatus.OK && status != StorageOperationStatus.NOT_FOUND) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to remove fullfilled requirement for instance {} in container {}. error {] ", componentInstanceId, containerV.getUniqueId(), status); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to remove attributes for instance {} in container {}. error {] ", componentInstanceId, containerV.getUniqueId(), status); return status; } status = deleteToscaDataDeepElementsBlockToToscaElement(containerV, EdgeLabelEnum.INST_PROPERTIES, VertexTypeEnum.INST_PROPERTIES, componentInstanceId); if (status != StorageOperationStatus.OK && status != StorageOperationStatus.NOT_FOUND) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to remove fullfilled requirement for instance {} in container {}. error {] ", componentInstanceId, containerV.getUniqueId(), status); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to remove properties for instance {} in container {}. error {] ", componentInstanceId, containerV.getUniqueId(), status); return status; } status = deleteToscaDataDeepElementsBlockToToscaElement(containerV, EdgeLabelEnum.INST_INPUTS, VertexTypeEnum.INST_INPUTS, componentInstanceId); @@ -433,6 +438,11 @@ public class NodeTemplateOperation extends BaseOperation { return status; } status = deleteToscaDataDeepElementsBlockToToscaElement(containerV, EdgeLabelEnum.INST_DEPLOYMENT_ARTIFACTS, VertexTypeEnum.INST_DEPLOYMENT_ARTIFACTS, componentInstanceId); + if (status != StorageOperationStatus.OK && status != StorageOperationStatus.NOT_FOUND) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to remove instance deployment artifacts for instance {} in container {}. error {] ", componentInstanceId, containerV.getUniqueId(), status); + return status; + } + status = deleteToscaDataDeepElementsBlockToToscaElement(containerV, EdgeLabelEnum.INSTANCE_ARTIFACTS, VertexTypeEnum.INSTANCE_ARTIFACTS, componentInstanceId); if (status != StorageOperationStatus.OK && status != StorageOperationStatus.NOT_FOUND) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to remove instance artifacts for instance {} in container {}. error {] ", componentInstanceId, containerV.getUniqueId(), status); return status; @@ -440,7 +450,7 @@ public class NodeTemplateOperation extends BaseOperation { return StorageOperationStatus.OK; } - private Either addComponentInstanceToscaDataToContainerComponent(ToscaElement originToscaElement, ComponentInstanceDataDefinition componentInstance, GraphVertex updatedContainerVertex, User user) { + protected Either addComponentInstanceToscaDataToContainerComponent(ToscaElement originToscaElement, ComponentInstanceDataDefinition componentInstance, GraphVertex updatedContainerVertex, User user) { Either result; StorageOperationStatus status; @@ -561,7 +571,7 @@ public class NodeTemplateOperation extends BaseOperation { return status; } - MapAttributesDataDefinition instAttributes = new MapAttributesDataDefinition(originNodeType.getAttributes()); + MapPropertiesDataDefinition instAttributes = new MapPropertiesDataDefinition(originNodeType.getAttributes()); status = addToscaDataDeepElementsBlockToToscaElement(updatedContainerVertex, EdgeLabelEnum.INST_ATTRIBUTES, VertexTypeEnum.INST_ATTRIBUTES, instAttributes, componentInstance.getUniqueId()); @@ -775,7 +785,7 @@ public class NodeTemplateOperation extends BaseOperation { return null; } - public StorageOperationStatus addGroupInstancesToComponentInstance(Component containerComponent, ComponentInstance componentInstance, List groups, Map> groupInstancesArtifacts) { + public StorageOperationStatus addGroupInstancesToComponentInstance(Component containerComponent, ComponentInstanceDataDefinition componentInstance, List groups, Map> groupInstancesArtifacts) { StorageOperationStatus result = null; Map groupInstanceToCreate = new HashMap<>(); @@ -783,7 +793,7 @@ public class NodeTemplateOperation extends BaseOperation { for (Map.Entry> groupArtifacts : groupInstancesArtifacts.entrySet()) { Optional groupOptional = groups.stream().filter(g -> g.getUniqueId().equals(groupArtifacts.getKey())).findFirst(); if (groupOptional.isPresent()) { - GroupInstanceDataDefinition groupInstance = buildGroupInstanceDataDefinition(groupOptional.get(), componentInstance); + GroupInstanceDataDefinition groupInstance = buildGroupInstanceDataDefinition((GroupDataDefinition)groupOptional.get(), (ComponentInstanceDataDefinition)componentInstance); groupInstance.setGroupInstanceArtifacts(groupArtifacts.getValue().stream().map(a -> a.getUniqueId()).collect(Collectors.toList())); groupInstance.setGroupInstanceArtifactsUuid(groupArtifacts.getValue().stream().map(a -> a.getArtifactUUID()).collect(Collectors.toList())); groupInstanceToCreate.put(groupInstance.getName(), groupInstance); @@ -799,31 +809,7 @@ public class NodeTemplateOperation extends BaseOperation { return result; } - private GroupInstanceDataDefinition buildGroupInstanceDataDefinition(GroupDefinition group, ComponentInstance componentInstance) { - - String componentInstanceName = componentInstance.getName(); - Long creationDate = System.currentTimeMillis(); - GroupInstanceDataDefinition groupInstance = new GroupInstanceDataDefinition(); - String groupUid = group.getUniqueId(); - - groupInstance.setGroupUid(groupUid); - groupInstance.setType(group.getType()); - groupInstance.setCustomizationUUID(generateCustomizationUUID()); - groupInstance.setCreationTime(creationDate); - groupInstance.setModificationTime(creationDate); - groupInstance.setName(buildGroupInstanceName(componentInstanceName, group.getName())); - groupInstance.setGroupName(groupInstance.getName()); - groupInstance.setNormalizedName(ValidationUtils.normalizeComponentInstanceName(groupInstance.getName())); - groupInstance.setUniqueId(UniqueIdBuilder.buildResourceInstanceUniuqeId(componentInstance.getUniqueId(), groupUid, groupInstance.getNormalizedName())); - groupInstance.setArtifacts(group.getArtifacts()); - groupInstance.setArtifactsUuid(group.getArtifactsUuid()); - groupInstance.setProperties(group.getProperties()); - groupInstance.setInvariantUUID(group.getInvariantUUID()); - groupInstance.setGroupUUID(group.getGroupUUID()); - groupInstance.setVersion(group.getVersion()); - - return groupInstance; - } + private ComponentInstanceDataDefinition buildComponentInstanceDataDefinition(ComponentInstance resourceInstance, String containerComponentId, String instanceNewName, boolean generateUid, ToscaElement originToscaElement) { String ciOriginComponentUid = resourceInstance.getComponentUid(); @@ -892,15 +878,9 @@ public class NodeTemplateOperation extends BaseOperation { return isUniqueName; } - private String buildGroupInstanceName(String instanceName, String groupName) { - int groupNameIndex = groupName.indexOf(".."); - //turn group name from VFName..heatfile..module-n to VFiName..heatfile..module-n - return ValidationUtils.normaliseComponentName(instanceName) + groupName.substring(groupNameIndex); - } + - private String generateCustomizationUUID() { - return UUID.randomUUID().toString(); - } + private String buildComponentInstanceName(String instanceSuffixNumber, String instanceName) { return instanceName + " " + (instanceSuffixNumber == null ? 0 : instanceSuffixNumber); @@ -1525,7 +1505,7 @@ public class NodeTemplateOperation extends BaseOperation { RelationshipInstDataDefinition relationshipTypeData = buildRelationshipInstData(fromInstId, toInstId, relationPair); - relationshipTypeData.setType(type); + relationshipTypeData.setType(requirementForRelation.getRelationship()); return Either.left(relationshipTypeData); } @@ -1716,7 +1696,8 @@ public class NodeTemplateOperation extends BaseOperation { pathKeys.add(componentInstanceId); return updateToscaDataDeepElementOfToscaElement(containerComponent.getUniqueId(), EdgeLabelEnum.INST_PROPERTIES, VertexTypeEnum.INST_PROPERTIES, property, pathKeys, JsonPresentationFields.NAME); } - + + public StorageOperationStatus addComponentInstanceProperty(Component containerComponent, String componentInstanceId, ComponentInstanceProperty property) { List pathKeys = new ArrayList<>(); pathKeys.add(componentInstanceId); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/NodeTypeOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/NodeTypeOperation.java index 1eb67e5c51..985870b5e3 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/NodeTypeOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/NodeTypeOperation.java @@ -2,16 +2,17 @@ package org.openecomp.sdc.be.model.jsontitan.operations; import fj.data.Either; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.ImmutableTriple; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; +import org.openecomp.sdc.be.dao.graph.datatype.GraphNode; import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum; import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.datatypes.elements.AdditionalInfoParameterDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.InterfaceDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListCapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; @@ -20,11 +21,11 @@ import org.openecomp.sdc.be.datatypes.elements.MapCapabiltyProperty; import org.openecomp.sdc.be.datatypes.elements.MapPropertiesDataDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.DerivedNodeTypeResolver; import org.openecomp.sdc.be.model.LifecycleStateEnum; -import org.openecomp.sdc.be.model.RequirementDefinition; import org.openecomp.sdc.be.model.jsontitan.datamodel.NodeType; import org.openecomp.sdc.be.model.jsontitan.datamodel.TopologyTemplate; import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElement; @@ -32,6 +33,22 @@ import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElementTypeEnum; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.be.resources.data.AttributeData; +import org.openecomp.sdc.be.resources.data.AttributeValueData; +import org.openecomp.sdc.be.resources.data.CapabilityData; +import org.openecomp.sdc.be.resources.data.CapabilityTypeData; +import org.openecomp.sdc.be.resources.data.DataTypeData; +import org.openecomp.sdc.be.resources.data.GroupData; +import org.openecomp.sdc.be.resources.data.GroupTypeData; +import org.openecomp.sdc.be.resources.data.InputValueData; +import org.openecomp.sdc.be.resources.data.InputsData; +import org.openecomp.sdc.be.resources.data.PolicyTypeData; +import org.openecomp.sdc.be.resources.data.PropertyData; +import org.openecomp.sdc.be.resources.data.PropertyValueData; +import org.openecomp.sdc.be.resources.data.RelationshipInstData; +import org.openecomp.sdc.be.resources.data.RelationshipTypeData; +import org.openecomp.sdc.be.resources.data.RequirementData; +import org.openecomp.sdc.be.resources.data.ResourceMetadataData; import org.openecomp.sdc.common.jsongraph.util.CommonUtility; import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum; import org.slf4j.Logger; @@ -44,6 +61,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.function.Function; import java.util.regex.Pattern; @org.springframework.stereotype.Component("node-type-operation") @@ -152,7 +170,7 @@ public class NodeTypeOperation extends ToscaElementOperation { private StorageOperationStatus associateInterfacesToResource(GraphVertex nodeTypeVertex, NodeType nodeType, List derivedResources) { // Note : currently only one derived supported!!!! - Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, InterfaceDataDefinition.class, EdgeLabelEnum.INTERFACE_ARTIFACTS); + Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, EdgeLabelEnum.INTERFACE_ARTIFACTS); if (dataFromDerived.isRight()) { return dataFromDerived.right().value(); } @@ -377,7 +395,7 @@ public class NodeTypeOperation extends ToscaElementOperation { } private TitanOperationStatus setResourceAttributesFromGraph(GraphVertex componentV, NodeType toscaElement) { - Either, TitanOperationStatus> result = getDataFromGraph(componentV, EdgeLabelEnum.ATTRIBUTES); + Either, TitanOperationStatus> result = getDataFromGraph(componentV, EdgeLabelEnum.ATTRIBUTES); if (result.isLeft()) { toscaElement.setAttributes(result.left().value()); } else { @@ -413,7 +431,7 @@ public class NodeTypeOperation extends ToscaElementOperation { private StorageOperationStatus addAdditionalInformationToResource(GraphVertex nodeTypeVertex, NodeType nodeType, List derivedResources) { // Note : currently only one derived supported!!!! - Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, AdditionalInfoParameterDataDefinition.class, EdgeLabelEnum.ADDITIONAL_INFORMATION); + Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, EdgeLabelEnum.ADDITIONAL_INFORMATION); if (dataFromDerived.isRight()) { return dataFromDerived.right().value(); } @@ -421,7 +439,7 @@ public class NodeTypeOperation extends ToscaElementOperation { Map addInformation = nodeType.getAdditionalInformation(); if (addInformation != null) { - addInformationAll.putAll(addInformation); + ToscaDataDefinition.mergeDataMaps(addInformationAll, addInformation); } if (!addInformationAll.isEmpty()) { Either assosiateElementToData = assosiateElementToData(nodeTypeVertex, VertexTypeEnum.ADDITIONAL_INFORMATION, EdgeLabelEnum.ADDITIONAL_INFORMATION, addInformationAll); @@ -434,7 +452,7 @@ public class NodeTypeOperation extends ToscaElementOperation { private StorageOperationStatus associateCapabilitiesToResource(GraphVertex nodeTypeVertex, NodeType nodeType, List derivedResources) { // Note : currently only one derived supported!!!! - Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, ListCapabilityDataDefinition.class, EdgeLabelEnum.CAPABILITIES); + Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, EdgeLabelEnum.CAPABILITIES); if (dataFromDerived.isRight()) { return dataFromDerived.right().value(); } @@ -452,9 +470,7 @@ public class NodeTypeOperation extends ToscaElementOperation { }); }); - for (Entry entry : capabilties.entrySet()) { - capabiltiesAll.merge(entry.getKey(), entry.getValue(), (list1, list2) -> list1.mergeListItemsByName(list2)); - } + ToscaDataDefinition.mergeDataMaps(capabiltiesAll, capabilties); } if (!capabiltiesAll.isEmpty()) { Either assosiateElementToData = assosiateElementToData(nodeTypeVertex, VertexTypeEnum.CAPABILTIES, EdgeLabelEnum.CAPABILITIES, capabiltiesAll); @@ -467,7 +483,7 @@ public class NodeTypeOperation extends ToscaElementOperation { private StorageOperationStatus associateRequirementsToResource(GraphVertex nodeTypeVertex, NodeType nodeType, List derivedResources) { // Note : currently only one derived supported!!!! - Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, ListRequirementDataDefinition.class, EdgeLabelEnum.REQUIREMENTS); + Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, EdgeLabelEnum.REQUIREMENTS); if (dataFromDerived.isRight()) { return dataFromDerived.right().value(); } @@ -485,9 +501,8 @@ public class NodeTypeOperation extends ToscaElementOperation { }); }); - for (Entry entry : requirements.entrySet()) { - requirementsAll.merge(entry.getKey(), entry.getValue(), (list1, list2) -> list1.mergeListItemsByName(list2)); - } + ToscaDataDefinition.mergeDataMaps(requirementsAll, requirements); + } if (!requirementsAll.isEmpty()) { Either assosiateElementToData = assosiateElementToData(nodeTypeVertex, VertexTypeEnum.REQUIREMENTS, EdgeLabelEnum.REQUIREMENTS, requirementsAll); @@ -500,19 +515,19 @@ public class NodeTypeOperation extends ToscaElementOperation { private StorageOperationStatus associateAttributesToResource(GraphVertex nodeTypeVertex, NodeType nodeType, List derivedResources) { // Note : currently only one derived supported!!!! - Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, AttributeDataDefinition.class, EdgeLabelEnum.ATTRIBUTES); + Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, EdgeLabelEnum.ATTRIBUTES); if (dataFromDerived.isRight()) { return dataFromDerived.right().value(); } - Map attributesAll = dataFromDerived.left().value(); + Map attributesAll = dataFromDerived.left().value(); - Map attributes = nodeType.getAttributes(); + Map attributes = nodeType.getAttributes(); if (attributes != null) { attributes.values().stream().filter(p -> p.getUniqueId() == null).forEach(p -> { String uid = UniqueIdBuilder.buildAttributeUid(nodeTypeVertex.getUniqueId(), p.getName()); p.setUniqueId(uid); }); - attributesAll.putAll(attributes); + ToscaDataDefinition.mergeDataMaps(attributesAll, attributes); } if (!attributesAll.isEmpty()) { Either assosiateElementToData = assosiateElementToData(nodeTypeVertex, VertexTypeEnum.ATTRIBUTES, EdgeLabelEnum.ATTRIBUTES, attributesAll); @@ -526,7 +541,7 @@ public class NodeTypeOperation extends ToscaElementOperation { // TODO get from derived private StorageOperationStatus associateCapabilitiesPropertiesToResource(GraphVertex nodeTypeVertex, NodeType nodeType, List derivedResources) { // // Note : currently only one derived supported!!!! - Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, MapPropertiesDataDefinition.class, EdgeLabelEnum.CAPABILITIES_PROPERTIES); + Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, EdgeLabelEnum.CAPABILITIES_PROPERTIES); if (dataFromDerived.isRight()) { return dataFromDerived.right().value(); } @@ -542,9 +557,9 @@ public class NodeTypeOperation extends ToscaElementOperation { }); } }); - propertiesAll.putAll(capabiltiesProps); + ToscaDataDefinition.mergeDataMaps(propertiesAll, capabiltiesProps); } - if (propertiesAll != null) { + if (!propertiesAll.isEmpty()) { Either assosiateElementToData = assosiateElementToData(nodeTypeVertex, VertexTypeEnum.CAPABILITIES_PROPERTIES, EdgeLabelEnum.CAPABILITIES_PROPERTIES, propertiesAll); if (assosiateElementToData.isRight()) { return assosiateElementToData.right().value(); @@ -657,7 +672,7 @@ public class NodeTypeOperation extends ToscaElementOperation { protected StorageOperationStatus updateDerived(T toscaElementToUpdate, GraphVertex nodeTypeV) { NodeType nodeType = (NodeType) toscaElementToUpdate; - List derivedResources = null; + List derivedResources = new ArrayList<>(); List derivedFromResources = nodeType.getDerivedFrom(); @@ -691,7 +706,8 @@ public class NodeTypeOperation extends ToscaElementOperation { } // must be only one GraphVertex newDerived = getParentResources.left().value().get(0); - StorageOperationStatus updateStatus = updateDataFromNewDerived(newDerived, nodeTypeV); + derivedResources.add(newDerived); + StorageOperationStatus updateStatus = updateDataFromNewDerived(derivedResources, nodeTypeV, (NodeType)toscaElementToUpdate); if (updateStatus != StorageOperationStatus.OK) { CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to update data for {} from new derived {} ", nodeTypeV.getUniqueId(), newDerived.getUniqueId(), updateStatus); return updateStatus; @@ -704,44 +720,70 @@ public class NodeTypeOperation extends ToscaElementOperation { return DaoStatusConverter.convertTitanStatusToStorageStatus(deleteError); } - titanDao.createEdge(nodeTypeV, newDerived, EdgeLabelEnum.DERIVED_FROM, null); + titanDao.createEdge(nodeTypeV, newDerived, EdgeLabelEnum.DERIVED_FROM, new HashMap<>()); } } return StorageOperationStatus.OK; } + + private StorageOperationStatus associateDerivedDataByType(EdgeLabelEnum edgeLabel, GraphVertex nodeTypeV, NodeType nodeToUpdate, List newDerived) { + + switch (edgeLabel) { + case CAPABILITIES: + return associateCapabilitiesToResource(nodeTypeV, nodeToUpdate, newDerived); + case REQUIREMENTS: + return associateRequirementsToResource(nodeTypeV, nodeToUpdate, newDerived); + case PROPERTIES: + return associatePropertiesToResource(nodeTypeV, nodeToUpdate, newDerived); + case ATTRIBUTES: + return associateAttributesToResource(nodeTypeV, nodeToUpdate, newDerived); + case ADDITIONAL_INFORMATION: + return addAdditionalInformationToResource(nodeTypeV, nodeToUpdate, newDerived); + case CAPABILITIES_PROPERTIES: + return associateCapabilitiesPropertiesToResource(nodeTypeV, nodeToUpdate, newDerived); + default: + return StorageOperationStatus.OK; + } + + } - private StorageOperationStatus updateDataFromNewDerived(GraphVertex newDerived, GraphVertex nodeTypeV) { - StorageOperationStatus status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.CAPABILITIES, CapabilityDataDefinition.class); + private StorageOperationStatus updateDataFromNewDerived(List newDerived, GraphVertex nodeTypeV, NodeType nodeToUpdate) { + + StorageOperationStatus status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.CAPABILITIES, nodeToUpdate); if (status != StorageOperationStatus.OK) { return status; } - status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.REQUIREMENTS, RequirementDefinition.class); + + status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.REQUIREMENTS, nodeToUpdate); if (status != StorageOperationStatus.OK) { return status; } - status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.PROPERTIES, PropertyDataDefinition.class); + + status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.PROPERTIES, nodeToUpdate); if (status != StorageOperationStatus.OK) { return status; } - status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.ATTRIBUTES, AttributeDataDefinition.class); + + status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.ATTRIBUTES, nodeToUpdate); + if (status != StorageOperationStatus.OK) { + return status; + } + + status = updateDataByType(newDerived, nodeTypeV,EdgeLabelEnum.CAPABILITIES_PROPERTIES, nodeToUpdate); if (status != StorageOperationStatus.OK) { return status; } - // TODO - // status = updateDataByType(newDerived, nodeTypeV, - // EdgeLabelEnum.CAPABILITIES_PROPERTIES, capa); - // if ( status != StorageOperationStatus.OK){ - // return status; - // } - status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.ADDITIONAL_INFORMATION, AdditionalInfoParameterDataDefinition.class); + status = updateDataByType(newDerived, nodeTypeV, EdgeLabelEnum.ADDITIONAL_INFORMATION, nodeToUpdate); return status; } - private StorageOperationStatus updateDataByType(GraphVertex newDerived, GraphVertex nodeTypeV, EdgeLabelEnum label, Class clazz) { + private StorageOperationStatus updateDataByType(List newDerivedList, GraphVertex nodeTypeV, EdgeLabelEnum label, NodeType nodeElement) { log.debug("Update data from derived for element {} type {}", nodeTypeV.getUniqueId(), label); Either dataFromGraph = getDataVertex(nodeTypeV, label); if (dataFromGraph.isRight()) { + if (TitanOperationStatus.NOT_FOUND == dataFromGraph.right().value()) + return associateDerivedDataByType(label, nodeTypeV, nodeElement, newDerivedList); return DaoStatusConverter.convertTitanStatusToStorageStatus(dataFromGraph.right().value()); } GraphVertex dataV = dataFromGraph.left().value(); @@ -749,16 +791,19 @@ public class NodeTypeOperation extends ToscaElementOperation { Map mapFromGraph = (Map) dataV.getJson(); mapFromGraph.entrySet().removeIf(e -> e.getValue().getOwnerId() != null); - List derivedList = new ArrayList<>(); - derivedList.add(newDerived); - - Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedList, clazz, EdgeLabelEnum.CAPABILITIES); + + Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(newDerivedList, label); if (dataFromDerived.isRight()) { return dataFromDerived.right().value(); } - Map capabiltiesAll = dataFromDerived.left().value(); - capabiltiesAll.putAll(mapFromGraph); - + Map dataFromDerivedAll = dataFromDerived.left().value(); + + Either, String> merged = ToscaDataDefinition.mergeDataMaps(dataFromDerivedAll, mapFromGraph); + if(merged.isRight()){ + log.debug("property {} cannot be overriden", merged.right().value()); + return StorageOperationStatus.INVALID_PROPERTY; + } + dataV.setJson(dataFromDerivedAll); Either updateDataV = updateOrCopyOnUpdate(dataV, nodeTypeV, label); if (updateDataV.isRight()) { return DaoStatusConverter.convertTitanStatusToStorageStatus(updateDataV.right().value()); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/TopologyTemplateOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/TopologyTemplateOperation.java index 62d04edf4f..0389c2739a 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/TopologyTemplateOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/TopologyTemplateOperation.java @@ -6,6 +6,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.Map.Entry; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; @@ -20,7 +22,6 @@ import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition; import org.openecomp.sdc.be.datatypes.elements.CompositionDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapArtifactDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.MapAttributesDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapCapabiltyProperty; import org.openecomp.sdc.be.datatypes.elements.MapGroupsDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapListCapabiltyDataDefinition; @@ -31,6 +32,7 @@ import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.DistributionStatusEnum; import org.openecomp.sdc.be.model.User; @@ -117,6 +119,12 @@ public class TopologyTemplateOperation extends ToscaElementOperation { result = Either.right(associateInstInputs); return result; } + StorageOperationStatus associateInstGroups = associateInstGroupsToComponent(topologyTemplateVertex, topologyTemplate); + if (associateInstProperties != StorageOperationStatus.OK) { + result = Either.right(associateInstInputs); + return result; + } + StorageOperationStatus associateRequirements = associateRequirementsToResource(topologyTemplateVertex, topologyTemplate); if (associateRequirements != StorageOperationStatus.OK) { result = Either.right(associateRequirements); @@ -251,6 +259,12 @@ public class TopologyTemplateOperation extends ToscaElementOperation { Map instProps = topologyTemplate.getInstInputs(); return associateInstInputsToComponent(nodeTypeVertex, instProps); } + + public StorageOperationStatus associateInstGroupsToComponent(GraphVertex nodeTypeVertex, TopologyTemplate topologyTemplate) { + Map instGroups = topologyTemplate.getInstGroups(); + return associateInstGroupsToComponent(nodeTypeVertex, instGroups); + } + public StorageOperationStatus associateInstPropertiesToComponent(GraphVertex nodeTypeVertex, Map instProps) { if (instProps != null && !instProps.isEmpty()) { @@ -271,21 +285,18 @@ public class TopologyTemplateOperation extends ToscaElementOperation { } return StorageOperationStatus.OK; } - - public StorageOperationStatus addInstInputsToComponent(GraphVertex nodeTypeVertex, Map instInputs) { - - if (instInputs != null && !instInputs.isEmpty()) { - instInputs.entrySet().forEach(i -> { - StorageOperationStatus status = addToscaDataDeepElementsBlockToToscaElement(nodeTypeVertex, EdgeLabelEnum.INST_INPUTS, VertexTypeEnum.INST_INPUTS, i.getValue(), i.getKey()); - if (status != StorageOperationStatus.OK) { - return; - } - }); + + public StorageOperationStatus associateInstGroupsToComponent(GraphVertex nodeTypeVertex, Map instGroups) { + if (instGroups != null && !instGroups.isEmpty()) { + Either assosiateElementToData = assosiateElementToData(nodeTypeVertex, VertexTypeEnum.INST_GROUPS, EdgeLabelEnum.INST_GROUPS, instGroups); + if (assosiateElementToData.isRight()) { + return assosiateElementToData.right().value(); + } } - return StorageOperationStatus.OK; } + public StorageOperationStatus deleteInstInputsToComponent(GraphVertex nodeTypeVertex, Map instInputs) { if (instInputs != null && !instInputs.isEmpty()) { @@ -361,11 +372,11 @@ public class TopologyTemplateOperation extends ToscaElementOperation { } private StorageOperationStatus associateInstAttributesToComponent(GraphVertex nodeTypeVertex, TopologyTemplate topologyTemplate) { - Map instAttr = topologyTemplate.getInstAttributes(); + Map instAttr = topologyTemplate.getInstAttributes(); return associateInstAttributeToComponent(nodeTypeVertex, instAttr); } - public StorageOperationStatus associateInstAttributeToComponent(GraphVertex nodeTypeVertex, Map instAttr) { + public StorageOperationStatus associateInstAttributeToComponent(GraphVertex nodeTypeVertex, Map instAttr) { if (instAttr != null && !instAttr.isEmpty()) { Either assosiateElementToData = assosiateElementToData(nodeTypeVertex, VertexTypeEnum.INST_ATTRIBUTES, EdgeLabelEnum.INST_ATTRIBUTES, instAttr); if (assosiateElementToData.isRight()) { @@ -953,6 +964,7 @@ public class TopologyTemplateOperation extends ToscaElementOperation { if (instances != null && instances.getComponentInstances() != null && !instances.getComponentInstances().isEmpty()) { for (ComponentInstanceDataDefinition ci : instances.getComponentInstances().values()) { if (ci.getComponentUid().equals(elementV.getUniqueId())) { + log.debug("The resource {} failed to delete cause in use as component instance UniqueID = {} in {} with UniqueID {}", elementV.getUniqueId(), ci.getUniqueId(), containerV.getType(), containerV.getUniqueId()); return true; } } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaElementLifecycleOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaElementLifecycleOperation.java index be995089a9..1397e81f9c 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaElementLifecycleOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaElementLifecycleOperation.java @@ -1,10 +1,13 @@ package org.openecomp.sdc.be.model.jsontitan.operations; +import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.Map.Entry; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; @@ -14,7 +17,9 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; + import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum; import org.openecomp.sdc.be.dao.jsongraph.types.EdgePropertyEnum; @@ -24,20 +29,39 @@ import org.openecomp.sdc.be.dao.jsongraph.utils.IdBuilderUtils; import org.openecomp.sdc.be.dao.jsongraph.utils.JsonParserUtils; import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.CompositionDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.GroupInstanceDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.MapArtifactDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.MapDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.MapGroupsDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.MapPropertiesDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; +import org.openecomp.sdc.be.model.ArtifactDefinition; import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.GroupDefinition; import org.openecomp.sdc.be.model.LifecycleStateEnum; import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.jsontitan.datamodel.TopologyTemplate; import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElement; +import org.openecomp.sdc.be.model.jsontitan.datamodel.ToscaElementTypeEnum; +import org.openecomp.sdc.be.model.jsontitan.enums.JsonConstantKeysEnum; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; import org.openecomp.sdc.common.jsongraph.util.CommonUtility; import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum; +import org.openecomp.sdc.exception.ResponseFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,20 +70,19 @@ import fj.data.Either; @org.springframework.stereotype.Component("tosca-element-lifecycle-operation") /** - * Allows to perform lifecycle operations: - * checkin, checkout, submit for testing, start certification and certification process - * for tosca element + * Allows to perform lifecycle operations: checkin, checkout, submit for testing, start certification and certification process for tosca element */ public class ToscaElementLifecycleOperation extends BaseOperation { - + private static final String FAILED_TO_GET_VERTICES = "Failed to get vertices by id {}. Status is {}. "; public static final String VERSION_DELIMETER = "."; public static final String VERSION_DELIMETER_REGEXP = "\\."; - + private static Logger logger = LoggerFactory.getLogger(ToscaElementLifecycleOperation.class.getName()); /** - * Performs changing a lifecycle state of tosca element from "checked out" or "ready for certification" to "checked in" + * Performs changing a lifecycle state of tosca element from "checked out" or "ready for certification" to "checked in" + * * @param currState * @param toscaElementId * @param modifierId @@ -72,109 +95,115 @@ public class ToscaElementLifecycleOperation extends BaseOperation { Map vertices = null; ToscaElementOperation operation; try { - Either, TitanOperationStatus> getVerticesRes = - titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForCheckin(toscaElementId, modifierId, ownerId)); - if(getVerticesRes.isRight()){ + Either, TitanOperationStatus> getVerticesRes = titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForCheckin(toscaElementId, modifierId, ownerId)); + if (getVerticesRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId); updateResult = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getVerticesRes.right().value())); } else { vertices = getVerticesRes.left().value(); updateResult = checkinToscaELement(currState, vertices.get(toscaElementId), vertices.get(ownerId), vertices.get(modifierId), LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); } - if(updateResult.isLeft()) { + if (updateResult.isLeft()) { ComponentParametersView componentParametersView = buildComponentParametersViewAfterCheckin(); operation = getToscaElementOperation(vertices.get(toscaElementId).getLabel()); result = operation.getToscaElement(updateResult.left().value().getUniqueId(), componentParametersView); - if(result.isRight()){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to get updated tosca element {}. Status is {}", toscaElementId, result.right().value()); + if (result.isRight()) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to get updated tosca element {}. Status is {}", toscaElementId, result.right().value()); } } else { result = Either.right(updateResult.right().value()); } - } catch (Exception e){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Exception occured during checkin of tosca element {}. {} ", toscaElementId, e.getMessage()); + } catch (Exception e) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during checkin of tosca element {}. {} ", toscaElementId, e.getMessage()); } return result; } + /** * Returns vertex presenting owner of tosca element specified by uniqueId + * * @param toscaElement * @return */ public Either getToscaElementOwner(String toscaElementId) { - Either result = null; + Either result = null; GraphVertex toscaElement = null; Either getToscaElementRes = titanDao.getVertexById(toscaElementId, JsonParseFlagEnum.NoParse); - if(getToscaElementRes.isRight()){ + if (getToscaElementRes.isRight()) { result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getToscaElementRes.right().value())); } - if(result == null){ + if (result == null) { toscaElement = getToscaElementRes.left().value(); Iterator vertices = toscaElement.getVertex().vertices(Direction.IN, EdgeLabelEnum.STATE.name()); - if(vertices == null || !vertices.hasNext()){ + if (vertices == null || !vertices.hasNext()) { result = Either.right(StorageOperationStatus.NOT_FOUND); } else { result = Either.left(convertToUser(vertices.next())); } } - return result; - } + return result; + } + /** * Returns vertex presenting owner of tosca element specified by uniqueId + * * @param toscaElement * @return */ public Either getToscaElementOwner(GraphVertex toscaElement) { - Either result = null; + Either result = null; Iterator vertices = toscaElement.getVertex().vertices(Direction.IN, EdgeLabelEnum.STATE.name()); - if(vertices == null || !vertices.hasNext()){ + if (vertices == null || !vertices.hasNext()) { result = Either.right(StorageOperationStatus.NOT_FOUND); } else { result = Either.left(convertToUser(vertices.next())); } - return result; - } + return result; + } -/** - * Performs checkout of a tosca element - * @param toscaElementId - * @param modifierId - * @param ownerId - * @param currState - * @return - */ + /** + * Performs checkout of a tosca element + * + * @param toscaElementId + * @param modifierId + * @param ownerId + * @param currState + * @return + */ public Either checkoutToscaElement(String toscaElementId, String modifierId, String ownerId) { Either result = null; Map vertices = null; - try{ - Either, TitanOperationStatus> getVerticesRes = - titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForCheckout(toscaElementId, modifierId, ownerId)); - if(getVerticesRes.isRight()){ + try { + Either, TitanOperationStatus> getVerticesRes = titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForCheckout(toscaElementId, modifierId, ownerId)); + if (getVerticesRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getVerticesRes.right().value())); } - if(result == null){ + if (result == null) { vertices = getVerticesRes.left().value(); // update previous component if not certified StorageOperationStatus status = updatePreviousVersion(vertices.get(toscaElementId), vertices.get(ownerId)); - if(status != StorageOperationStatus.OK){ + if (status != StorageOperationStatus.OK) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to update vertex with id {} . Status is {}. ", status); result = Either.right(status); } } - if(result == null){ + if (result == null) { result = cloneToscaElementForCheckout(vertices.get(toscaElementId), vertices.get(modifierId)); if (result.isRight()) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to checkout tosca element {}. Status is {} ", toscaElementId, result.right().value()); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to checkout tosca element {}. Status is {} ", toscaElementId, result.right().value()); } + } - } catch (Exception e){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Exception occured during checkout tosca element {}. {}", toscaElementId, e.getMessage()); + } catch (Exception e) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during checkout tosca element {}. {}", toscaElementId, e.getMessage()); } return result; } + /** * Performs undo checkout for tosca element + * * @param toscaElementId * @return */ @@ -185,44 +214,45 @@ public class ToscaElementLifecycleOperation extends BaseOperation { ToscaElementOperation operation; try { getToscaElementRes = titanDao.getVertexById(toscaElementId, JsonParseFlagEnum.ParseMetadata); - if(getToscaElementRes.isRight()){ + if (getToscaElementRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getToscaElementRes.right().value())); } - if(result == null && hasPreviousVersion(getToscaElementRes.left().value())){ + if (result == null && hasPreviousVersion(getToscaElementRes.left().value())) { // find previous version nextVersionComponentIter = getToscaElementRes.left().value().getVertex().edges(Direction.IN, EdgeLabelEnum.VERSION.name()); - if(nextVersionComponentIter == null || !nextVersionComponentIter.hasNext()){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to fetch previous version of tosca element with name {}. ", - getToscaElementRes.left().value().getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME).toString()); - result = Either.right(StorageOperationStatus.NOT_FOUND); + if (nextVersionComponentIter == null || !nextVersionComponentIter.hasNext()) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to fetch previous version of tosca element with name {}. ", getToscaElementRes.left().value().getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME).toString()); + result = Either.right(StorageOperationStatus.NOT_FOUND); } - if(result == null){ + if (result == null) { StorageOperationStatus updateOldResourceResult = updateOldToscaElementBeforeUndoCheckout(nextVersionComponentIter.next().outVertex()); if (updateOldResourceResult != StorageOperationStatus.OK) { result = Either.right(updateOldResourceResult); } } } - if(result == null){ + if (result == null) { operation = getToscaElementOperation(getToscaElementRes.left().value().getLabel()); result = operation.deleteToscaElement(getToscaElementRes.left().value()); } - } catch(Exception e){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Exception occured during undo checkout tosca element {}. {}", toscaElementId, e.getMessage()); + } catch (Exception e) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during undo checkout tosca element {}. {}", toscaElementId, e.getMessage()); } - return result; + return result; } - + private boolean hasPreviousVersion(GraphVertex toscaElementVertex) { boolean hasPreviousVersion = true; String version = (String) toscaElementVertex.getMetadataProperty(GraphPropertyEnum.VERSION); - if(StringUtils.isEmpty(version) || version.equals("0.1")) + if (StringUtils.isEmpty(version) || version.equals("0.1")) hasPreviousVersion = false; return hasPreviousVersion; } + /** * Performs request certification for tosca element + * * @param toscaElementId * @param modifierId * @param ownerId @@ -235,49 +265,48 @@ public class ToscaElementLifecycleOperation extends BaseOperation { GraphVertex modifier = null; GraphVertex owner; try { - Either, TitanOperationStatus> getVerticesRes = - titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId)); - if(getVerticesRes.isRight()){ + Either, TitanOperationStatus> getVerticesRes = titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId)); + if (getVerticesRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getVerticesRes.right().value())); } - if(result == null){ + if (result == null) { toscaElement = getVerticesRes.left().value().get(toscaElementId); modifier = getVerticesRes.left().value().get(modifierId); owner = getVerticesRes.left().value().get(ownerId); - + StorageOperationStatus status = handleRelationsUponRequestForCertification(toscaElement, modifier, owner); - if(status != StorageOperationStatus.OK){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to handle relations on certification request for tosca element {}. Status is {}. ", - toscaElement.getUniqueId(), status); + if (status != StorageOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to handle relations on certification request for tosca element {}. Status is {}. ", toscaElement.getUniqueId(), status); } } - if(result == null){ + if (result == null) { LifecycleStateEnum nextState = LifecycleStateEnum.READY_FOR_CERTIFICATION; - + toscaElement.addMetadataProperty(GraphPropertyEnum.STATE, nextState.name()); toscaElement.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, System.currentTimeMillis()); - + resultUpdate = updateToscaElementVertexMetadataPropertiesAndJson(toscaElement); if (resultUpdate.isRight()) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to set lifecycle for tosca elememt {} to state {}, error: {}", toscaElement.getUniqueId(), nextState, resultUpdate.right().value()); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to set lifecycle for tosca elememt {} to state {}, error: {}", toscaElement.getUniqueId(), nextState, resultUpdate.right().value()); result = Either.right(resultUpdate.right().value()); } } - if(result == null){ + if (result == null) { ToscaElementOperation operation = getToscaElementOperation(toscaElement.getLabel()); result = operation.getToscaElement(toscaElement.getUniqueId()); } return result; - } catch (Exception e){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Exception occured during request certification tosca element {}. {}", toscaElementId, e.getMessage()); + } catch (Exception e) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during request certification tosca element {}. {}", toscaElementId, e.getMessage()); } return result; } - + /** * Starts certification of tosca element + * * @param toscaElementId * @param modifierId * @param ownerId @@ -290,45 +319,43 @@ public class ToscaElementLifecycleOperation extends BaseOperation { GraphVertex modifier = null; GraphVertex owner; try { - Either, TitanOperationStatus> getVerticesRes = - titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId)); - if(getVerticesRes.isRight()){ + Either, TitanOperationStatus> getVerticesRes = titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId)); + if (getVerticesRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getVerticesRes.right().value())); } - if(result == null){ + if (result == null) { toscaElement = getVerticesRes.left().value().get(toscaElementId); modifier = getVerticesRes.left().value().get(modifierId); owner = getVerticesRes.left().value().get(ownerId); - + StorageOperationStatus status = handleRelationsUponCertification(toscaElement, modifier, owner); - if(status != StorageOperationStatus.OK){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to handle relations during certification of tosca element {}. Status is {}. ", - toscaElement.getUniqueId(), status); + if (status != StorageOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to handle relations during certification of tosca element {}. Status is {}. ", toscaElement.getUniqueId(), status); } } - if(result == null){ + if (result == null) { LifecycleStateEnum nextState = LifecycleStateEnum.CERTIFICATION_IN_PROGRESS; - + toscaElement.addMetadataProperty(GraphPropertyEnum.STATE, nextState.name()); toscaElement.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, System.currentTimeMillis()); - + resultUpdate = updateToscaElementVertexMetadataPropertiesAndJson(toscaElement); if (resultUpdate.isRight()) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Couldn't set lifecycle for component {} to state {}, error: {}", toscaElement.getUniqueId(), nextState, resultUpdate.right().value()); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Couldn't set lifecycle for component {} to state {}, error: {}", toscaElement.getUniqueId(), nextState, resultUpdate.right().value()); result = Either.right(resultUpdate.right().value()); } } - if(result == null){ + if (result == null) { ToscaElementOperation operation = getToscaElementOperation(toscaElement.getLabel()); result = operation.getToscaElement(toscaElement.getUniqueId()); } - } catch (Exception e){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Exception occured during start certification tosca element {}. {}", toscaElementId, e.getMessage()); + } catch (Exception e) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during start certification tosca element {}. {}", toscaElementId, e.getMessage()); } return result; } - + public Either certifyToscaElement(String toscaElementId, String modifierId, String ownerId) { Either result = null; Either cloneRes = null; @@ -339,53 +366,52 @@ public class ToscaElementLifecycleOperation extends BaseOperation { StorageOperationStatus status; try { - Either, TitanOperationStatus> getVerticesRes = - titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId)); - if(getVerticesRes.isRight()){ + Either, TitanOperationStatus> getVerticesRes = titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId)); + if (getVerticesRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getVerticesRes.right().value())); } - if(result == null){ + if (result == null) { toscaElement = getVerticesRes.left().value().get(toscaElementId); modifier = getVerticesRes.left().value().get(modifierId); majorVersion = getMajorVersion((String) toscaElement.getMetadataProperty(GraphPropertyEnum.VERSION)); status = handleRelationsOfPreviousToscaElementBeforeCertifying(toscaElement, modifier, majorVersion); - if(status != StorageOperationStatus.OK){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to handle relations of previous tosca element before certifying {}. Status is {}. ", - toscaElement.getUniqueId(), status); + if (status != StorageOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to handle relations of previous tosca element before certifying {}. Status is {}. ", toscaElement.getUniqueId(), status); } } - if(result == null){ + if (result == null) { cloneRes = cloneToscaElementForCertify(toscaElement, modifier, majorVersion); if (cloneRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to clone tosca element during certification. "); result = Either.right(cloneRes.right().value()); } } - if(result == null){ + if (result == null) { certifiedToscaElement = cloneRes.left().value(); status = handleRelationsOfNewestCertifiedToscaElement(toscaElement, certifiedToscaElement); - if(status != StorageOperationStatus.OK){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to handle relations of newest certified tosca element {}. Status is {}. ", - certifiedToscaElement.getUniqueId(), status); + if (status != StorageOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to handle relations of newest certified tosca element {}. Status is {}. ", certifiedToscaElement.getUniqueId(), status); } } - if(result == null){ - return getToscaElementOperation(toscaElement.getLabel()).getToscaElement(certifiedToscaElement.getUniqueId()); + if (result == null) { + return getToscaElementOperation(toscaElement.getLabel()).getToscaElement(certifiedToscaElement.getUniqueId()); } - } catch (Exception e){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Exception occured during certification tosca element {}. {}", toscaElementId, e.getMessage()); + } catch (Exception e) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during certification tosca element {}. {}", toscaElementId, e.getMessage()); } return result; } -/** - * Deletes (marks as deleted) all tosca elements according received name and uuid - * @param vertexType - * @param componentType - * @param componentName - * @param uuid - * @return - */ + + /** + * Deletes (marks as deleted) all tosca elements according received name and uuid + * + * @param vertexType + * @param componentType + * @param componentName + * @param uuid + * @return + */ public Either deleteOldToscaElementVersions(VertexTypeEnum vertexType, ComponentTypeEnum componentType, String componentName, String uuid) { Either result = null; @@ -395,29 +421,31 @@ public class ToscaElementLifecycleOperation extends BaseOperation { Map properties = new EnumMap<>(GraphPropertyEnum.class); properties.put(GraphPropertyEnum.UUID, uuid); properties.put(GraphPropertyEnum.NAME, componentName); - Either, TitanOperationStatus> getToscaElementsRes= titanDao.getByCriteria(vertexType, properties, JsonParseFlagEnum.ParseMetadata); + Either, TitanOperationStatus> getToscaElementsRes = titanDao.getByCriteria(vertexType, properties, JsonParseFlagEnum.ParseMetadata); if (getToscaElementsRes.isRight()) { result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getToscaElementsRes.right().value())); } - if(result == null){ + if (result == null) { result = markToscaElementsAsDeleted(operation, getToscaElementsRes.left().value()); } - if(result == null){ + if (result == null) { result = Either.left(true); } - } catch (Exception e){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Exception occured during deleteng all tosca elements by UUID {} and name {}. {} ", uuid, componentName, e.getMessage()); + } catch (Exception e) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during deleteng all tosca elements by UUID {} and name {}. {} ", uuid, componentName, e.getMessage()); } return result; } -/** - * Performs cancelation or failure of certification for received tosca element - * @param toscaElementId - * @param modifierId - * @param ownerId - * @param nextState - * @return - */ + + /** + * Performs cancelation or failure of certification for received tosca element + * + * @param toscaElementId + * @param modifierId + * @param ownerId + * @param nextState + * @return + */ public Either cancelOrFailCertification(String toscaElementId, String modifierId, String ownerId, LifecycleStateEnum nextState) { Either result = null; StorageOperationStatus status; @@ -425,60 +453,56 @@ public class ToscaElementLifecycleOperation extends BaseOperation { GraphVertex toscaElement = null; GraphVertex modifier = null; try { - Either, TitanOperationStatus> getVerticesRes = - titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId)); - if(getVerticesRes.isRight()){ + Either, TitanOperationStatus> getVerticesRes = titanDao.getVerticesByUniqueIdAndParseFlag(prepareParametersToGetVerticesForRequestCertification(toscaElementId, modifierId, ownerId)); + if (getVerticesRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getVerticesRes.right().value())); } - if(result == null){ + if (result == null) { toscaElement = getVerticesRes.left().value().get(toscaElementId); modifier = getVerticesRes.left().value().get(modifierId); operation = getToscaElementOperation(toscaElement.getLabel()); toscaElement.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, System.currentTimeMillis()); toscaElement.setJsonMetadataField(JsonPresentationFields.USER_ID_LAST_UPDATER, modifier.getUniqueId()); toscaElement.addMetadataProperty(GraphPropertyEnum.STATE, nextState.name()); - + Either updateVertexRes = titanDao.updateVertex(toscaElement); - if(updateVertexRes.isRight()){ + if (updateVertexRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to update vertex {} . Status is {}. ", toscaElementId, updateVertexRes.right().value()); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(updateVertexRes.right().value())); } } - if(result == null){ - // cancel certification process + if (result == null) { + // cancel certification process status = handleRelationsUponCancelCertification(toscaElement, nextState); - if(status != StorageOperationStatus.OK){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to handle relations upon cancel certification {}. Status is {}. ", - toscaElement.getUniqueId(), status); + if (status != StorageOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to handle relations upon cancel certification {}. Status is {}. ", toscaElement.getUniqueId(), status); } } - if(result == null){ - // fail certification + if (result == null) { + // fail certification status = handleRelationsUponFailCertification(toscaElement, nextState); - if(status != StorageOperationStatus.OK){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to handle relations upon fail certification {}. Status is {}. ", - toscaElement.getUniqueId(), status); + if (status != StorageOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to handle relations upon fail certification {}. Status is {}. ", toscaElement.getUniqueId(), status); } - } + } if (result == null) { result = operation.getToscaElement(toscaElementId); } - } catch (Exception e){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Exception occured during cancel or fail certification of tosca element {}. {}. ", - toscaElementId, e.getMessage()); + } catch (Exception e) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during cancel or fail certification of tosca element {}. {}. ", toscaElementId, e.getMessage()); } return result; } - + public Either findUser(String userId) { return findUserVertex(userId); } - - private Either markToscaElementsAsDeleted(ToscaElementOperation operation, List toscaElements) { + + private Either markToscaElementsAsDeleted(ToscaElementOperation operation, List toscaElements) { Either result = Either.left(true); for (GraphVertex resourceToDelete : toscaElements) { - if(!((String)resourceToDelete.getJsonMetadataField(JsonPresentationFields.LIFECYCLE_STATE)).equals(LifecycleStateEnum.CERTIFIED.name())){ + if (!((String) resourceToDelete.getJsonMetadataField(JsonPresentationFields.LIFECYCLE_STATE)).equals(LifecycleStateEnum.CERTIFIED.name())) { Either deleteElementRes = operation.markComponentToDelete(resourceToDelete); if (deleteElementRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete tosca element {}. Status is {}. ", resourceToDelete.getUniqueId(), deleteElementRes.right().value()); @@ -489,7 +513,6 @@ public class ToscaElementLifecycleOperation extends BaseOperation { } return result; } - private StorageOperationStatus handleRelationsOfNewestCertifiedToscaElement(GraphVertex toscaElement, GraphVertex certifiedToscaElement) { StorageOperationStatus result = null; @@ -498,46 +521,53 @@ public class ToscaElementLifecycleOperation extends BaseOperation { // add rfc relation to preserve follower information // get user of certification request certReqUserEdgeIter = toscaElement.getVertex().edges(Direction.IN, GraphEdgeLabels.LAST_STATE.name()); - if(certReqUserEdgeIter == null || !certReqUserEdgeIter.hasNext()){ + if (certReqUserEdgeIter == null || !certReqUserEdgeIter.hasNext()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to find rfc relation during certification clone. "); result = StorageOperationStatus.NOT_FOUND; } + if (result == null) { + TitanOperationStatus createVersionEdgeStatus = titanDao.createEdge(toscaElement, certifiedToscaElement, EdgeLabelEnum.VERSION, new HashMap<>()); + if (createVersionEdgeStatus != TitanOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to create version edge from last element {} to new certified element {}. status=", toscaElement.getUniqueId(),certifiedToscaElement.getUniqueId(), createVersionEdgeStatus); + result = DaoStatusConverter.convertTitanStatusToStorageStatus(createVersionEdgeStatus); + } + } if(result == null){ - - while(certReqUserEdgeIter.hasNext()){ + + while (certReqUserEdgeIter.hasNext()) { Edge edge = certReqUserEdgeIter.next(); - if(((String)titanDao.getProperty(edge, EdgePropertyEnum.STATE)).equals(LifecycleStateEnum.READY_FOR_CERTIFICATION.name()) ){ + if (((String) titanDao.getProperty(edge, EdgePropertyEnum.STATE)).equals(LifecycleStateEnum.READY_FOR_CERTIFICATION.name())) { foundEdge = edge; break; } - + } - if(foundEdge == null){ + if (foundEdge == null) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to find rfc relation during certification clone. "); result = StorageOperationStatus.NOT_FOUND; } } - if(result == null){ + if (result == null) { TitanOperationStatus createEdgeRes = titanDao.createEdge(foundEdge.outVertex(), certifiedToscaElement.getVertex(), EdgeLabelEnum.LAST_STATE, foundEdge); if (createEdgeRes != TitanOperationStatus.OK) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to create rfc relation for component {}. status=", certifiedToscaElement.getUniqueId(), createEdgeRes); result = DaoStatusConverter.convertTitanStatusToStorageStatus(createEdgeRes); } } - if(result == null){ + if (result == null) { result = StorageOperationStatus.OK; } return result; } - + private StorageOperationStatus handleRelationsUponFailCertification(GraphVertex toscaElement, LifecycleStateEnum nextState) { StorageOperationStatus result = null; TitanOperationStatus status = null; Edge originEdge; Vertex user = null; - if(nextState == LifecycleStateEnum.NOT_CERTIFIED_CHECKIN){ - // fail certification - // delete relation CERTIFICATION_IN_PROGRESS + if (nextState == LifecycleStateEnum.NOT_CERTIFIED_CHECKIN) { + // fail certification + // delete relation CERTIFICATION_IN_PROGRESS Map properties = new EnumMap<>(GraphPropertyEnum.class); properties.put(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS); @@ -547,29 +577,29 @@ public class ToscaElementLifecycleOperation extends BaseOperation { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete state edge. Status is {}. ", status); result = StorageOperationStatus.INCONSISTENCY; } - if(result == null){ - // delete relation READY_FOR_CERTIFICATION + if (result == null) { + // delete relation READY_FOR_CERTIFICATION properties.put(GraphPropertyEnum.STATE, LifecycleStateEnum.READY_FOR_CERTIFICATION); deleteResult = titanDao.deleteBelongingEdgeByCriteria(toscaElement, EdgeLabelEnum.LAST_STATE, properties); - if(deleteResult.isRight()){ + if (deleteResult.isRight()) { status = deleteResult.right().value(); CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete last state edge. Status is {}. ", status); result = StorageOperationStatus.INCONSISTENCY; } } - if(result == null){ - // delete relation NOT_CERTIFIED_CHECKIN (in order to change to STATE) + if (result == null) { + // delete relation NOT_CERTIFIED_CHECKIN (in order to change to STATE) properties.put(GraphPropertyEnum.STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); deleteResult = titanDao.deleteBelongingEdgeByCriteria(toscaElement, EdgeLabelEnum.LAST_STATE, properties); - if(deleteResult.isRight()){ + if (deleteResult.isRight()) { status = deleteResult.right().value(); CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete last state edge. Status is {}. ", status); result = StorageOperationStatus.INCONSISTENCY; } } - if(result == null){ + if (result == null) { // create new STATE relation NOT_CERTIFIED_CHECKIN - originEdge = deleteResult.left().value(); + originEdge = deleteResult.left().value(); user = originEdge.outVertex(); status = titanDao.createEdge(user, toscaElement.getVertex(), EdgeLabelEnum.STATE, originEdge); if (status != TitanOperationStatus.OK) { @@ -577,17 +607,17 @@ public class ToscaElementLifecycleOperation extends BaseOperation { result = StorageOperationStatus.INCONSISTENCY; } } - if(result == null){ - // delete relation LAST_MODIFIER (in order to change tester to designer) + if (result == null) { + // delete relation LAST_MODIFIER (in order to change tester to designer) deleteResult = titanDao.deleteBelongingEdgeByCriteria(toscaElement, EdgeLabelEnum.LAST_MODIFIER, new HashMap<>()); if (status != TitanOperationStatus.OK) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to create last modifier edge. Status is {}. ", status); result = StorageOperationStatus.INCONSISTENCY; } } - if(result == null){ + if (result == null) { // create new LAST_MODIFIER relation - originEdge = deleteResult.left().value(); + originEdge = deleteResult.left().value(); status = titanDao.createEdge(user, toscaElement.getVertex(), EdgeLabelEnum.LAST_MODIFIER, originEdge); if (status != TitanOperationStatus.OK) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to create last modifier edge. Status is {}. ", status); @@ -595,7 +625,7 @@ public class ToscaElementLifecycleOperation extends BaseOperation { } } } - if(result == null){ + if (result == null) { result = StorageOperationStatus.OK; } return result; @@ -604,27 +634,27 @@ public class ToscaElementLifecycleOperation extends BaseOperation { private StorageOperationStatus handleRelationsUponCancelCertification(GraphVertex toscaElement, LifecycleStateEnum nextState) { StorageOperationStatus result = null; Edge originEdge; - if(nextState == LifecycleStateEnum.READY_FOR_CERTIFICATION){ - // delete relation CERTIFICATION_IN_PROGRESS + if (nextState == LifecycleStateEnum.READY_FOR_CERTIFICATION) { + // delete relation CERTIFICATION_IN_PROGRESS Map properties = new EnumMap<>(GraphPropertyEnum.class); properties.put(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS); Either deleteResult = titanDao.deleteBelongingEdgeByCriteria(toscaElement, EdgeLabelEnum.STATE, properties); - + if (deleteResult.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete state edge. Status is {}. ", deleteResult.right().value()); result = StorageOperationStatus.INCONSISTENCY; } - if(result == null){ + if (result == null) { // delete relation READY_FOR_CERTIFICATION (LAST_STATE) properties.put(GraphPropertyEnum.STATE, nextState); deleteResult = titanDao.deleteBelongingEdgeByCriteria(toscaElement, EdgeLabelEnum.LAST_STATE, properties); - + if (deleteResult.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete last state edge. Status is {}. ", deleteResult.right().value()); result = StorageOperationStatus.INCONSISTENCY; } } - if(result == null){ + if (result == null) { // create relation READY_FOR_CERTIFICATION (STATE) originEdge = deleteResult.left().value(); TitanOperationStatus status = titanDao.createEdge(originEdge.outVertex(), toscaElement.getVertex(), EdgeLabelEnum.STATE, originEdge); @@ -633,43 +663,43 @@ public class ToscaElementLifecycleOperation extends BaseOperation { result = StorageOperationStatus.INCONSISTENCY; } } - if(result == null){ + if (result == null) { result = StorageOperationStatus.OK; } } return result; } - private StorageOperationStatus handleRelationsOfPreviousToscaElementBeforeCertifying(GraphVertex toscaElement, GraphVertex modifier, Integer majorVersion) { + private StorageOperationStatus handleRelationsOfPreviousToscaElementBeforeCertifying(GraphVertex toscaElement, GraphVertex modifier, Integer majorVersion) { StorageOperationStatus result = null; if (majorVersion > 0) { Either findRes = findLastCertifiedToscaElementVertex(toscaElement); - if(findRes.isRight()){ + if (findRes.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to fetch last certified tosca element {} . Status is {}. ", toscaElement.getMetadataProperty(GraphPropertyEnum.NAME), findRes.right().value()); result = findRes.right().value(); } - if(result == null){ + if (result == null) { Vertex lastCertifiedVertex = findRes.left().value(); Map properties = new EnumMap<>(GraphPropertyEnum.class); properties.put(GraphPropertyEnum.IS_HIGHEST_VERSION, false); TitanOperationStatus status = titanDao.updateVertexMetadataPropertiesWithJson(lastCertifiedVertex, properties); if (status != TitanOperationStatus.OK) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to set highest version of tosca element {} to [{}]. Status is {}", toscaElement.getUniqueId(), false, status); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to set highest version of tosca element {} to [{}]. Status is {}", toscaElement.getUniqueId(), false, status); result = DaoStatusConverter.convertTitanStatusToStorageStatus(status); } } } - if(result == null){ + if (result == null) { result = StorageOperationStatus.OK; } return result; } - + private StorageOperationStatus handleRelationsUponRequestForCertification(GraphVertex toscaElement, GraphVertex modifier, GraphVertex owner) { TitanOperationStatus status; StorageOperationStatus result = null; - - if (((String)toscaElement.getMetadataProperty(GraphPropertyEnum.STATE)).equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())) { + + if (((String) toscaElement.getMetadataProperty(GraphPropertyEnum.STATE)).equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())) { // remove CHECKOUT relation Either deleteRes = titanDao.deleteEdge(owner, toscaElement, EdgeLabelEnum.STATE); if (deleteRes.isRight()) { @@ -677,7 +707,7 @@ public class ToscaElementLifecycleOperation extends BaseOperation { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete edge. Status is {}. ", status); result = DaoStatusConverter.convertTitanStatusToStorageStatus(status); } - if(result == null){ + if (result == null) { // create CHECKIN relation Map properties = new EnumMap<>(EdgePropertyEnum.class); properties.put(EdgePropertyEnum.STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); @@ -693,54 +723,54 @@ public class ToscaElementLifecycleOperation extends BaseOperation { result = DaoStatusConverter.convertTitanStatusToStorageStatus(status); } } - if(result == null){ + if (result == null) { // create RFC relation Map properties = new EnumMap<>(EdgePropertyEnum.class); properties.put(EdgePropertyEnum.STATE, LifecycleStateEnum.READY_FOR_CERTIFICATION); status = titanDao.createEdge(modifier.getVertex(), toscaElement.getVertex(), EdgeLabelEnum.STATE, properties); if (status != TitanOperationStatus.OK) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to create edge. Status is {}", status); - result = DaoStatusConverter.convertTitanStatusToStorageStatus(status); + result = DaoStatusConverter.convertTitanStatusToStorageStatus(status); } } - if(result == null){ + if (result == null) { result = StorageOperationStatus.OK; } return result; } - - private StorageOperationStatus handleRelationsUponCertification(GraphVertex toscaElement, GraphVertex modifier, GraphVertex owner) { + + private StorageOperationStatus handleRelationsUponCertification(GraphVertex toscaElement, GraphVertex modifier, GraphVertex owner) { StorageOperationStatus result = null; TitanOperationStatus status = titanDao.replaceEdgeLabel(owner.getVertex(), toscaElement.getVertex(), EdgeLabelEnum.STATE, EdgeLabelEnum.LAST_STATE); if (status != TitanOperationStatus.OK) { result = DaoStatusConverter.convertTitanStatusToStorageStatus(status); } - if(result == null){ + if (result == null) { Map properties = new EnumMap<>(EdgePropertyEnum.class); properties.put(EdgePropertyEnum.STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS); status = titanDao.createEdge(modifier, toscaElement, EdgeLabelEnum.STATE, properties); if (status != TitanOperationStatus.OK) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"failed to create edge. Status is {}", status); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "failed to create edge. Status is {}", status); result = DaoStatusConverter.convertTitanStatusToStorageStatus(status); } } - if(result == null){ + if (result == null) { result = StorageOperationStatus.OK; } return result; } - + private Either findLastCertifiedToscaElementVertex(GraphVertex toscaElement) { return findLastCertifiedToscaElementVertexRecursively(toscaElement.getVertex()); } private Either findLastCertifiedToscaElementVertexRecursively(Vertex vertex) { - if(isCertifiedVersion((String)vertex.property(GraphPropertyEnum.VERSION.getProperty()).value())){ + if (isCertifiedVersion((String) vertex.property(GraphPropertyEnum.VERSION.getProperty()).value())) { return Either.left(vertex); } Iterator edgeIter = vertex.edges(Direction.IN, EdgeLabelEnum.VERSION.name()); - if(!edgeIter.hasNext()){ + if (!edgeIter.hasNext()) { return Either.right(StorageOperationStatus.NOT_FOUND); } return findLastCertifiedToscaElementVertexRecursively(edgeIter.next().outVertex()); @@ -748,131 +778,350 @@ public class ToscaElementLifecycleOperation extends BaseOperation { private boolean isCertifiedVersion(String version) { String[] versionParts = version.split(VERSION_DELIMETER_REGEXP); - if(Integer.parseInt(versionParts[0]) > 0 && Integer.parseInt(versionParts[1]) == 0){ + if (Integer.parseInt(versionParts[0]) > 0 && Integer.parseInt(versionParts[1]) == 0) { return true; } return false; } private StorageOperationStatus updateOldToscaElementBeforeUndoCheckout(Vertex previousVersionToscaElement) { - + StorageOperationStatus result = StorageOperationStatus.OK; String previousVersion = (String) previousVersionToscaElement.property(GraphPropertyEnum.VERSION.getProperty()).value(); if (!previousVersion.endsWith(".0")) { - try{ - CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to update vertex of previous version of tosca element", - previousVersionToscaElement.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty())); - + try { + CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to update vertex of previous version of tosca element", previousVersionToscaElement.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty())); + Map propertiesToUpdate = new HashMap<>(); propertiesToUpdate.put(GraphPropertyEnum.IS_HIGHEST_VERSION.getProperty(), true); - Map jsonMetadataMap = - JsonParserUtils.parseToJson((String)previousVersionToscaElement.property(GraphPropertyEnum.METADATA.getProperty()).value()); + Map jsonMetadataMap = JsonParserUtils.parseToJson((String) previousVersionToscaElement.property(GraphPropertyEnum.METADATA.getProperty()).value()); jsonMetadataMap.put(GraphPropertyEnum.IS_HIGHEST_VERSION.getProperty(), true); propertiesToUpdate.put(GraphPropertyEnum.METADATA.getProperty(), JsonParserUtils.jsonToString(jsonMetadataMap)); - + titanDao.setVertexProperties(previousVersionToscaElement, propertiesToUpdate); - + Iterator edgesIter = previousVersionToscaElement.edges(Direction.IN, EdgeLabelEnum.LAST_STATE.name()); - if(!edgesIter.hasNext()){ + if (!edgesIter.hasNext()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to fetch last modifier vertex for tosca element {}. ", previousVersionToscaElement.property(GraphPropertyEnum.NORMALIZED_NAME.getProperty())); result = StorageOperationStatus.NOT_FOUND; } else { Edge lastStateEdge = edgesIter.next(); Vertex lastModifier = lastStateEdge.outVertex(); - TitanOperationStatus replaceRes = - titanDao.replaceEdgeLabel(lastModifier, previousVersionToscaElement, lastStateEdge, EdgeLabelEnum.LAST_STATE, EdgeLabelEnum.STATE); + TitanOperationStatus replaceRes = titanDao.replaceEdgeLabel(lastModifier, previousVersionToscaElement, lastStateEdge, EdgeLabelEnum.LAST_STATE, EdgeLabelEnum.STATE); if (replaceRes != TitanOperationStatus.OK) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to replace label from {} to {}. status = {}", EdgeLabelEnum.LAST_STATE, EdgeLabelEnum.STATE, replaceRes); - result = StorageOperationStatus.INCONSISTENCY; + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to replace label from {} to {}. status = {}", EdgeLabelEnum.LAST_STATE, EdgeLabelEnum.STATE, replaceRes); + result = StorageOperationStatus.INCONSISTENCY; if (replaceRes != TitanOperationStatus.INVALID_ID) { result = DaoStatusConverter.convertTitanStatusToStorageStatus(replaceRes); } } } - } catch (Exception e){ + } catch (Exception e) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during update previous tosca element {} before undo checkout. {} ", e.getMessage()); } } return result; } + private StorageOperationStatus updatePreviousVersion(GraphVertex toscaElementVertex, GraphVertex ownerVertex) { StorageOperationStatus result = null; String ownerId = (String) ownerVertex.getMetadataProperty(GraphPropertyEnum.USERID); String toscaElementId = toscaElementVertex.getUniqueId(); - if(!toscaElementVertex.getMetadataProperty(GraphPropertyEnum.STATE).equals(LifecycleStateEnum.CERTIFIED.name())){ + if (!toscaElementVertex.getMetadataProperty(GraphPropertyEnum.STATE).equals(LifecycleStateEnum.CERTIFIED.name())) { toscaElementVertex.addMetadataProperty(GraphPropertyEnum.IS_HIGHEST_VERSION, false); Either updateVertexRes = titanDao.updateVertex(toscaElementVertex); if (updateVertexRes.isRight()) { TitanOperationStatus titatStatus = updateVertexRes.right().value(); - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, - "Failed to update tosca element vertex {}. Status is {}", toscaElementVertex.getUniqueId(), titatStatus); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to update tosca element vertex {}. Status is {}", toscaElementVertex.getUniqueId(), titatStatus); result = DaoStatusConverter.convertTitanStatusToStorageStatus(titatStatus); } Either deleteEdgeRes = null; - if(result == null){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE,"Going to replace edge with label {} to label {} from {} to {}. ", - EdgeLabelEnum.STATE , EdgeLabelEnum.LAST_STATE, ownerId, toscaElementId); - + if (result == null) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to replace edge with label {} to label {} from {} to {}. ", EdgeLabelEnum.STATE, EdgeLabelEnum.LAST_STATE, ownerId, toscaElementId); + deleteEdgeRes = titanDao.deleteEdge(ownerVertex, toscaElementVertex, EdgeLabelEnum.STATE); - if(deleteEdgeRes.isRight()){ + if (deleteEdgeRes.isRight()) { TitanOperationStatus titanStatus = deleteEdgeRes.right().value(); - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, - "Failed to delete edge with label {} from {} to {}. Status is {} ", - EdgeLabelEnum.STATE , EdgeLabelEnum.LAST_STATE, ownerId, toscaElementId, titanStatus); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete edge with label {} from {} to {}. Status is {} ", EdgeLabelEnum.STATE, EdgeLabelEnum.LAST_STATE, ownerId, toscaElementId, titanStatus); if (!titanStatus.equals(TitanOperationStatus.INVALID_ID)) { result = DaoStatusConverter.convertTitanStatusToStorageStatus(titanStatus); - } else{ + } else { result = StorageOperationStatus.INCONSISTENCY; } } } - if(result == null){ + if (result == null) { TitanOperationStatus createEdgeRes = titanDao.createEdge(ownerVertex.getVertex(), toscaElementVertex.getVertex(), EdgeLabelEnum.LAST_STATE, deleteEdgeRes.left().value()); - if(createEdgeRes != TitanOperationStatus.OK){ + if (createEdgeRes != TitanOperationStatus.OK) { result = DaoStatusConverter.convertTitanStatusToStorageStatus(createEdgeRes); } } } - if(result == null){ + if (result == null) { result = StorageOperationStatus.OK; } return result; } - - private Either cloneToscaElementForCheckout(GraphVertex toscaElementVertex, GraphVertex modifierVertex) { - + + private Either cloneToscaElementForCheckout(GraphVertex toscaElementVertex, GraphVertex modifierVertex) { + Either result = null; Either cloneResult = null; ToscaElementOperation operation = getToscaElementOperation(toscaElementVertex.getLabel()); // check if component with the next version doesn't exist. Iterator nextVersionComponentIter = toscaElementVertex.getVertex().edges(Direction.OUT, EdgeLabelEnum.VERSION.name()); - if(nextVersionComponentIter != null && nextVersionComponentIter.hasNext()){ + if (nextVersionComponentIter != null && nextVersionComponentIter.hasNext()) { String fetchedVersion = (String) nextVersionComponentIter.next().inVertex().property(GraphPropertyEnum.VERSION.getProperty()).value(); String fetchedName = (String) nextVersionComponentIter.next().inVertex().property(GraphPropertyEnum.NORMALIZED_NAME.getProperty()).value(); CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to checkout component {} with version {}. The component with name {} and version {} was fetched from graph as existing following version. ", toscaElementVertex.getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME).toString(), toscaElementVertex.getMetadataProperty(GraphPropertyEnum.VERSION).toString(), fetchedName, fetchedVersion); result = Either.right(StorageOperationStatus.ENTITY_ALREADY_EXISTS); } - if(result == null){ + if (result == null) { cloneResult = operation.cloneToscaElement(toscaElementVertex, cloneGraphVertexForCheckout(toscaElementVertex, modifierVertex), modifierVertex); - if(cloneResult.isRight()){ + if (cloneResult.isRight()) { result = Either.right(cloneResult.right().value()); } } + GraphVertex clonedVertex = null; if (result == null) { + clonedVertex = cloneResult.left().value(); TitanOperationStatus status = titanDao.createEdge(toscaElementVertex.getVertex(), cloneResult.left().value().getVertex(), EdgeLabelEnum.VERSION, new HashMap<>()); if (status != TitanOperationStatus.OK) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to create edge with label {} from vertex {} to tosca element vertex {} on graph. Status is {}. ", EdgeLabelEnum.VERSION, toscaElementVertex.getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME), - cloneResult.left().value().getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME), status); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to create edge with label {} from vertex {} to tosca element vertex {} on graph. Status is {}. ", EdgeLabelEnum.VERSION, + toscaElementVertex.getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME), cloneResult.left().value().getMetadataProperty(GraphPropertyEnum.NORMALIZED_NAME), status); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(status)); } } - if(result == null){ + if (result == null) { result = operation.getToscaElement(cloneResult.left().value().getUniqueId()); + if (result.isRight()) { + return result; + } + + ToscaElement toscaElement = result.left().value(); + if (toscaElement.getToscaType() == ToscaElementTypeEnum.TopologyTemplate) { + result = handleFixTopologyTemplate(toscaElementVertex, result, operation, clonedVertex, toscaElement); + } + } + return result; + } + + private Either handleFixTopologyTemplate(GraphVertex toscaElementVertex, Either result, ToscaElementOperation operation, GraphVertex clonedVertex, + ToscaElement toscaElement) { + TopologyTemplate topologyTemplate = (TopologyTemplate) toscaElement; + Map instInputs = topologyTemplate.getInstInputs(); + Map instGroups = topologyTemplate.getInstGroups(); + Map instArtifactsMap = topologyTemplate.getInstanceArtifacts(); + Map origCompMap = new HashMap<>(); + if (instInputs == null) { + instInputs = new HashMap<>(); + } + if (instGroups == null) { + instGroups = new HashMap<>(); + } + if (instArtifactsMap == null) { + instArtifactsMap = new HashMap<>(); + } + Map instancesMap = topologyTemplate.getComponentInstances(); + boolean isAddInstGroup = instGroups == null || instGroups.isEmpty(); + boolean needUpdateComposition = false; + + if (instancesMap != null && !instancesMap.isEmpty()) { + for (ComponentInstanceDataDefinition vfInst : instancesMap.values()) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "vfInst name is {} . OriginType {}. ", vfInst.getName(), vfInst.getOriginType()); + if (vfInst.getOriginType().name().equals(OriginTypeEnum.VF.name())) { + collectInstanceInputAndGroups(instInputs, instGroups, instArtifactsMap, origCompMap, isAddInstGroup, vfInst, clonedVertex); + } + needUpdateComposition = needUpdateComposition || fixToscaComponentName(vfInst, origCompMap); + if(needUpdateComposition){ + instancesMap.put(vfInst.getUniqueId(), vfInst); + } + } + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "before add to graph instInputs {} instGroups {} needUpdateComposition {}", instInputs, instGroups, needUpdateComposition); + if (!instInputs.isEmpty()) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "before add inst inputs {} ", instInputs == null ? 0 : instInputs.size()); + GraphVertex toscaDataVertex = null; + Either instInpVertexEither = titanDao.getChildVertex(toscaElementVertex, EdgeLabelEnum.INST_INPUTS, JsonParseFlagEnum.ParseJson); + if (instInpVertexEither.isLeft()) { + toscaDataVertex = instInpVertexEither.left().value(); + } + + StorageOperationStatus status = handleToscaData(clonedVertex, VertexTypeEnum.INST_INPUTS, EdgeLabelEnum.INST_INPUTS, toscaDataVertex, instInputs); + if (status != StorageOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to update instance inputs . Status is {}. ", status); + result = Either.right(status); + return result; + } + + } + if (!instGroups.isEmpty()) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "before add inst groups {} ", instGroups == null ? 0 : instGroups.size()); + GraphVertex toscaDataVertex = null; + Either instGrVertexEither = titanDao.getChildVertex(toscaElementVertex, EdgeLabelEnum.INST_GROUPS, JsonParseFlagEnum.ParseJson); + if (instGrVertexEither.isLeft()) { + toscaDataVertex = instGrVertexEither.left().value(); + } + + StorageOperationStatus status = handleToscaData(clonedVertex, VertexTypeEnum.INST_GROUPS, EdgeLabelEnum.INST_GROUPS, toscaDataVertex, instGroups); + if (status != StorageOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to update instance group . Status is {}. ", status); + result = Either.right(status); + return result; + } + + } + if (needUpdateComposition) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "before update Instances "); + Map jsonComposition = (Map) clonedVertex.getJson(); + CompositionDataDefinition compositionDataDefinition = jsonComposition.get(JsonConstantKeysEnum.COMPOSITION.getValue()); + compositionDataDefinition.setComponentInstances(instancesMap); + Either updateElement = titanDao.updateVertex(clonedVertex); + if (updateElement.isRight()) { + TitanOperationStatus status = updateElement.right().value(); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to update instances on metadata vertex . Status is {}. ", status); + result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(status)); + return result; + } + } + + result = operation.getToscaElement(clonedVertex.getUniqueId()); + + } else { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "RI map empty on component {}", toscaElement.getUniqueId()); } return result; } + private boolean fixToscaComponentName(ComponentInstanceDataDefinition vfInst, Map origCompMap) { + if (vfInst.getToscaComponentName() == null || vfInst.getToscaComponentName().isEmpty()) { + String ciUid = vfInst.getUniqueId(); + String origCompUid = vfInst.getComponentUid(); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "fixToscaComponentName:: Ri id {} . origin component id is {}. type is{} ", ciUid, origCompUid, vfInst.getOriginType()); + ToscaElement origComp = null; + if (!origCompMap.containsKey(origCompUid)) { + Either origCompEither; + if (vfInst.getOriginType() == null || vfInst.getOriginType().name().equals(OriginTypeEnum.VF.name())) { + origCompEither = topologyTemplateOperation.getToscaElement(origCompUid); + }else{ + origCompEither = nodeTypeOperation.getToscaElement(origCompUid); + } + if (origCompEither.isRight()) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to find orig component {} . Status is {}. ", origCompEither.right().value()); + return false; + } + origComp = origCompEither.left().value(); + origCompMap.put(origCompUid, origComp); + } else { + origComp = origCompMap.get(origCompUid); + } + String toscaName = (String) origComp.getMetadataValue(JsonPresentationFields.TOSCA_RESOURCE_NAME); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Origin component id is {}. toscaName {}", origCompUid, toscaName); + vfInst.setToscaComponentName(toscaName); + return true; + } + return false; + } + + private void collectInstanceInputAndGroups(Map instInputs, Map instGroups, Map instArtifactsMap, Map origCompMap, + boolean isAddInstGroup, ComponentInstanceDataDefinition vfInst, GraphVertex clonedVertex) { + String ciUid = vfInst.getUniqueId(); + String origCompUid = vfInst.getComponentUid(); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "collectInstanceInputAndGroups:: Ri id {} . origin component id is {}. ", ciUid, origCompUid); + TopologyTemplate origComp = null; + if (!origCompMap.containsKey(origCompUid)) { + Either origCompEither = topologyTemplateOperation.getToscaElement(origCompUid); + if (origCompEither.isRight()) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to find orig component {} . Status is {}. ", origCompEither.right().value()); + return; + } + origComp = (TopologyTemplate) origCompEither.left().value(); + origCompMap.put(origCompUid, origComp); + } else { + origComp = (TopologyTemplate) origCompMap.get(origCompUid); + } + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Orig component {}. ", origComp.getUniqueId()); + + Map origInputs = origComp.getInputs(); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Orig component inputs size {}. ", origInputs == null ? 0 : origInputs.size()); + if (origInputs != null) { + if (!instInputs.containsKey(ciUid)) { + MapPropertiesDataDefinition instProperties = new MapPropertiesDataDefinition(origInputs); + instInputs.put(ciUid, instProperties); + } else { + + MapPropertiesDataDefinition instInputMap = instInputs.get(ciUid); + Map instProp = instInputMap.getMapToscaDataDefinition(); + origInputs.forEach((propName, propMap) -> { + if (!instProp.containsKey(propName)) { + instProp.put(propName, propMap); + } + }); + } + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "ComponentInstanseInputs {}. ", instInputs.get(ciUid)); + } + + if (isAddInstGroup) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "before create group instance. "); + List filteredGroups = null; + + + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "check vf groups before filter. Size is {} ", filteredGroups == null ? 0 : filteredGroups.size()); + if (origComp.getGroups() != null && !origComp.getGroups().isEmpty()) { + filteredGroups = origComp.getGroups().values().stream().filter(g -> g.getType().equals(VF_MODULE)).collect(Collectors.toList()); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "check vf groups . Size is {} ", filteredGroups == null ? 0 : filteredGroups.size()); + } + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "check vf groups after filter. Size is {} ", filteredGroups == null ? 0 : filteredGroups.size()); + if (CollectionUtils.isNotEmpty(filteredGroups)) { + MapArtifactDataDefinition instArifacts = null; + if(!instArtifactsMap.containsKey(ciUid)){ + + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "istance artifacts not found "); + + Map deploymentArtifacts = origComp.getDeploymentArtifacts(); + + + instArifacts = new MapArtifactDataDefinition(deploymentArtifacts); + addToscaDataDeepElementsBlockToToscaElement(clonedVertex, EdgeLabelEnum.INST_DEPLOYMENT_ARTIFACTS, VertexTypeEnum.INST_DEPLOYMENT_ARTIFACTS, instArifacts, ciUid); + + instArtifactsMap.put(ciUid, instArifacts); + + }else{ + instArifacts = instArtifactsMap.get(ciUid); + } + + if(instArifacts != null){ + Map instDeplArtifMap = instArifacts.getMapToscaDataDefinition(); + + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "check group dep artifacts. Size is {} ", instDeplArtifMap == null ? 0 : instDeplArtifMap.values().size()); + Map groupInstanceToCreate = new HashMap<>(); + for(GroupDataDefinition group:filteredGroups){ + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "create new groupInstance {} ", group.getName()); + GroupInstanceDataDefinition groupInstance = buildGroupInstanceDataDefinition(group, vfInst); + List artifactsUid = new ArrayList<>(); + List artifactsId = new ArrayList<>(); + for (ArtifactDataDefinition artifact : instDeplArtifMap.values()) { + //CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "create new groupInstance {} ", artifact.getA); + Optional op = group.getArtifacts().stream().filter(p -> p.equals(artifact.getGeneratedFromId())).findAny(); + if (op.isPresent()) { + artifactsUid.add(artifact.getArtifactUUID()); + artifactsId.add(artifact.getUniqueId()); + + } + } + groupInstance.setGroupInstanceArtifacts(artifactsId); + groupInstance.setGroupInstanceArtifactsUuid(artifactsUid); + groupInstanceToCreate.put(groupInstance.getName(), groupInstance); + } + if (MapUtils.isNotEmpty(groupInstanceToCreate)) { + instGroups.put(vfInst.getUniqueId(), new MapGroupsDataDefinition(groupInstanceToCreate)); + + } + } + } + } + } + private GraphVertex cloneGraphVertexForCheckout(GraphVertex toscaElementVertex, GraphVertex modifierVertex) { GraphVertex nextVersionToscaElementVertex = new GraphVertex(); String uniqueId = UniqueIdBuilder.buildComponentUniqueId(); @@ -881,11 +1130,11 @@ public class ToscaElementLifecycleOperation extends BaseOperation { nextVersionToscaElementVertex.setUniqueId(uniqueId); nextVersionToscaElementVertex.setLabel(toscaElementVertex.getLabel()); nextVersionToscaElementVertex.setType(toscaElementVertex.getType()); - + nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.UNIQUE_ID, uniqueId); nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.COMPONENT_TYPE, nextVersionToscaElementVertex.getType().name()); String nextVersion = getNextVersion((String) toscaElementVertex.getMetadataProperty(GraphPropertyEnum.VERSION)); - if(isFirstCheckoutAfterCertification(nextVersion)){ + if (isFirstCheckoutAfterCertification(nextVersion)) { nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.UUID, IdBuilderUtils.generateUUID()); } nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.VERSION, nextVersion); @@ -895,7 +1144,7 @@ public class ToscaElementLifecycleOperation extends BaseOperation { if (toscaElementVertex.getType() == ComponentTypeEnum.SERVICE && toscaElementVertex.getMetadataProperty(GraphPropertyEnum.STATE).equals(LifecycleStateEnum.CERTIFIED.name())) { nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.DISTRIBUTION_STATUS, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.getValue()); } - if(!MapUtils.isEmpty(toscaElementVertex.getMetadataJson())){ + if (!MapUtils.isEmpty(toscaElementVertex.getMetadataJson())) { nextVersionToscaElementVertex.setMetadataJson(new HashMap(toscaElementVertex.getMetadataJson())); nextVersionToscaElementVertex.updateMetadataJsonWithCurrentMetadataProperties(); } @@ -904,73 +1153,70 @@ public class ToscaElementLifecycleOperation extends BaseOperation { nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, currTime); nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_CREATOR, modifierVertex.getUniqueId()); nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_LAST_UPDATER, modifierVertex.getUniqueId()); - if(toscaElementVertex.getType() == ComponentTypeEnum.SERVICE) { + if (toscaElementVertex.getType() == ComponentTypeEnum.SERVICE) { nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.CONFORMANCE_LEVEL, ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel()); } - - if(!MapUtils.isEmpty(toscaElementVertex.getJson())){ + + if (!MapUtils.isEmpty(toscaElementVertex.getJson())) { nextVersionToscaElementVertex.setJson(new HashMap(toscaElementVertex.getJson())); } return nextVersionToscaElementVertex; } - + private Either cloneToscaElementForCertify(GraphVertex toscaElementVertex, GraphVertex modifierVertex, Integer majorVersion) { Either result; Either, StorageOperationStatus> deleteResult = null; GraphVertex clonedToscaElement = null; result = getToscaElementOperation(toscaElementVertex.getLabel()).cloneToscaElement(toscaElementVertex, cloneGraphVertexForCertify(toscaElementVertex, modifierVertex, majorVersion), modifierVertex); - if(result.isRight()){ + if (result.isRight()) { CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to clone tosca element {} for certification. Sattus is {}. ", toscaElementVertex.getUniqueId(), result.right().value()); - } - else{ + } else { clonedToscaElement = result.left().value(); deleteResult = deleteAllPreviousNotCertifiedVersions(toscaElementVertex); - if(deleteResult.isRight()){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete all previous npt certified versions of tosca element {}. Status is {}. ", - toscaElementVertex.getUniqueId(), deleteResult.right().value()); + if (deleteResult.isRight()) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete all previous npt certified versions of tosca element {}. Status is {}. ", toscaElementVertex.getUniqueId(), deleteResult.right().value()); result = Either.right(deleteResult.right().value()); } } - if(result.isLeft()){ + if (result.isLeft()) { result = handlePreviousVersionRelation(clonedToscaElement, deleteResult.left().value(), majorVersion); } return result; } - + private Either handlePreviousVersionRelation(GraphVertex clonedToscaElement, List deletedVersions, Integer majorVersion) { Either result = null; Vertex previousCertifiedToscaElement = null; - if(majorVersion > 0){ - List firstMinorVersionVertex = deletedVersions.stream() - .filter(gv->getMinorVersion((String)gv.getMetadataProperty(GraphPropertyEnum.VERSION)) == 1).collect(Collectors.toList()); - - if(CollectionUtils.isEmpty(firstMinorVersionVertex)){ + if (majorVersion > 0) { + List firstMinorVersionVertex = deletedVersions.stream().filter(gv -> getMinorVersion((String) gv.getMetadataProperty(GraphPropertyEnum.VERSION)) == 1).collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(firstMinorVersionVertex)) { result = Either.right(StorageOperationStatus.NOT_FOUND); } else { previousCertifiedToscaElement = getPreviousCertifiedToscaElement(firstMinorVersionVertex.get(0)); - if(previousCertifiedToscaElement == null){ + if (previousCertifiedToscaElement == null) { result = Either.right(StorageOperationStatus.NOT_FOUND); } } - if(result == null){ + if (result == null) { TitanOperationStatus status = titanDao.createEdge(previousCertifiedToscaElement, clonedToscaElement.getVertex(), EdgeLabelEnum.VERSION, new HashMap<>()); if (status != TitanOperationStatus.OK) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to create edge with label {} from vertex {} to tosca element vertex {} on graph. Status is {}. ", EdgeLabelEnum.VERSION, previousCertifiedToscaElement.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), - clonedToscaElement.getUniqueId(), status); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to create edge with label {} from vertex {} to tosca element vertex {} on graph. Status is {}. ", EdgeLabelEnum.VERSION, + previousCertifiedToscaElement.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), clonedToscaElement.getUniqueId(), status); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(status)); } } } - if(result == null){ + if (result == null) { result = Either.left(clonedToscaElement); } return result; } private Vertex getPreviousCertifiedToscaElement(GraphVertex graphVertex) { - + Iterator edges = graphVertex.getVertex().edges(Direction.IN, EdgeLabelEnum.VERSION.name()); - if(edges.hasNext()){ + if (edges.hasNext()) { return edges.next().outVertex(); } return null; @@ -978,7 +1224,7 @@ public class ToscaElementLifecycleOperation extends BaseOperation { private Either, StorageOperationStatus> deleteAllPreviousNotCertifiedVersions(GraphVertex toscaElementVertex) { Either, StorageOperationStatus> result = null; - + ToscaElementOperation operation = getToscaElementOperation(toscaElementVertex.getLabel()); List previosVersions = null; Object uuid = toscaElementVertex.getMetadataProperty(GraphPropertyEnum.UUID); @@ -987,28 +1233,28 @@ public class ToscaElementLifecycleOperation extends BaseOperation { Map properties = new HashMap<>(); properties.put(GraphPropertyEnum.UUID, uuid); properties.put(GraphPropertyEnum.NAME, componentName); - Either, TitanOperationStatus> getToscaElementsRes= titanDao.getByCriteria(toscaElementVertex.getLabel(), properties, JsonParseFlagEnum.ParseMetadata); + Either, TitanOperationStatus> getToscaElementsRes = titanDao.getByCriteria(toscaElementVertex.getLabel(), properties, JsonParseFlagEnum.ParseMetadata); if (getToscaElementsRes.isRight()) { result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getToscaElementsRes.right().value())); } - if(result == null){ + if (result == null) { previosVersions = getToscaElementsRes.left().value(); Either deleteResult = markToscaElementsAsDeleted(operation, getToscaElementsRes.left().value()); - if(deleteResult.isRight()){ + if (deleteResult.isRight()) { result = Either.right(deleteResult.right().value()); } } - if(result == null){ + if (result == null) { result = Either.left(previosVersions); } - } catch (Exception e){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Exception occured during deleteng all tosca elements by UUID {} and name {}. {} ", uuid, componentName, e.getMessage()); + } catch (Exception e) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during deleteng all tosca elements by UUID {} and name {}. {} ", uuid, componentName, e.getMessage()); } return result; } private GraphVertex cloneGraphVertexForCertify(GraphVertex toscaElementVertex, GraphVertex modifierVertex, Integer majorVersion) { - + GraphVertex nextVersionToscaElementVertex = new GraphVertex(); String uniqueId = IdBuilderUtils.generateUniqueId(); Map metadataProperties = new HashMap<>(toscaElementVertex.getMetadataProperties()); @@ -1016,7 +1262,7 @@ public class ToscaElementLifecycleOperation extends BaseOperation { nextVersionToscaElementVertex.setUniqueId(uniqueId); nextVersionToscaElementVertex.setLabel(toscaElementVertex.getLabel()); nextVersionToscaElementVertex.setType(toscaElementVertex.getType()); - + nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.UNIQUE_ID, uniqueId); nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.COMPONENT_TYPE, nextVersionToscaElementVertex.getType().name()); nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.VERSION, (majorVersion + 1) + VERSION_DELIMETER + "0"); @@ -1026,20 +1272,20 @@ public class ToscaElementLifecycleOperation extends BaseOperation { nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, null); nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_CREATOR, modifierVertex.getUniqueId()); nextVersionToscaElementVertex.setJsonMetadataField(JsonPresentationFields.USER_ID_LAST_UPDATER, modifierVertex.getUniqueId()); - + if (toscaElementVertex.getType() == ComponentTypeEnum.SERVICE && toscaElementVertex.getMetadataProperty(GraphPropertyEnum.STATE).equals(LifecycleStateEnum.CERTIFIED)) { nextVersionToscaElementVertex.addMetadataProperty(GraphPropertyEnum.DISTRIBUTION_STATUS, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.getValue()); } - if(!MapUtils.isEmpty(toscaElementVertex.getMetadataJson())){ + if (!MapUtils.isEmpty(toscaElementVertex.getMetadataJson())) { nextVersionToscaElementVertex.setMetadataJson(new HashMap(toscaElementVertex.getMetadataJson())); nextVersionToscaElementVertex.updateMetadataJsonWithCurrentMetadataProperties(); } - if(!MapUtils.isEmpty(toscaElementVertex.getJson())){ + if (!MapUtils.isEmpty(toscaElementVertex.getJson())) { nextVersionToscaElementVertex.setJson(new HashMap(toscaElementVertex.getJson())); } return nextVersionToscaElementVertex; } - + private ComponentParametersView buildComponentParametersViewAfterCheckin() { ComponentParametersView componentParametersView = new ComponentParametersView(); componentParametersView.disableAll(); @@ -1050,141 +1296,141 @@ public class ToscaElementLifecycleOperation extends BaseOperation { private Either checkinToscaELement(LifecycleStateEnum currState, GraphVertex toscaElementVertex, GraphVertex ownerVertex, GraphVertex modifierVertex, LifecycleStateEnum nextState) { Either updateRelationsRes; Either result = changeStateToCheckedIn(currState, toscaElementVertex, ownerVertex, modifierVertex); - if(result.isLeft()) { + if (result.isLeft()) { toscaElementVertex.addMetadataProperty(GraphPropertyEnum.STATE, nextState.name()); toscaElementVertex.setJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE, System.currentTimeMillis()); result = updateToscaElementVertexMetadataPropertiesAndJson(toscaElementVertex); } - if(result.isLeft()){ + if (result.isLeft()) { updateRelationsRes = updateLastModifierEdge(toscaElementVertex, ownerVertex, modifierVertex); - if(updateRelationsRes.isRight()){ + if (updateRelationsRes.isRight()) { result = Either.right(updateRelationsRes.right().value()); } } return result; } - private Either updateToscaElementVertexMetadataPropertiesAndJson(GraphVertex toscaElementVertex){ - + private Either updateToscaElementVertexMetadataPropertiesAndJson(GraphVertex toscaElementVertex) { + Either result; - + Either updateVertexRes = titanDao.updateVertex(toscaElementVertex); if (updateVertexRes.isRight()) { TitanOperationStatus titatStatus = updateVertexRes.right().value(); - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to update state of tosca element vertex {} metadata. Status is {}", toscaElementVertex.getUniqueId(), titatStatus); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to update state of tosca element vertex {} metadata. Status is {}", toscaElementVertex.getUniqueId(), titatStatus); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titatStatus)); } else { result = Either.left(updateVertexRes.left().value()); } return result; } - + private Either changeStateToCheckedIn(LifecycleStateEnum currState, GraphVertex toscaElementVertex, GraphVertex ownerVertex, GraphVertex modifierVertex) { Either result = null; LifecycleStateEnum nextState = LifecycleStateEnum.NOT_CERTIFIED_CHECKIN; String faileToUpdateStateMsg = "Failed to update state of tosca element {}. Status is {}"; - + if (currState == LifecycleStateEnum.READY_FOR_CERTIFICATION) { - //In case of cancel "ready for certification" remove last state edge with "STATE" property equals to "NOT_CERTIFIED_CHECKIN" + // In case of cancel "ready for certification" remove last state edge with "STATE" property equals to "NOT_CERTIFIED_CHECKIN" Map vertexProperties = new HashMap<>(); vertexProperties.put(GraphPropertyEnum.STATE, nextState); - Either deleteResult = titanDao.deleteBelongingEdgeByCriteria(toscaElementVertex, EdgeLabelEnum.LAST_STATE, vertexProperties); + Either deleteResult = titanDao.deleteBelongingEdgeByCriteria(toscaElementVertex, EdgeLabelEnum.LAST_STATE, vertexProperties); if (deleteResult.isRight()) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,faileToUpdateStateMsg, toscaElementVertex.getUniqueId(), deleteResult.right().value()); - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"failed to update last state relation"); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, faileToUpdateStateMsg, toscaElementVertex.getUniqueId(), deleteResult.right().value()); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "failed to update last state relation"); result = Either.right(StorageOperationStatus.INCONSISTENCY); } } - if(result == null) { - //Remove CHECKOUT relation + if (result == null) { + // Remove CHECKOUT relation Either deleteEdgeResult = titanDao.deleteEdge(ownerVertex, toscaElementVertex, EdgeLabelEnum.STATE); if (deleteEdgeResult.isRight()) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,faileToUpdateStateMsg, toscaElementVertex.getUniqueId()); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, faileToUpdateStateMsg, toscaElementVertex.getUniqueId()); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(deleteEdgeResult.right().value())); } } - if(result == null) { - //Create CHECKIN relation + if (result == null) { + // Create CHECKIN relation Map edgeProperties = new HashMap<>(); edgeProperties.put(EdgePropertyEnum.STATE, nextState); TitanOperationStatus createEdgeRes = titanDao.createEdge(modifierVertex.getVertex(), toscaElementVertex.getVertex(), EdgeLabelEnum.STATE, edgeProperties); if (createEdgeRes != TitanOperationStatus.OK) { - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,faileToUpdateStateMsg, toscaElementVertex.getUniqueId()); + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, faileToUpdateStateMsg, toscaElementVertex.getUniqueId()); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(createEdgeRes)); } } - if(result == null) { + if (result == null) { result = Either.left(toscaElementVertex); } return result; } - private Either updateLastModifierEdge( GraphVertex toscaElementVertex, GraphVertex ownerVertex, GraphVertex modifierVertex) { + private Either updateLastModifierEdge(GraphVertex toscaElementVertex, GraphVertex ownerVertex, GraphVertex modifierVertex) { Either result = null; - if(!modifierVertex.getMetadataProperties().get(GraphPropertyEnum.USERID).equals(ownerVertex.getMetadataProperties().get(GraphPropertyEnum.USERID))){ + if (!modifierVertex.getMetadataProperties().get(GraphPropertyEnum.USERID).equals(ownerVertex.getMetadataProperties().get(GraphPropertyEnum.USERID))) { Either deleteEdgeRes = titanDao.deleteEdge(ownerVertex, toscaElementVertex, EdgeLabelEnum.LAST_MODIFIER); - if(deleteEdgeRes.isRight()){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to delete last modifier {} to tosca element {}. Edge type is {}", ownerVertex.getUniqueId(), ownerVertex.getUniqueId(), EdgeLabelEnum.LAST_MODIFIER); + if (deleteEdgeRes.isRight()) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete last modifier {} to tosca element {}. Edge type is {}", ownerVertex.getUniqueId(), ownerVertex.getUniqueId(), EdgeLabelEnum.LAST_MODIFIER); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(deleteEdgeRes.right().value())); } - if(result == null) { + if (result == null) { TitanOperationStatus createEdgeRes = titanDao.createEdge(modifierVertex.getVertex(), toscaElementVertex.getVertex(), EdgeLabelEnum.LAST_MODIFIER, new HashMap<>()); - - if(createEdgeRes != TitanOperationStatus.OK){ - CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG,"Failed to associate user {} to component {}. Edge type is {}", modifierVertex.getUniqueId(), ownerVertex.getUniqueId(), EdgeLabelEnum.LAST_MODIFIER); + + if (createEdgeRes != TitanOperationStatus.OK) { + CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to associate user {} to component {}. Edge type is {}", modifierVertex.getUniqueId(), ownerVertex.getUniqueId(), EdgeLabelEnum.LAST_MODIFIER); result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(createEdgeRes)); - } else{ + } else { result = Either.left(modifierVertex); } } - } else{ + } else { result = Either.left(ownerVertex); } return result; } - private Map> prepareParametersToGetVerticesForCheckin(String toscaElementId, String modifierId, String ownerId) { - Map> verticesToGetParameters = new HashMap<>(); + private Map> prepareParametersToGetVerticesForCheckin(String toscaElementId, String modifierId, String ownerId) { + Map> verticesToGetParameters = new HashMap<>(); verticesToGetParameters.put(toscaElementId, new ImmutablePair<>(GraphPropertyEnum.UNIQUE_ID, JsonParseFlagEnum.ParseMetadata)); - verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID,JsonParseFlagEnum.NoParse)); - verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID,JsonParseFlagEnum.NoParse)); + verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse)); + verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse)); return verticesToGetParameters; } - - private Map> prepareParametersToGetVerticesForRequestCertification(String toscaElementId, String modifierId, String ownerId) { - Map> verticesToGetParameters = new HashMap<>(); + + private Map> prepareParametersToGetVerticesForRequestCertification(String toscaElementId, String modifierId, String ownerId) { + Map> verticesToGetParameters = new HashMap<>(); verticesToGetParameters.put(toscaElementId, new ImmutablePair<>(GraphPropertyEnum.UNIQUE_ID, JsonParseFlagEnum.ParseAll)); - verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID,JsonParseFlagEnum.NoParse)); - verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID,JsonParseFlagEnum.NoParse)); + verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse)); + verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse)); return verticesToGetParameters; } - - private Map> prepareParametersToGetVerticesForCheckout(String toscaElementId, String modifierId, String ownerId) { - Map> verticesToGetParameters = new HashMap<>(); + + private Map> prepareParametersToGetVerticesForCheckout(String toscaElementId, String modifierId, String ownerId) { + Map> verticesToGetParameters = new HashMap<>(); verticesToGetParameters.put(toscaElementId, new ImmutablePair<>(GraphPropertyEnum.UNIQUE_ID, JsonParseFlagEnum.ParseAll)); - verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID,JsonParseFlagEnum.NoParse)); - verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID,JsonParseFlagEnum.NoParse)); + verticesToGetParameters.put(modifierId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse)); + verticesToGetParameters.put(ownerId, new ImmutablePair<>(GraphPropertyEnum.USERID, JsonParseFlagEnum.NoParse)); return verticesToGetParameters; } - + private String getNextVersion(String currVersion) { String[] versionParts = currVersion.split(VERSION_DELIMETER_REGEXP); Integer minorVersion = Integer.parseInt(versionParts[1]) + 1; return versionParts[0] + VERSION_DELIMETER + minorVersion; } - + private Integer getMinorVersion(String version) { String[] versionParts = version.split(VERSION_DELIMETER_REGEXP); return Integer.parseInt(versionParts[1]); } - + private Integer getMajorVersion(String version) { String[] versionParts = version.split(VERSION_DELIMETER_REGEXP); return Integer.parseInt(versionParts[0]); } - + private boolean isFirstCheckoutAfterCertification(String version) { - if(Integer.parseInt(version.split(VERSION_DELIMETER_REGEXP)[0]) != 0 && Integer.parseInt(version.split(VERSION_DELIMETER_REGEXP)[1]) == 1){ + if (Integer.parseInt(version.split(VERSION_DELIMETER_REGEXP)[0]) != 0 && Integer.parseInt(version.split(VERSION_DELIMETER_REGEXP)[1]) == 1) { return true; } return false; diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaElementOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaElementOperation.java index 95e65e1e82..699d9e0e9d 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaElementOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaElementOperation.java @@ -130,7 +130,7 @@ public abstract class ToscaElementOperation extends BaseOperation { Either result = null; GraphVertex createdToscaElementVertex = null; TitanOperationStatus status; - + Either createNextVersionRes = titanDao.createVertex(nextToscaElement); if (createNextVersionRes.isRight()) { status = createNextVersionRes.right().value(); @@ -182,7 +182,7 @@ public abstract class ToscaElementOperation extends BaseOperation { } } } - + if (result == null) { result = Either.left(createdToscaElementVertex); } else { @@ -203,6 +203,7 @@ public abstract class ToscaElementOperation extends BaseOperation { toscaElement.setLastUpdaterFullName(buildFullName(userV)); return TitanOperationStatus.OK; } + public String buildFullName(GraphVertex userV) { String fullName = (String) userV.getMetadataProperty(GraphPropertyEnum.FIRST_NAME); @@ -217,6 +218,7 @@ public abstract class ToscaElementOperation extends BaseOperation { } return fullName; } + protected TitanOperationStatus setCreatorFromGraph(GraphVertex componentV, ToscaElement toscaElement) { Either parentVertex = titanDao.getParentVertex(componentV, EdgeLabelEnum.CREATOR, JsonParseFlagEnum.NoParse); if (parentVertex.isRight()) { @@ -227,7 +229,7 @@ public abstract class ToscaElementOperation extends BaseOperation { String creatorUserId = (String) userV.getMetadataProperty(GraphPropertyEnum.USERID); toscaElement.setCreatorUserId(creatorUserId); toscaElement.setCreatorFullName(buildFullName(userV)); - + return TitanOperationStatus.OK; } @@ -318,7 +320,7 @@ public abstract class ToscaElementOperation extends BaseOperation { toscaElement.setLastUpdaterUserId(toscaElement.getCreatorUserId()); toscaElement.setLastUpdaterFullName(toscaElement.getCreatorFullName()); - + result = titanDao.createEdge(creatorVertex, nodeTypeVertex, EdgeLabelEnum.CREATOR, null); log.debug("After associating user {} to resource {}. Edge type is {} ", creatorVertex, nodeTypeVertex.getUniqueId(), EdgeLabelEnum.CREATOR); if (!result.equals(TitanOperationStatus.OK)) { @@ -472,9 +474,9 @@ public abstract class ToscaElementOperation extends BaseOperation { return StorageOperationStatus.OK; } - private StorageOperationStatus associatePropertiesToResource(GraphVertex nodeTypeVertex, ToscaElement nodeType, List derivedResources) { + protected StorageOperationStatus associatePropertiesToResource(GraphVertex nodeTypeVertex, ToscaElement nodeType, List derivedResources) { // Note : currently only one derived supported!!!! - Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, PropertyDataDefinition.class, EdgeLabelEnum.PROPERTIES); + Either, StorageOperationStatus> dataFromDerived = getDataFromDerived(derivedResources, EdgeLabelEnum.PROPERTIES); if (dataFromDerived.isRight()) { return dataFromDerived.right().value(); } @@ -488,13 +490,12 @@ public abstract class ToscaElementOperation extends BaseOperation { p.setUniqueId(uid); }); - Either, String> eitherMerged = PropertyDataDefinition.mergeProperties(propertiesAll, properties, false); + Either, String> eitherMerged = ToscaDataDefinition.mergeDataMaps(propertiesAll, properties); if (eitherMerged.isRight()) { // TODO re-factor error handling - moving BL to operation resulted in loss of info about the invalid property log.debug("property {} cannot be overriden", eitherMerged.right().value()); return StorageOperationStatus.INVALID_PROPERTY; } - } if (!propertiesAll.isEmpty()) { Either assosiateElementToData = assosiateElementToData(nodeTypeVertex, VertexTypeEnum.PROPERTIES, EdgeLabelEnum.PROPERTIES, propertiesAll); @@ -516,7 +517,7 @@ public abstract class ToscaElementOperation extends BaseOperation { return StorageOperationStatus.OK; } - protected Either, StorageOperationStatus> getDataFromDerived(List derivedResources, Class clazz, EdgeLabelEnum edge) { + protected Either, StorageOperationStatus> getDataFromDerived(List derivedResources, EdgeLabelEnum edge) { Map propertiesAll = new HashMap<>(); if (derivedResources != null && !derivedResources.isEmpty()) { @@ -575,10 +576,11 @@ public abstract class ToscaElementOperation extends BaseOperation { Map allVersion = new HashMap<>(); allVersion.put((String) componentV.getMetadataProperty(GraphPropertyEnum.VERSION), componentV.getUniqueId()); + ArrayList allChildrenAndParants = new ArrayList(); Either childResourceRes = titanDao.getChildVertex(componentV, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse); while (childResourceRes.isLeft()) { GraphVertex child = childResourceRes.left().value(); - allVersion.put((String) child.getMetadataProperty(GraphPropertyEnum.VERSION), child.getUniqueId()); + allChildrenAndParants.add(child); childResourceRes = titanDao.getChildVertex(child, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse); } TitanOperationStatus operationStatus = childResourceRes.right().value(); @@ -589,13 +591,18 @@ public abstract class ToscaElementOperation extends BaseOperation { Either parentResourceRes = titanDao.getParentVertex(componentV, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse); while (parentResourceRes.isLeft()) { GraphVertex parent = parentResourceRes.left().value(); - allVersion.put((String) parent.getMetadataProperty(GraphPropertyEnum.VERSION), parent.getUniqueId()); + allChildrenAndParants.add(parent); parentResourceRes = titanDao.getParentVertex(parent, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse); } operationStatus = parentResourceRes.right().value(); if (operationStatus != TitanOperationStatus.NOT_FOUND) { return operationStatus; } else { + allChildrenAndParants.stream().filter(vertex -> { + Boolean isDeleted = (Boolean) vertex.getMetadataProperty(GraphPropertyEnum.IS_DELETED); + return (isDeleted == null || isDeleted == false); + }).forEach(vertex -> allVersion.put((String) vertex.getMetadataProperty(GraphPropertyEnum.VERSION), vertex.getUniqueId())); + toscaElement.setAllVersions(allVersion); return TitanOperationStatus.OK; } @@ -1047,98 +1054,113 @@ public abstract class ToscaElementOperation extends BaseOperation { return status; } - - public Either, StorageOperationStatus> getElementCatalogData(ComponentTypeEnum componentType , ToscaElementTypeEnum toscaElement) { - Either, TitanOperationStatus> listOfHighestAndAllCertifiedComponents = this.getListOfHighestAndAllCertifiedComponents(componentType , toscaElement); - if (listOfHighestAndAllCertifiedComponents.isRight() && listOfHighestAndAllCertifiedComponents.right().value() != TitanOperationStatus.NOT_FOUND) { - return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(listOfHighestAndAllCertifiedComponents.right().value())); + public Either, StorageOperationStatus> getElementCatalogData(ComponentTypeEnum componentType, ToscaElementTypeEnum toscaElement, boolean isHighestVersions) { + Either, TitanOperationStatus> listOfComponents; + if (isHighestVersions) { + listOfComponents = getListOfHighestComponents(componentType, toscaElement); + } else { + listOfComponents = getListOfHighestAndAllCertifiedComponents(componentType, toscaElement); + } + if (listOfComponents.isRight() && listOfComponents.right().value() != TitanOperationStatus.NOT_FOUND) { + return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(listOfComponents.right().value())); } - List highestAndAllCertified = listOfHighestAndAllCertifiedComponents.left().value(); List result = new ArrayList<>(); - if (highestAndAllCertified != null && false == highestAndAllCertified.isEmpty()) { - for (GraphVertex vertexComponent : highestAndAllCertified) { - Either component = getLightComponent(vertexComponent, componentType, new ComponentParametersView(true)); - if (component.isRight()) { - log.debug("Failed to fetch ligth element for {} error {}", vertexComponent.getUniqueId(), component.right().value()); - return Either.right(component.right().value()); - } else { - result.add(component.left().value()); + if (listOfComponents.isLeft()) { + List highestAndAllCertified = listOfComponents.left().value(); + if (highestAndAllCertified != null && false == highestAndAllCertified.isEmpty()) { + for (GraphVertex vertexComponent : highestAndAllCertified) { + Either component = getLightComponent(vertexComponent, componentType, new ComponentParametersView(true)); + if (component.isRight()) { + log.debug("Failed to fetch ligth element for {} error {}", vertexComponent.getUniqueId(), component.right().value()); + return Either.right(component.right().value()); + } else { + result.add(component.left().value()); + } } } } return Either.left(result); } - - -public Either, TitanOperationStatus> getListOfHighestAndAllCertifiedComponents(ComponentTypeEnum componentType , ToscaElementTypeEnum toscaElement) { - long startFetchAllStates = System.currentTimeMillis(); - Map propertiesToMatchCertified = new HashMap<>(); - propertiesToMatchCertified.put(GraphPropertyEnum.STATE , LifecycleStateEnum.CERTIFIED.name()); - propertiesToMatchCertified.put(GraphPropertyEnum.COMPONENT_TYPE, componentType.name()); - if (componentType == ComponentTypeEnum.RESOURCE ){ - propertiesToMatchCertified.put(GraphPropertyEnum.IS_ABSTRACT, false); - } - Map propertiesHasNotToMatchCertified = new HashMap<>(); - propertiesHasNotToMatchCertified.put(GraphPropertyEnum.IS_DELETED, true); - - - Either, TitanOperationStatus> certifiedNodes = titanDao.getByCriteria(ToscaElementTypeEnum.getVertexTypeByToscaType(toscaElement) , propertiesToMatchCertified, propertiesHasNotToMatchCertified, JsonParseFlagEnum.ParseMetadata); - if (certifiedNodes.isRight() && certifiedNodes.right().value() != TitanOperationStatus.NOT_FOUND) { - return Either.right(certifiedNodes.right().value()); - } - - Map propertiesToMatchHighest = new HashMap<>(); - propertiesToMatchHighest.put(GraphPropertyEnum.IS_HIGHEST_VERSION , true); - propertiesToMatchHighest.put(GraphPropertyEnum.COMPONENT_TYPE, componentType.name()); - if (componentType == ComponentTypeEnum.RESOURCE ){ - propertiesToMatchHighest.put(GraphPropertyEnum.IS_ABSTRACT, false); - } + private Either, TitanOperationStatus> getListOfHighestComponents(ComponentTypeEnum componentType, ToscaElementTypeEnum toscaElement) { + Map propertiesToMatch = new HashMap<>(); + propertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, componentType.name()); + propertiesToMatch.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true); + if (componentType == ComponentTypeEnum.RESOURCE) { + propertiesToMatch.put(GraphPropertyEnum.IS_ABSTRACT, false); + } - Map propertiesHasNotToMatchHighest = new HashMap<>(); - propertiesHasNotToMatchHighest.put(GraphPropertyEnum.IS_DELETED, true); - propertiesHasNotToMatchHighest.put(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED.name()); - - - Either, TitanOperationStatus> highestNode = titanDao.getByCriteria(ToscaElementTypeEnum.getVertexTypeByToscaType(toscaElement) , propertiesToMatchHighest, propertiesHasNotToMatchHighest, JsonParseFlagEnum.ParseMetadata); - if (highestNode.isRight() && highestNode.right().value() != TitanOperationStatus.NOT_FOUND) { - return Either.right(highestNode.right().value()); - } - - long endFetchAllStates = System.currentTimeMillis(); - - - List allNodes = new ArrayList<>(); - - if (certifiedNodes.isLeft()) { - allNodes.addAll(certifiedNodes.left().value()); - } - if (highestNode.isLeft()){ - allNodes.addAll(highestNode.left().value()); - } - - int certifiedSize; - int nonCertifiedSize; - - if (certifiedNodes.isRight()){ - certifiedSize = 0; - } else { - certifiedSize = certifiedNodes.left().value().size(); - } - - if (highestNode.isRight()){ - nonCertifiedSize = 0; - } else { - nonCertifiedSize = highestNode.left().value().size(); + Map propertiesHasNotToMatch = new HashMap<>(); + propertiesHasNotToMatch.put(GraphPropertyEnum.IS_DELETED, true); + + return titanDao.getByCriteria(ToscaElementTypeEnum.getVertexTypeByToscaType(toscaElement), propertiesToMatch, propertiesHasNotToMatch, JsonParseFlagEnum.ParseMetadata); } - - - log.debug("Fetch catalog {}s all states: certified {}, noncertified {}", componentType, certifiedSize , nonCertifiedSize ); - log.debug("Fetch catalog {}s all states from graph took {} ms", componentType, endFetchAllStates - startFetchAllStates); - return Either.left(allNodes); -} + public Either, TitanOperationStatus> getListOfHighestAndAllCertifiedComponents(ComponentTypeEnum componentType, ToscaElementTypeEnum toscaElement) { + long startFetchAllStates = System.currentTimeMillis(); + Map propertiesToMatchCertified = new HashMap<>(); + propertiesToMatchCertified.put(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED.name()); + propertiesToMatchCertified.put(GraphPropertyEnum.COMPONENT_TYPE, componentType.name()); + if (componentType == ComponentTypeEnum.RESOURCE) { + propertiesToMatchCertified.put(GraphPropertyEnum.IS_ABSTRACT, false); + } + + Map propertiesHasNotToMatchCertified = new HashMap<>(); + propertiesHasNotToMatchCertified.put(GraphPropertyEnum.IS_DELETED, true); + + Either, TitanOperationStatus> certifiedNodes = titanDao.getByCriteria(ToscaElementTypeEnum.getVertexTypeByToscaType(toscaElement), propertiesToMatchCertified, propertiesHasNotToMatchCertified, + JsonParseFlagEnum.ParseMetadata); + if (certifiedNodes.isRight() && certifiedNodes.right().value() != TitanOperationStatus.NOT_FOUND) { + return Either.right(certifiedNodes.right().value()); + } + + Map propertiesToMatchHighest = new HashMap<>(); + propertiesToMatchHighest.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true); + propertiesToMatchHighest.put(GraphPropertyEnum.COMPONENT_TYPE, componentType.name()); + if (componentType == ComponentTypeEnum.RESOURCE) { + propertiesToMatchHighest.put(GraphPropertyEnum.IS_ABSTRACT, false); + } + + Map propertiesHasNotToMatchHighest = new HashMap<>(); + propertiesHasNotToMatchHighest.put(GraphPropertyEnum.IS_DELETED, true); + propertiesHasNotToMatchHighest.put(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED.name()); + + Either, TitanOperationStatus> highestNode = titanDao.getByCriteria(ToscaElementTypeEnum.getVertexTypeByToscaType(toscaElement), propertiesToMatchHighest, propertiesHasNotToMatchHighest, JsonParseFlagEnum.ParseMetadata); + if (highestNode.isRight() && highestNode.right().value() != TitanOperationStatus.NOT_FOUND) { + return Either.right(highestNode.right().value()); + } + + long endFetchAllStates = System.currentTimeMillis(); + + List allNodes = new ArrayList<>(); + + if (certifiedNodes.isLeft()) { + allNodes.addAll(certifiedNodes.left().value()); + } + if (highestNode.isLeft()) { + allNodes.addAll(highestNode.left().value()); + } + + int certifiedSize; + int nonCertifiedSize; + + if (certifiedNodes.isRight()) { + certifiedSize = 0; + } else { + certifiedSize = certifiedNodes.left().value().size(); + } + + if (highestNode.isRight()) { + nonCertifiedSize = 0; + } else { + nonCertifiedSize = highestNode.left().value().size(); + } + + log.debug("Fetch catalog {}s all states: certified {}, noncertified {}", componentType, certifiedSize, nonCertifiedSize); + log.debug("Fetch catalog {}s all states from graph took {} ms", componentType, endFetchAllStates - startFetchAllStates); + return Either.left(allNodes); + } protected Either, StorageOperationStatus> getAllComponentsMarkedForDeletion(ComponentTypeEnum componentType) { diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaOperationFacade.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaOperationFacade.java index 9c7f108a05..458bbbe226 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaOperationFacade.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/operations/ToscaOperationFacade.java @@ -24,14 +24,12 @@ import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.datatypes.components.ComponentMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition; import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListCapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListRequirementDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapArtifactDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.MapAttributesDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapCapabiltyProperty; import org.openecomp.sdc.be.datatypes.elements.MapListCapabiltyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.MapListRequirementDataDefinition; @@ -44,7 +42,6 @@ import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; import org.openecomp.sdc.be.model.ArtifactDefinition; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; @@ -100,12 +97,14 @@ public class ToscaOperationFacade { return getToscaElement(componentId, JsonParseFlagEnum.ParseAll); } + public Either getToscaFullElement(String componentId) { ComponentParametersView filters = new ComponentParametersView(); filters.setIgnoreCapabiltyProperties(false); - + return getToscaElement(componentId, filters); } + public Either getToscaElement(String componentId, ComponentParametersView filters) { Either getVertexEither = titanDao.getVertexById(componentId, filters.detectParseFlag()); @@ -657,25 +656,25 @@ public class ToscaOperationFacade { return getToscaElementByOperation(getResourceRes.left().value().get(0)); } - public Either, StorageOperationStatus> getCatalogComponents(ComponentTypeEnum componentType) { + public Either, StorageOperationStatus> getCatalogComponents(ComponentTypeEnum componentType, boolean isHighestVersions) { List components = new ArrayList<>(); Either, StorageOperationStatus> catalogDataResult; List toscaElements; switch (componentType) { case RESOURCE: - catalogDataResult = nodeTypeOperation.getElementCatalogData(ComponentTypeEnum.RESOURCE ,ToscaElementTypeEnum.NodeType); + catalogDataResult = nodeTypeOperation.getElementCatalogData(ComponentTypeEnum.RESOURCE, ToscaElementTypeEnum.NodeType, isHighestVersions); if (catalogDataResult.isRight()) { return Either.right(catalogDataResult.right().value()); } toscaElements = catalogDataResult.left().value(); - Either, StorageOperationStatus> resourceCatalogData = topologyTemplateOperation.getElementCatalogData(ComponentTypeEnum.RESOURCE ,ToscaElementTypeEnum.TopologyTemplate); + Either, StorageOperationStatus> resourceCatalogData = topologyTemplateOperation.getElementCatalogData(ComponentTypeEnum.RESOURCE, ToscaElementTypeEnum.TopologyTemplate, isHighestVersions); if (resourceCatalogData.isRight()) { return Either.right(resourceCatalogData.right().value()); } toscaElements.addAll(resourceCatalogData.left().value()); break; case SERVICE: - catalogDataResult = topologyTemplateOperation.getElementCatalogData(ComponentTypeEnum.SERVICE , ToscaElementTypeEnum.TopologyTemplate); + catalogDataResult = topologyTemplateOperation.getElementCatalogData(ComponentTypeEnum.SERVICE, ToscaElementTypeEnum.TopologyTemplate, isHighestVersions); if (catalogDataResult.isRight()) { return Either.right(catalogDataResult.right().value()); } @@ -1034,37 +1033,34 @@ public class ToscaOperationFacade { } - public Either>, StorageOperationStatus> addComponentInstanceInputsToComponent(Map> instProperties, String componentId) { - - Either getVertexEither = titanDao.getVertexById(componentId, JsonParseFlagEnum.NoParse); - if (getVertexEither.isRight()) { - log.debug("Couldn't fetch component with and unique id {}, error: {}", componentId, getVertexEither.right().value()); - return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getVertexEither.right().value())); - - } + public Either>, StorageOperationStatus> addComponentInstanceInputsToComponent(Component containerComponent, Map> instProperties) { - GraphVertex vertex = getVertexEither.left().value(); - Map instPropsMap = new HashMap<>(); + StorageOperationStatus status = StorageOperationStatus.OK; if (instProperties != null) { - MapPropertiesDataDefinition propertiesMap; for (Entry> entry : instProperties.entrySet()) { - propertiesMap = new MapPropertiesDataDefinition(); - - propertiesMap.setMapToscaDataDefinition(entry.getValue().stream().map(e -> new PropertyDataDefinition(e)).collect(Collectors.toMap(e -> e.getName(), e -> e))); - - instPropsMap.put(entry.getKey(), propertiesMap); + List props = entry.getValue(); + String componentInstanseId = entry.getKey(); + if (props != null && !props.isEmpty()) { + for (ComponentInstanceInput property : props) { + List componentInstancesInputs = containerComponent.getComponentInstancesInputs().get(componentInstanseId); + Optional instanceProperty = componentInstancesInputs.stream().filter(p -> p.getName().equals(property.getName())).findAny(); + if (instanceProperty.isPresent()) { + status = updateComponentInstanceInput(containerComponent, componentInstanseId, property); + } else { + status = addComponentInstanceInput(containerComponent, componentInstanseId, property); + } + if (status != StorageOperationStatus.OK) { + log.debug("Failed to update instance input {} for instance {} error {} ", property, componentInstanseId, status); + return Either.right(status); + } else { + log.trace("instance input {} for instance {} updated", property, componentInstanseId); + } + } + } } } - - StorageOperationStatus status = topologyTemplateOperation.addInstInputsToComponent(vertex, instPropsMap); - - if (StorageOperationStatus.OK == status) { - log.debug("Component created successfully!!!"); - return Either.left(instProperties); - } - return Either.right(status); - + return Either.left(instProperties); } public StorageOperationStatus deleteComponentInstanceInputsToComponent(Map> instProperties, String componentId) { @@ -1148,7 +1144,7 @@ public class ToscaOperationFacade { } - public StorageOperationStatus associateInstAttributeToComponentToInstances(Map> instArttributes, String componentId) { + public StorageOperationStatus associateInstAttributeToComponentToInstances(Map> instArttributes, String componentId) { Either getVertexEither = titanDao.getVertexById(componentId, JsonParseFlagEnum.NoParse); if (getVertexEither.isRight()) { @@ -1158,13 +1154,13 @@ public class ToscaOperationFacade { } GraphVertex vertex = getVertexEither.left().value(); - Map instAttr = new HashMap<>(); + Map instAttr = new HashMap<>(); if (instArttributes != null) { - MapAttributesDataDefinition attributesMap; - for (Entry> entry : instArttributes.entrySet()) { - attributesMap = new MapAttributesDataDefinition(); - attributesMap.setMapToscaDataDefinition(entry.getValue().stream().map(e -> new AttributeDataDefinition(e)).collect(Collectors.toMap(e -> e.getName(), e -> e))); + MapPropertiesDataDefinition attributesMap; + for (Entry> entry : instArttributes.entrySet()) { + attributesMap = new MapPropertiesDataDefinition(); + attributesMap.setMapToscaDataDefinition(entry.getValue().stream().map(e -> new PropertyDataDefinition(e)).collect(Collectors.toMap(e -> e.getName(), e -> e))); instAttr.put(entry.getKey(), attributesMap); } } @@ -1184,9 +1180,10 @@ public class ToscaOperationFacade { GraphVertex vertex = getVertexEither.left().value(); Map calcRequirements = new HashMap<>(); - + Map calcCapabilty = new HashMap<>(); - Map calculatedCapabilitiesProperties = new HashMap<>();; + Map calculatedCapabilitiesProperties = new HashMap<>(); + ; if (instCapabilties != null) { for (Entry>> entry : instCapabilties.entrySet()) { @@ -1200,7 +1197,7 @@ public class ToscaOperationFacade { MapListCapabiltyDataDefinition capMap = nodeTemplateOperation.prepareCalculatedCapabiltyForNodeType(mapToscaDataDefinition, componentInstance); MapCapabiltyProperty mapCapabiltyProperty = ModelConverter.convertToMapOfMapCapabiltyProperties(caps, componentInstance.getUniqueId(), true); - + calcCapabilty.put(entry.getKey().getUniqueId(), capMap); calculatedCapabilitiesProperties.put(entry.getKey().getUniqueId(), mapCapabiltyProperty); } @@ -1226,8 +1223,7 @@ public class ToscaOperationFacade { return status; } - private Either, StorageOperationStatus> getLatestVersionNotAbstractToscaElementsMetadataOnly(boolean isAbstract, Boolean isHighest, ComponentTypeEnum componentTypeEnum, String internalComponentType, - VertexTypeEnum vertexType) { + private Either, StorageOperationStatus> getLatestVersionNotAbstractToscaElementsMetadataOnly(boolean isAbstract, Boolean isHighest, ComponentTypeEnum componentTypeEnum, String internalComponentType, VertexTypeEnum vertexType) { Map hasProps = new EnumMap<>(GraphPropertyEnum.class); Map hasNotProps = new EnumMap<>(GraphPropertyEnum.class); @@ -1242,33 +1238,35 @@ public class ToscaOperationFacade { return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getRes.right().value())); } } else { - List nonAbstractLatestComponents = new ArrayList<>(); - ComponentParametersView params = new ComponentParametersView(true); - params.setIgnoreAllVersions(false); - for (GraphVertex vertexComponent : getRes.left().value()) { - Either componentRes = topologyTemplateOperation.getLightComponent(vertexComponent, componentTypeEnum, params); - if (componentRes.isRight()) { - log.debug("Failed to fetch ligth element for {} error {}", vertexComponent.getUniqueId(), componentRes.right().value()); - return Either.right(componentRes.right().value()); - } else { - Component component = ModelConverter.convertFromToscaElement(componentRes.left().value()); - - nonAbstractLatestComponents.add(component); - } - } + List nonAbstractLatestComponents = new ArrayList<>(); + ComponentParametersView params = new ComponentParametersView(true); + params.setIgnoreAllVersions(false); + for (GraphVertex vertexComponent : getRes.left().value()) { + Either componentRes = topologyTemplateOperation.getLightComponent(vertexComponent, componentTypeEnum, params); + if (componentRes.isRight()) { + log.debug("Failed to fetch ligth element for {} error {}", vertexComponent.getUniqueId(), componentRes.right().value()); + return Either.right(componentRes.right().value()); + } else { + Component component = ModelConverter.convertFromToscaElement(componentRes.left().value()); + + nonAbstractLatestComponents.add(component); + } + } return Either.left(nonAbstractLatestComponents); } } - public Either getLatestComponentMetadataByUuid(String componentUuid, JsonParseFlagEnum parseFlag) { + public Either getLatestComponentMetadataByUuid(String componentUuid, JsonParseFlagEnum parseFlag, Boolean isHighest) { Either result; Map hasProperties = new EnumMap<>(GraphPropertyEnum.class); hasProperties.put(GraphPropertyEnum.UUID, componentUuid); - hasProperties.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true); + if (isHighest != null) { + hasProperties.put(GraphPropertyEnum.IS_HIGHEST_VERSION, isHighest.booleanValue()); + } Map propertiesNotToMatch = new EnumMap<>(GraphPropertyEnum.class); propertiesNotToMatch.put(GraphPropertyEnum.IS_DELETED, true); @@ -1499,6 +1497,7 @@ public class ToscaOperationFacade { hasNotProps.put(GraphPropertyEnum.STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); hasNotProps.put(GraphPropertyEnum.IS_DELETED, true); + hasProps.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true); if (VertexTypeEnum.NODE_TYPE == internalVertexType) { hasProps.put(GraphPropertyEnum.IS_ABSTRACT, isAbstract); if (internalComponentType != null) { @@ -1533,21 +1532,21 @@ public class ToscaOperationFacade { return Either.left(result); } - + public Either, StorageOperationStatus> getLatestComponentListByUuid(String componentUuid) { Map propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); propertiesToMatch.put(GraphPropertyEnum.IS_HIGHEST_VERSION, true); return getComponentListByUuid(componentUuid, propertiesToMatch); } - + public Either, StorageOperationStatus> getComponentListByUuid(String componentUuid, Map additionalPropertiesToMatch) { - + Map propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); - - if(additionalPropertiesToMatch != null){ + + if (additionalPropertiesToMatch != null) { propertiesToMatch.putAll(additionalPropertiesToMatch); } - + propertiesToMatch.put(GraphPropertyEnum.UUID, componentUuid); Map propertiesNotToMatch = new EnumMap<>(GraphPropertyEnum.class); @@ -1781,14 +1780,14 @@ public class ToscaOperationFacade { } public Either updateDistributionStatus(Service service, User user, DistributionStatusEnum distributionStatus) { - Either updateDistributionStatus = topologyTemplateOperation.updateDistributionStatus(service.getUniqueId(), user, distributionStatus); - if ( updateDistributionStatus.isRight() ){ - return Either.right(updateDistributionStatus.right().value()); - } - GraphVertex serviceV = updateDistributionStatus.left().value(); - service.setDistributionStatus(distributionStatus); - service.setLastUpdateDate((Long) serviceV.getJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE)); - return Either.left(service); + Either updateDistributionStatus = topologyTemplateOperation.updateDistributionStatus(service.getUniqueId(), user, distributionStatus); + if (updateDistributionStatus.isRight()) { + return Either.right(updateDistributionStatus.right().value()); + } + GraphVertex serviceV = updateDistributionStatus.left().value(); + service.setDistributionStatus(distributionStatus); + service.setLastUpdateDate((Long) serviceV.getJsonMetadataField(JsonPresentationFields.LAST_UPDATE_DATE)); + return Either.left(service); } public Either updateComponentLastUpdateDateOnGraph(Component component, Long modificationTime) { @@ -1821,25 +1820,25 @@ public class ToscaOperationFacade { public TitanDao getTitanDao() { return titanDao; } - + public Either, StorageOperationStatus> getCertifiedServicesWithDistStatus(Set distStatus) { Map propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); propertiesToMatch.put(GraphPropertyEnum.STATE, LifecycleStateEnum.CERTIFIED.name()); - + return getServicesWithDistStatus(distStatus, propertiesToMatch); } - + public Either, StorageOperationStatus> getServicesWithDistStatus(Set distStatus, Map additionalPropertiesToMatch) { List servicesAll = new ArrayList<>(); Map propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); Map propertiesNotToMatch = new EnumMap<>(GraphPropertyEnum.class); - - if(additionalPropertiesToMatch != null && !additionalPropertiesToMatch.isEmpty()) { + + if (additionalPropertiesToMatch != null && !additionalPropertiesToMatch.isEmpty()) { propertiesToMatch.putAll(additionalPropertiesToMatch); } - + propertiesToMatch.put(GraphPropertyEnum.COMPONENT_TYPE, ComponentTypeEnum.SERVICE.name()); propertiesNotToMatch.put(GraphPropertyEnum.IS_DELETED, true); @@ -1848,10 +1847,9 @@ public class ToscaOperationFacade { for (DistributionStatusEnum state : distStatus) { propertiesToMatch.put(GraphPropertyEnum.DISTRIBUTION_STATUS, state.name()); Either, StorageOperationStatus> fetchServicesByCriteria = fetchServicesByCriteria(servicesAll, propertiesToMatch, propertiesNotToMatch); - if ( fetchServicesByCriteria.isRight() ){ + if (fetchServicesByCriteria.isRight()) { return fetchServicesByCriteria; - } - else{ + } else { servicesAll = fetchServicesByCriteria.left().value(); } } @@ -1861,6 +1859,27 @@ public class ToscaOperationFacade { } } + // private Either, StorageOperationStatus> fetchServicesByCriteria(List servicesAll, Map propertiesToMatch, Map propertiesNotToMatch) { + // Either, TitanOperationStatus> getRes = titanDao.getByCriteria(VertexTypeEnum.TOPOLOGY_TEMPLATE, propertiesToMatch, propertiesNotToMatch, JsonParseFlagEnum.ParseAll); + // if (getRes.isRight()) { + // if (getRes.right().value() != TitanOperationStatus.NOT_FOUND) { + // CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch certified services by match properties {} not match properties {} . Status is {}. ", propertiesToMatch, propertiesNotToMatch, getRes.right().value()); + // return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(getRes.right().value())); + // } + // } else { + // for (GraphVertex vertex : getRes.left().value()) { + // Either getServiceRes = getToscaElementByOperation(vertex); + // if (getServiceRes.isRight()) { + // CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch certified service {}. Status is {}. ", vertex.getJsonMetadataField(JsonPresentationFields.NAME), getServiceRes.right().value()); + // return Either.right(getServiceRes.right().value()); + // } else { + // servicesAll.add((Service) getToscaElementByOperation(vertex).left().value()); + // } + // } + // } + // return Either.left(servicesAll); + // } + private Either, StorageOperationStatus> fetchServicesByCriteria(List servicesAll, Map propertiesToMatch, Map propertiesNotToMatch) { Either, TitanOperationStatus> getRes = titanDao.getByCriteria(VertexTypeEnum.TOPOLOGY_TEMPLATE, propertiesToMatch, propertiesNotToMatch, JsonParseFlagEnum.ParseAll); if (getRes.isRight()) { @@ -1870,12 +1889,14 @@ public class ToscaOperationFacade { } } else { for (GraphVertex vertex : getRes.left().value()) { - Either getServiceRes = getToscaElementByOperation(vertex); + // Either getServiceRes = getToscaElementByOperation(vertex); + Either getServiceRes = topologyTemplateOperation.getLightComponent(vertex, ComponentTypeEnum.SERVICE, new ComponentParametersView(true)); + if (getServiceRes.isRight()) { CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to fetch certified service {}. Status is {}. ", vertex.getJsonMetadataField(JsonPresentationFields.NAME), getServiceRes.right().value()); return Either.right(getServiceRes.right().value()); } else { - servicesAll.add((Service) getToscaElementByOperation(vertex).left().value()); + servicesAll.add(ModelConverter.convertFromToscaElement(getServiceRes.left().value())); } } } @@ -1942,7 +1963,7 @@ public class ToscaOperationFacade { public StorageOperationStatus deletePropertyOfResource(Resource resource, String propertyName) { return getToscaElementOperation(resource).deleteToscaDataElement(resource.getUniqueId(), EdgeLabelEnum.PROPERTIES, VertexTypeEnum.PROPERTIES, propertyName, JsonPresentationFields.NAME); } - + public StorageOperationStatus deleteAttributeOfResource(Component component, String attributeName) { return getToscaElementOperation(component).deleteToscaDataElement(component.getUniqueId(), EdgeLabelEnum.ATTRIBUTES, VertexTypeEnum.ATTRIBUTES, attributeName, JsonPresentationFields.NAME); } @@ -1980,16 +2001,16 @@ public class ToscaOperationFacade { } return result; } - - public Either addAttributeOfResource(Component component, AttributeDefinition newAttributeDef) { + + public Either addAttributeOfResource(Component component, PropertyDefinition newAttributeDef) { Either getUpdatedComponentRes = null; - Either result = null; - if(newAttributeDef.getUniqueId() == null || newAttributeDef.getUniqueId().isEmpty()){ + Either result = null; + if (newAttributeDef.getUniqueId() == null || newAttributeDef.getUniqueId().isEmpty()) { String attUniqueId = UniqueIdBuilder.buildAttributeUid(component.getUniqueId(), newAttributeDef.getName()); newAttributeDef.setUniqueId(attUniqueId); } - + StorageOperationStatus status = getToscaElementOperation(component).addToscaDataToToscaElement(component.getUniqueId(), EdgeLabelEnum.ATTRIBUTES, VertexTypeEnum.ATTRIBUTES, newAttributeDef, JsonPresentationFields.NAME); if (status != StorageOperationStatus.OK) { CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to add the property {} to the resource {}. Status is {}. ", newAttributeDef.getName(), component.getName(), status); @@ -2005,7 +2026,7 @@ public class ToscaOperationFacade { } } if (result == null) { - Optional newAttribute = ((Resource) getUpdatedComponentRes.left().value()).getAttributes().stream().filter(p -> p.getName().equals(newAttributeDef.getName())).findAny(); + Optional newAttribute = ((Resource) getUpdatedComponentRes.left().value()).getAttributes().stream().filter(p -> p.getName().equals(newAttributeDef.getName())).findAny(); if (newAttribute.isPresent()) { result = Either.left(newAttribute.get()); } else { @@ -2015,11 +2036,11 @@ public class ToscaOperationFacade { } return result; } - - public Either updateAttributeOfResource(Component component, AttributeDefinition newAttributeDef) { + + public Either updateAttributeOfResource(Component component, PropertyDefinition newAttributeDef) { Either getUpdatedComponentRes = null; - Either result = null; + Either result = null; StorageOperationStatus status = getToscaElementOperation(component).updateToscaDataOfToscaElement(component.getUniqueId(), EdgeLabelEnum.ATTRIBUTES, VertexTypeEnum.ATTRIBUTES, newAttributeDef, JsonPresentationFields.NAME); if (status != StorageOperationStatus.OK) { CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Failed to add the property {} to the resource {}. Status is {}. ", newAttributeDef.getName(), component.getName(), status); @@ -2035,7 +2056,7 @@ public class ToscaOperationFacade { } } if (result == null) { - Optional newProperty = ((Resource) getUpdatedComponentRes.left().value()).getAttributes().stream().filter(p -> p.getName().equals(newAttributeDef.getName())).findAny(); + Optional newProperty = ((Resource) getUpdatedComponentRes.left().value()).getAttributes().stream().filter(p -> p.getName().equals(newAttributeDef.getName())).findAny(); if (newProperty.isPresent()) { result = Either.left(newProperty.get()); } else { @@ -2045,7 +2066,7 @@ public class ToscaOperationFacade { } return result; } - + public Either updateInputOfComponent(Component component, InputDefinition newInputDefinition) { Either getUpdatedComponentRes = null; @@ -2103,7 +2124,7 @@ public class ToscaOperationFacade { public StorageOperationStatus addComponentInstanceProperty(Component containerComponent, String componentInstanceId, ComponentInstanceProperty property) { return nodeTemplateOperation.addComponentInstanceProperty(containerComponent, componentInstanceId, property); } - + public StorageOperationStatus updateComponentInstanceInput(Component containerComponent, String componentInstanceId, ComponentInstanceInput property) { return nodeTemplateOperation.updateComponentInstanceInput(containerComponent, componentInstanceId, property); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/utils/ModelConverter.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/utils/ModelConverter.java index 07845c8ea5..e6f9ff6f93 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/utils/ModelConverter.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsontitan/utils/ModelConverter.java @@ -21,11 +21,9 @@ import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; import org.openecomp.sdc.be.model.AdditionalInformationDefinition; import org.openecomp.sdc.be.model.ArtifactDefinition; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; import org.openecomp.sdc.be.model.ComponentInstanceInput; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.DistributionStatusEnum; @@ -168,15 +166,15 @@ public class ModelConverter { } private static void convertAttributes(NodeType nodeType, Resource resource) { - Map attributes = nodeType.getAttributes(); + Map attributes = nodeType.getAttributes(); if (attributes != null) { - List attrs = attributes.values().stream().map(dataDef -> ModelConverter.fromDataDefinition(resource.getUniqueId(), dataDef)).collect(Collectors.toList()); + List attrs = attributes.values().stream().map(dataDef -> ModelConverter.fromDataDefinition(resource.getUniqueId(), dataDef)).collect(Collectors.toList()); resource.setAttributes(attrs); } } - private static AttributeDefinition fromDataDefinition(String resourceId, AttributeDataDefinition dataDefinition) { - AttributeDefinition attributeDefinition = new AttributeDefinition(dataDefinition); + private static PropertyDefinition fromDataDefinition(String resourceId, PropertyDataDefinition dataDefinition) { + PropertyDefinition attributeDefinition = new PropertyDefinition(dataDefinition); attributeDefinition.setParentUniqueId(resourceId); return attributeDefinition; } @@ -684,9 +682,9 @@ public class ModelConverter { } private static void convertAttributes(Resource component, NodeType nodeType) { - List attributes = component.getAttributes(); + List attributes = component.getAttributes(); if (attributes != null) { - Map attrsByName = attributes.stream().map(AttributeDataDefinition::new).collect(Collectors.toMap(AttributeDataDefinition::getName, Function.identity())); + Map attrsByName = attributes.stream().map(PropertyDataDefinition::new).collect(Collectors.toMap(PropertyDataDefinition::getName, Function.identity())); nodeType.setAttributes(attrsByName); } } @@ -997,11 +995,11 @@ public class ModelConverter { private static void setComponentInstancesAttributesToComponent(TopologyTemplate topologyTemplate, Component component) { if (topologyTemplate.getInstAttributes() != null) { - Map> attributes = new HashMap<>(); - for (Map.Entry entry : topologyTemplate.getInstAttributes().entrySet()) { + Map> attributes = new HashMap<>(); + for (Map.Entry entry : topologyTemplate.getInstAttributes().entrySet()) { if (entry.getValue() != null && entry.getValue().getMapToscaDataDefinition() != null) { String key = entry.getKey(); - List componentInstanceAttributes = entry.getValue().getMapToscaDataDefinition().entrySet().stream().map(e -> new ComponentInstanceAttribute(new AttributeDefinition(e.getValue()))) + List componentInstanceAttributes = entry.getValue().getMapToscaDataDefinition().entrySet().stream().map(e -> new ComponentInstanceProperty(new ComponentInstanceProperty(e.getValue()))) .collect(Collectors.toList()); attributes.put(key, componentInstanceAttributes); } @@ -1206,11 +1204,11 @@ public class ModelConverter { if (component.getComponentInstancesAttributes() != null) { topologyTemplate.setInstAttributes(new HashMap<>()); - MapAttributesDataDefinition attributesMap; - for (Entry> entry : component.getComponentInstancesAttributes().entrySet()) { - attributesMap = new MapAttributesDataDefinition(); + MapPropertiesDataDefinition attributesMap; + for (Entry> entry : component.getComponentInstancesAttributes().entrySet()) { + attributesMap = new MapPropertiesDataDefinition(); - attributesMap.setMapToscaDataDefinition(entry.getValue().stream().map(e -> new AttributeDataDefinition(e)).collect(Collectors.toMap(e -> e.getName(), e -> e))); + attributesMap.setMapToscaDataDefinition(entry.getValue().stream().map(e -> new PropertyDataDefinition(e)).collect(Collectors.toMap(e -> e.getName(), e -> e))); topologyTemplate.getInstAttributes().put(entry.getKey(), attributesMap); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IAttributeOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IAttributeOperation.java index db2b988f5f..c5fc70eb38 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IAttributeOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IAttributeOperation.java @@ -25,10 +25,10 @@ import java.util.Map; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.resources.data.AttributeData; import org.openecomp.sdc.be.resources.data.AttributeValueData; @@ -39,23 +39,23 @@ import fj.data.Either; public interface IAttributeOperation { Either deleteAttribute(String attributeId); - TitanOperationStatus addAttributesToGraph(TitanVertex metadataVertex, Map attributes, String resourceId, Map dataTypes); + TitanOperationStatus addAttributesToGraph(TitanVertex metadataVertex, Map attributes, String resourceId, Map dataTypes); - Either, TitanOperationStatus> getAllAttributesOfResourceInstance(ComponentInstance compInstance); + Either, TitanOperationStatus> getAllAttributesOfResourceInstance(ComponentInstance compInstance); - TitanOperationStatus findAllResourceAttributesRecursively(String resourceId, List attributes); + TitanOperationStatus findAllResourceAttributesRecursively(String resourceId, List attributes); - Either, StorageOperationStatus> deleteAllAttributeAssociatedToNode(NodeTypeEnum nodeType, String uniqueId); + Either, StorageOperationStatus> deleteAllAttributeAssociatedToNode(NodeTypeEnum nodeType, String uniqueId); - TitanOperationStatus findNodeNonInheretedAttribues(String uniqueId, NodeTypeEnum nodeType, List attributes); + TitanOperationStatus findNodeNonInheretedAttribues(String uniqueId, NodeTypeEnum nodeType, List attributes); - Either addAttribute(AttributeDefinition attributeDefinition, String resourceId); + Either addAttribute(PropertyDefinition attributeDefinition, String resourceId); - Either addAttributeToGraph(AttributeDefinition attribute, String resourceId, Map dataTypes); + Either addAttributeToGraph(PropertyDefinition attribute, String resourceId, Map dataTypes); - AttributeDefinition convertAttributeDataToAttributeDefinition(AttributeData attributeData, String attributeName, String resourceId); + PropertyDefinition convertAttributeDataToAttributeDefinition(AttributeData attributeData, String attributeName, String resourceId); - Either updateAttribute(String attributeId, AttributeDefinition newAttDef, Map dataTypes); + Either updateAttribute(String attributeId, PropertyDefinition newAttDef, Map dataTypes); /** * Builds ComponentInstanceAttribute from AttributeValueData @@ -64,8 +64,8 @@ public interface IAttributeOperation { * @param resourceInstanceAttribute * @return */ - ComponentInstanceAttribute buildResourceInstanceAttribute(AttributeValueData attributeValueData, ComponentInstanceAttribute resourceInstanceAttribute); + ComponentInstanceProperty buildResourceInstanceAttribute(AttributeValueData attributeValueData, ComponentInstanceProperty resourceInstanceAttribute); - TitanOperationStatus addAttributeToGraphByVertex(TitanVertex metadataVertex, AttributeDefinition attribute, String resourceId, Map dataTypes); + TitanOperationStatus addAttributeToGraphByVertex(TitanVertex metadataVertex, PropertyDefinition attribute, String resourceId, Map dataTypes); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IComponentInstanceOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IComponentInstanceOperation.java index 28e70ad127..f4cb13fa64 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IComponentInstanceOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IComponentInstanceOperation.java @@ -30,7 +30,6 @@ import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.ArtifactDefinition; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; import org.openecomp.sdc.be.model.ComponentInstanceInput; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; @@ -196,7 +195,7 @@ public interface IComponentInstanceOperation { * * @param resourceInstanceId * @param index * @param inTransaction * @return **/ - public Either addAttributeValueToResourceInstance(ComponentInstanceAttribute resourceInstanceAttribute, String resourceInstanceId, Integer index, boolean inTransaction); + public Either addAttributeValueToResourceInstance(ComponentInstanceProperty resourceInstanceAttribute, String resourceInstanceId, Integer index, boolean inTransaction); public Either updatePropertyValueInResourceInstance(ComponentInstanceProperty resourceInstanceProperty, String resourceInstanceId, boolean inTransaction); @@ -208,9 +207,9 @@ public interface IComponentInstanceOperation { * @param inTransaction * @return */ - public Either updateAttributeValueInResourceInstance(ComponentInstanceAttribute attribute, String resourceInstanceId, boolean inTransaction); + public Either updateAttributeValueInResourceInstance(ComponentInstanceProperty attribute, String resourceInstanceId, boolean inTransaction); - public Either createOrUpdateAttributeOfResourceInstance(ComponentInstanceAttribute attributeInstanceProperty, String resourceInstanceId); + public Either createOrUpdateAttributeOfResourceInstance(ComponentInstanceProperty attributeInstanceProperty, String resourceInstanceId); public Either addInputValueToResourceInstance(ComponentInstanceInput input, String resourceInstanceId, Integer innerElement, boolean b); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IConsumerOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IConsumerOperation.java index ed43b7ce1f..cab49fe47d 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IConsumerOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IConsumerOperation.java @@ -24,6 +24,8 @@ import org.openecomp.sdc.be.resources.data.ConsumerData; import fj.data.Either; +import java.util.List; + public interface IConsumerOperation { /** @@ -95,4 +97,10 @@ public interface IConsumerOperation { */ Either getCredentials(String consumerName); + /** + * + * @return all consumers + */ + Either, StorageOperationStatus> getAll(); + } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IResourceOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IResourceOperation.java index 01db3a5105..8d9994ba8a 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IResourceOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IResourceOperation.java @@ -137,10 +137,5 @@ public interface IResourceOperation extends IComponentOperation { */ Either, StorageOperationStatus> getVFResources(); - /** - * - * @return all resources - */ - Either, StorageOperationStatus> getAll(); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IUserAdminOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IUserAdminOperation.java index 84413f7987..254432c682 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IUserAdminOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IUserAdminOperation.java @@ -50,7 +50,7 @@ public interface IUserAdminOperation { Either, ActionStatus> getAllUsers(); - public Either, StorageOperationStatus> getUserPandingTasksList(User user, Map properties); + public Either, StorageOperationStatus> getUserPendingTasksList(User user, Map properties); public Either, ActionStatus> getUserDataWithFunctionalMenu(String userId); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/AttributeOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/AttributeOperation.java index f82a2982b0..279aab667c 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/AttributeOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/AttributeOperation.java @@ -35,12 +35,12 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge; import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; -import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.operations.api.IAttributeOperation; import org.openecomp.sdc.be.model.operations.api.IPropertyOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; @@ -81,7 +81,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO * @param attributeDefinition * @return */ - private Either addAttributeToNodeType(AttributeDefinition attributeDefinition, NodeTypeEnum nodeType, String nodeUniqueId) { + private Either addAttributeToNodeType(PropertyDefinition attributeDefinition, NodeTypeEnum nodeType, String nodeUniqueId) { String attUniqueId = UniqueIdBuilder.buildAttributeUid(nodeUniqueId, attributeDefinition.getName()); Supplier dataBuilder = () -> buildAttributeData(attributeDefinition, attUniqueId); Supplier defNameGenerator = () -> "Attribute : " + attributeDefinition.getName(); @@ -90,7 +90,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } - private TitanOperationStatus addAttributeToNodeType(TitanVertex metadataVertex, AttributeDefinition attributeDefinition, NodeTypeEnum nodeType, String nodeUniqueId) { + private TitanOperationStatus addAttributeToNodeType(TitanVertex metadataVertex, PropertyDefinition attributeDefinition, NodeTypeEnum nodeType, String nodeUniqueId) { String attUniqueId = UniqueIdBuilder.buildAttributeUid(nodeUniqueId, attributeDefinition.getName()); Supplier dataBuilder = () -> buildAttributeData(attributeDefinition, attUniqueId); Supplier defNameGenerator = () -> "Attribute : " + attributeDefinition.getName(); @@ -99,7 +99,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } - private AttributeData buildAttributeData(AttributeDefinition attributeDefinition, String attUniqueId) { + private AttributeData buildAttributeData(PropertyDefinition attributeDefinition, String attUniqueId) { attributeDefinition.setUniqueId(attUniqueId); return new AttributeData(attributeDefinition); } @@ -115,14 +115,14 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } @Override - public Either, StorageOperationStatus> deleteAllAttributeAssociatedToNode(NodeTypeEnum nodeType, String uniqueId) { + public Either, StorageOperationStatus> deleteAllAttributeAssociatedToNode(NodeTypeEnum nodeType, String uniqueId) { Wrapper errorWrapper; - List attributes = new ArrayList<>(); + List attributes = new ArrayList<>(); TitanOperationStatus findAllResourceAttribues = findNodeNonInheretedAttribues(uniqueId, NodeTypeEnum.Resource, attributes); errorWrapper = (findAllResourceAttribues != TitanOperationStatus.OK) ? new Wrapper<>(findAllResourceAttribues) : new Wrapper<>(); if (errorWrapper.isEmpty()) { - for (AttributeDefinition attDef : attributes) { + for (PropertyDefinition attDef : attributes) { log.debug("Before deleting attribute from graph {}", attDef.getUniqueId()); Either deleteNode = titanGenericDao.deleteNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Attribute), attDef.getUniqueId(), AttributeData.class); if (deleteNode.isRight()) { @@ -133,7 +133,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } if (errorWrapper.isEmpty()) { - Map attributesMap = attributes.stream().collect(Collectors.toMap(e -> e.getName(), e -> e)); + Map attributesMap = attributes.stream().collect(Collectors.toMap(e -> e.getName(), e -> e)); return Either.left(attributesMap); } else { return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(errorWrapper.getInnerElement())); @@ -147,9 +147,9 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } @Override - public TitanOperationStatus addAttributesToGraph(TitanVertex metadataVertex, Map attributes, String resourceId, Map dataTypes) { + public TitanOperationStatus addAttributesToGraph(TitanVertex metadataVertex, Map attributes, String resourceId, Map dataTypes) { TitanOperationStatus titanStatus = TitanOperationStatus.OK; - for (AttributeDefinition attribute : attributes.values()) { + for (PropertyDefinition attribute : attributes.values()) { TitanOperationStatus eitherAddAttribute = addAttributeToGraphByVertex(metadataVertex, attribute, resourceId, dataTypes); if (!eitherAddAttribute.equals(TitanOperationStatus.OK)) { titanStatus = eitherAddAttribute; @@ -160,9 +160,9 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } @Override - public Either, TitanOperationStatus> getAllAttributesOfResourceInstance(ComponentInstance compInstance) { + public Either, TitanOperationStatus> getAllAttributesOfResourceInstance(ComponentInstance compInstance) { - Either, TitanOperationStatus> result; + Either, TitanOperationStatus> result; Either>, TitanOperationStatus> attributeImplNodes = titanGenericDao.getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.ResourceInstance), compInstance.getUniqueId(), GraphEdgeLabels.ATTRIBUTE_VALUE, NodeTypeEnum.AttributeValue, AttributeValueData.class); @@ -185,31 +185,31 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO return result; } - private Either, TitanOperationStatus> mergeAttributesResults(Either, TitanOperationStatus> eitherAttributesThatDoesNotExistOnRI, - Either, TitanOperationStatus> eitherAttributesThatExistOnRI) { + private Either, TitanOperationStatus> mergeAttributesResults(Either, TitanOperationStatus> eitherAttributesThatDoesNotExistOnRI, + Either, TitanOperationStatus> eitherAttributesThatExistOnRI) { - Either, TitanOperationStatus> result; + Either, TitanOperationStatus> result; if (eitherAttributesThatExistOnRI.isRight()) { result = Either.right(eitherAttributesThatExistOnRI.right().value()); } else if (eitherAttributesThatDoesNotExistOnRI.isRight()) { result = Either.right(eitherAttributesThatDoesNotExistOnRI.right().value()); } else { - final List attributesThatExistOnRI = eitherAttributesThatExistOnRI.left().value(); - final List attributesThatDoesNotExistOnRI = eitherAttributesThatDoesNotExistOnRI.left().value(); + final List attributesThatExistOnRI = eitherAttributesThatExistOnRI.left().value(); + final List attributesThatDoesNotExistOnRI = eitherAttributesThatDoesNotExistOnRI.left().value(); Set attributesIdThatExistOnRI = attributesThatExistOnRI.stream().map(e -> e.getUniqueId()).collect(Collectors.toSet()); // Attributes From The Resource Without attributes that also exist // on the instance - Stream filterAttributesThatDoesNotExistOnRI = attributesThatDoesNotExistOnRI.stream().filter(e -> !attributesIdThatExistOnRI.contains(e.getUniqueId())); + Stream filterAttributesThatDoesNotExistOnRI = attributesThatDoesNotExistOnRI.stream().filter(e -> !attributesIdThatExistOnRI.contains(e.getUniqueId())); // Add Fields From Resource Attributes fillAttributeInfoFromResource(attributesThatExistOnRI, attributesThatDoesNotExistOnRI); // Adding the Attributes on the instance for the full list - List mergedList = Stream.concat(filterAttributesThatDoesNotExistOnRI, attributesThatExistOnRI.stream()).collect(Collectors.toList()); + List mergedList = Stream.concat(filterAttributesThatDoesNotExistOnRI, attributesThatExistOnRI.stream()).collect(Collectors.toList()); result = Either.left(mergedList); } return result; } - private void fillAttributeInfoFromResource(List attributesThatExistOnRI, List attributesThatDoesNotExistOnRI) { + private void fillAttributeInfoFromResource(List attributesThatExistOnRI, List attributesThatDoesNotExistOnRI) { attributesThatExistOnRI.stream() .forEach(e -> addAttributeInfo(e, // Finds the same attribute in the resource @@ -217,7 +217,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } - private void addAttributeInfo(ComponentInstanceAttribute attributeFromRI, ComponentInstanceAttribute attributeFromResource) { + private void addAttributeInfo(ComponentInstanceProperty attributeFromRI, ComponentInstanceProperty attributeFromResource) { attributeFromRI.setName(attributeFromResource.getName()); attributeFromRI.setDescription(attributeFromResource.getDescription()); attributeFromRI.setDefaultValue(attributeFromResource.getDefaultValue()); @@ -228,18 +228,18 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } } - private Either, TitanOperationStatus> getAttributesFromResource(ComponentInstance compInstance) { - Either, TitanOperationStatus> result; - List attributes = new ArrayList<>(); + private Either, TitanOperationStatus> getAttributesFromResource(ComponentInstance compInstance) { + Either, TitanOperationStatus> result; + List attributes = new ArrayList<>(); // Attributes does not exist on Ri - fetch them from resource TitanOperationStatus findAllResourceAttribues = findAllResourceAttributesRecursively(compInstance.getComponentUid(), attributes); if (findAllResourceAttribues != TitanOperationStatus.OK) { result = Either.right(findAllResourceAttribues); } else { - List buildAttInstanceFromResource = attributes.stream().map(attDef -> new ComponentInstanceAttribute(attDef, false, null)).collect(Collectors.toList()); + List buildAttInstanceFromResource = attributes.stream().map(attDef -> new ComponentInstanceProperty(false, attDef, null)).collect(Collectors.toList()); // Set Value to be default value in case it is empty - Consumer valueSetter = att -> { + Consumer valueSetter = att -> { if (StringUtils.isEmpty(att.getValue())) { att.setValue(att.getDefaultValue()); } @@ -251,9 +251,9 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO return result; } - private Either, TitanOperationStatus> convertToComponentInstanceAttribute(List> list) { - Either, TitanOperationStatus> result = null; - List componentInstanceAttribute = new ArrayList<>(); + private Either, TitanOperationStatus> convertToComponentInstanceAttribute(List> list) { + Either, TitanOperationStatus> result = null; + List componentInstanceAttribute = new ArrayList<>(); for (ImmutablePair attributeValue : list) { AttributeValueData attributeValueData = attributeValue.getLeft(); String attributeValueUid = attributeValueData.getUniqueId(); @@ -272,7 +272,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO ImmutablePair attributeDefPair = attributeDefRes.left().value(); String attributeUniqueId = attributeDefPair.left.getUniqueId(); - ComponentInstanceAttribute resourceInstanceAttribute = new ComponentInstanceAttribute(); + ComponentInstanceProperty resourceInstanceAttribute = new ComponentInstanceProperty(); // set attribute original unique id resourceInstanceAttribute.setUniqueId(attributeUniqueId); // set hidden @@ -302,14 +302,14 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO * @return */ @Override - public TitanOperationStatus findAllResourceAttributesRecursively(String resourceId, List attributes) { - final NodeElementFetcher singleNodeFetcher = (resourceIdParam, attributesParam) -> findNodeNonInheretedAttribues(resourceIdParam, NodeTypeEnum.Resource, attributesParam); + public TitanOperationStatus findAllResourceAttributesRecursively(String resourceId, List attributes) { + final NodeElementFetcher singleNodeFetcher = (resourceIdParam, attributesParam) -> findNodeNonInheretedAttribues(resourceIdParam, NodeTypeEnum.Resource, attributesParam); return findAllResourceElementsDefinitionRecursively(resourceId, attributes, singleNodeFetcher); } @Override - public TitanOperationStatus findNodeNonInheretedAttribues(String uniqueId, NodeTypeEnum nodeType, List attributes) { + public TitanOperationStatus findNodeNonInheretedAttribues(String uniqueId, NodeTypeEnum nodeType, List attributes) { Either>, TitanOperationStatus> childrenNodes = titanGenericDao.getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(nodeType), uniqueId, GraphEdgeLabels.ATTRIBUTE, NodeTypeEnum.Attribute, AttributeData.class); @@ -330,7 +330,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO log.debug("Attribute {} is associated to node {}", attributeName, uniqueId); AttributeData attributeData = immutablePair.getKey(); - AttributeDefinition attributeDefinition = this.convertAttributeDataToAttributeDefinition(attributeData, attributeName, uniqueId); + PropertyDefinition attributeDefinition = this.convertAttributeDataToAttributeDefinition(attributeData, attributeName, uniqueId); attributes.add(attributeDefinition); @@ -343,16 +343,16 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } @Override - public AttributeDefinition convertAttributeDataToAttributeDefinition(AttributeData attributeData, String attributeName, String resourceId) { + public PropertyDefinition convertAttributeDataToAttributeDefinition(AttributeData attributeData, String attributeName, String resourceId) { log.debug("The object returned after create attribute is {}", attributeData); - AttributeDefinition attributeDefResult = new AttributeDefinition(attributeData.getAttributeDataDefinition()); + PropertyDefinition attributeDefResult = new PropertyDefinition(attributeData.getAttributeDataDefinition()); attributeDefResult.setName(attributeName); attributeDefResult.setParentUniqueId(resourceId); return attributeDefResult; } @Override - public Either addAttribute(AttributeDefinition attributeDefinition, String resourceId) { + public Either addAttribute(PropertyDefinition attributeDefinition, String resourceId) { Either eitherResult; Either, TitanOperationStatus> allDataTypes = applicationDataTypeCache.getAll(); @@ -373,7 +373,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } @Override - public Either updateAttribute(String attributeId, AttributeDefinition newAttDef, Map dataTypes) { + public Either updateAttribute(String attributeId, PropertyDefinition newAttDef, Map dataTypes) { StorageOperationStatus validateAndUpdateAttribute = propertyOperation.validateAndUpdateProperty(newAttDef, dataTypes); if (validateAndUpdateAttribute != StorageOperationStatus.OK) { @@ -388,7 +388,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO return Either.left(either.left().value()); } - private Either updateAttributeFromGraph(String attributeId, AttributeDefinition attributeDefenition) { + private Either updateAttributeFromGraph(String attributeId, PropertyDefinition attributeDefenition) { log.debug("Before updating attribute on graph {}", attributeId); // get the original property data @@ -398,12 +398,12 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO return Either.right(eitherAttribute.right().value()); } AttributeData orgAttributeData = eitherAttribute.left().value(); - AttributeDataDefinition orgAttributeDataDefinition = orgAttributeData.getAttributeDataDefinition(); + PropertyDataDefinition orgAttributeDataDefinition = orgAttributeData.getAttributeDataDefinition(); // create new property data to update AttributeData newAttributeData = new AttributeData(); newAttributeData.setAttributeDataDefinition(attributeDefenition); - AttributeDataDefinition newAttributeDataDefinition = newAttributeData.getAttributeDataDefinition(); + PropertyDataDefinition newAttributeDataDefinition = newAttributeData.getAttributeDataDefinition(); // update the original property data with new values if (!Objects.equals(orgAttributeDataDefinition.getDefaultValue(), newAttributeDataDefinition.getDefaultValue())) { @@ -424,17 +424,15 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } @Override - public ComponentInstanceAttribute buildResourceInstanceAttribute(AttributeValueData attributeValueData, ComponentInstanceAttribute resourceInstanceAttribute) { + public ComponentInstanceProperty buildResourceInstanceAttribute(AttributeValueData attributeValueData, ComponentInstanceProperty resourceInstanceAttribute) { Boolean hidden = attributeValueData.isHidden(); String uid = attributeValueData.getUniqueId(); - ComponentInstanceAttribute instanceAttribute = new ComponentInstanceAttribute(resourceInstanceAttribute, hidden, uid); - - return instanceAttribute; + return new ComponentInstanceProperty(hidden, resourceInstanceAttribute, uid); } @Override - public Either addAttributeToGraph(AttributeDefinition attribute, String resourceId, Map dataTypes) { + public Either addAttributeToGraph(PropertyDefinition attribute, String resourceId, Map dataTypes) { Either eitherResult; StorageOperationStatus validateAndUpdateAttribute = propertyOperation.validateAndUpdateProperty(attribute, dataTypes); if (validateAndUpdateAttribute != StorageOperationStatus.OK) { @@ -448,7 +446,7 @@ public class AttributeOperation extends AbstractOperation implements IAttributeO } @Override - public TitanOperationStatus addAttributeToGraphByVertex(TitanVertex metadataVertex, AttributeDefinition attribute, String resourceId, Map dataTypes) { + public TitanOperationStatus addAttributeToGraphByVertex(TitanVertex metadataVertex, PropertyDefinition attribute, String resourceId, Map dataTypes) { StorageOperationStatus validateAndUpdateAttribute = propertyOperation.validateAndUpdateProperty(attribute, dataTypes); TitanOperationStatus result; if (validateAndUpdateAttribute != StorageOperationStatus.OK) { diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ComponentInstanceOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ComponentInstanceOperation.java index c487b0ce71..43e4d0683b 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ComponentInstanceOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ComponentInstanceOperation.java @@ -66,7 +66,6 @@ import org.openecomp.sdc.be.model.ArtifactDefinition; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; import org.openecomp.sdc.be.model.ComponentInstanceInput; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.DataTypeDefinition; @@ -3893,7 +3892,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo private StorageOperationStatus cloneResourceInstanceAttributeValues(ComponentInstance createdInstance, ComponentInstance resourceInstance) { Wrapper storageStatusWrapper = new Wrapper<>(); - Wrapper> compInstanceAttList = new Wrapper<>(); + Wrapper> compInstanceAttList = new Wrapper<>(); findAllAttributesOfResourceInstance(resourceInstance, compInstanceAttList, storageStatusWrapper); @@ -3902,7 +3901,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } if (storageStatusWrapper.isEmpty()) { - List attributesOnInstance = compInstanceAttList.getInnerElement(); + List attributesOnInstance = compInstanceAttList.getInnerElement(); for (int i = 0; i < attributesOnInstance.size() && storageStatusWrapper.isEmpty(); i++) { cloneSingleAttributeOnResourceInstance(createdInstance, attributesOnInstance.get(i), storageStatusWrapper); } @@ -3915,7 +3914,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo private StorageOperationStatus cloneResourceInstanceAttributeValues(TitanVertex createdInstanceVertex, ComponentInstance resourceInstance, String instanceId) { Wrapper storageStatusWrapper = new Wrapper<>(); - Wrapper> compInstanceAttList = new Wrapper<>(); + Wrapper> compInstanceAttList = new Wrapper<>(); findAllAttributesOfResourceInstance(resourceInstance, compInstanceAttList, storageStatusWrapper); @@ -3924,7 +3923,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } if (storageStatusWrapper.isEmpty()) { - List attributesOnInstance = compInstanceAttList.getInnerElement(); + List attributesOnInstance = compInstanceAttList.getInnerElement(); for (int i = 0; i < attributesOnInstance.size() && storageStatusWrapper.isEmpty(); i++) { StorageOperationStatus result = cloneSingleAttributeOnResourceInstance(createdInstanceVertex, attributesOnInstance.get(i), instanceId); if (result != StorageOperationStatus.OK) { @@ -3945,9 +3944,9 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } } - private void findAllAttributesOfResourceInstance(ComponentInstance resourceInstance, Wrapper> compInstanceAttList, Wrapper storageStatusWrapper) { + private void findAllAttributesOfResourceInstance(ComponentInstance resourceInstance, Wrapper> compInstanceAttList, Wrapper storageStatusWrapper) { - Either, TitanOperationStatus> allAttributes = attributeOperation.getAllAttributesOfResourceInstance(resourceInstance); + Either, TitanOperationStatus> allAttributes = attributeOperation.getAllAttributesOfResourceInstance(resourceInstance); if (allAttributes.isRight()) { TitanOperationStatus status = allAttributes.right().value(); if (status == TitanOperationStatus.NOT_FOUND) { @@ -3960,7 +3959,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } } - private void cloneSingleAttributeOnResourceInstance(ComponentInstance createdInstance, ComponentInstanceAttribute attribute, Wrapper storageStatusWrapper) { + private void cloneSingleAttributeOnResourceInstance(ComponentInstance createdInstance, ComponentInstanceProperty attribute, Wrapper storageStatusWrapper) { // Only if valueUniqueId is not empty, then its belongs to the // instance if (attribute.getValueUniqueUid() != null) { @@ -3981,7 +3980,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } - private StorageOperationStatus cloneSingleAttributeOnResourceInstance(TitanVertex createdInstanceVertex, ComponentInstanceAttribute attribute, String instanceId) { + private StorageOperationStatus cloneSingleAttributeOnResourceInstance(TitanVertex createdInstanceVertex, ComponentInstanceProperty attribute, String instanceId) { // Only if valueUniqueId is not empty, then its belongs to the // instance if (attribute.getValueUniqueUid() != null) { @@ -4053,7 +4052,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } } - private void createAttributeValueDataNode(ComponentInstanceAttribute attributeInstanceProperty, Integer index, Wrapper errorWrapper, ComponentInstanceData resourceInstanceData, + private void createAttributeValueDataNode(ComponentInstanceProperty attributeInstanceProperty, Integer index, Wrapper errorWrapper, ComponentInstanceData resourceInstanceData, Wrapper attValueDataWrapper) { String valueUniqueUid = attributeInstanceProperty.getValueUniqueUid(); if (valueUniqueUid == null) { @@ -4093,7 +4092,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo * } else { BeEcompErrorManager.getInstance().logInternalFlowError( "CreateAttributeValueDataNode", "attribute value already exists.", ErrorSeverity.ERROR); errorWrapper.setInnerElement(TitanOperationStatus.ALREADY_EXIST); } } */ - private AttributeValueData buildAttributeValueDataFromComponentInstanceAttribute(ComponentInstanceAttribute resourceInstanceAttribute, String uniqueId) { + private AttributeValueData buildAttributeValueDataFromComponentInstanceAttribute(ComponentInstanceProperty resourceInstanceAttribute, String uniqueId) { AttributeValueData attributeValueData = new AttributeValueData(); attributeValueData.setUniqueId(uniqueId); attributeValueData.setHidden(resourceInstanceAttribute.isHidden()); @@ -4509,7 +4508,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } @Override - public Either createOrUpdateAttributeOfResourceInstance(ComponentInstanceAttribute attributeInstanceProperty, String resourceInstanceId) { + public Either createOrUpdateAttributeOfResourceInstance(ComponentInstanceProperty attributeInstanceProperty, String resourceInstanceId) { Either result; // Create if (attributeInstanceProperty.getValueUniqueUid() == null) { @@ -4536,7 +4535,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo * @param resourceInstanceId * @return */ - private Either updateAttributeOfResourceInstance(ComponentInstanceAttribute resourceInstanceAttribute, String resourceInstanceId) { + private Either updateAttributeOfResourceInstance(ComponentInstanceProperty resourceInstanceAttribute, String resourceInstanceId) { Either result = null; Wrapper errorWrapper = new Wrapper<>(); @@ -4562,7 +4561,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } - private Either addAttributeToResourceInstance(ComponentInstanceAttribute attributeInstanceProperty, String resourceInstanceId, Integer index) { + private Either addAttributeToResourceInstance(ComponentInstanceProperty attributeInstanceProperty, String resourceInstanceId, Integer index) { Wrapper errorWrapper = new Wrapper<>(); Wrapper compInsWrapper = new Wrapper<>(); Wrapper attDataWrapper = new Wrapper<>(); @@ -5263,8 +5262,8 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } @Override - public Either addAttributeValueToResourceInstance(ComponentInstanceAttribute resourceInstanceAttribute, String resourceInstanceId, Integer index, boolean inTransaction) { - Either result = null; + public Either addAttributeValueToResourceInstance(ComponentInstanceProperty resourceInstanceAttribute, String resourceInstanceId, Integer index, boolean inTransaction) { + Either result = null; try { @@ -5277,7 +5276,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } else { AttributeValueData attributeValueData = eitherStatus.left().value(); - ComponentInstanceAttribute attributeValueResult = attributeOperation.buildResourceInstanceAttribute(attributeValueData, resourceInstanceAttribute); + ComponentInstanceProperty attributeValueResult = attributeOperation.buildResourceInstanceAttribute(attributeValueData, resourceInstanceAttribute); log.debug("The returned ResourceInstanceAttribute is {}", attributeValueResult); result = Either.left(attributeValueResult); @@ -5291,9 +5290,9 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } @Override - public Either updateAttributeValueInResourceInstance(ComponentInstanceAttribute resourceInstanceAttribute, String resourceInstanceId, boolean inTransaction) { + public Either updateAttributeValueInResourceInstance(ComponentInstanceProperty resourceInstanceAttribute, String resourceInstanceId, boolean inTransaction) { - Either result = null; + Either result = null; try { Either eitherAttributeValue = updateAttributeOfResourceInstance(resourceInstanceAttribute, resourceInstanceId); @@ -5305,7 +5304,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo } else { AttributeValueData attributeValueData = eitherAttributeValue.left().value(); - ComponentInstanceAttribute attributeValueResult = attributeOperation.buildResourceInstanceAttribute(attributeValueData, resourceInstanceAttribute); + ComponentInstanceProperty attributeValueResult = attributeOperation.buildResourceInstanceAttribute(attributeValueData, resourceInstanceAttribute); log.debug("The returned ResourceInstanceAttribute is {}", attributeValueResult); result = Either.left(attributeValueResult); @@ -5463,7 +5462,7 @@ public class ComponentInstanceOperation extends AbstractOperation implements ICo return Either.left(result); } - // TODO Tal G US831698 + //US831698 public Either, StorageOperationStatus> getComponentInstancesPropertiesAndValuesFromGraph(ComponentInstance resourceInstance) { Map> alreadyProcessedResources = new HashMap<>(); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ConsumerOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ConsumerOperation.java index 215a1464a6..a5a1348f21 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ConsumerOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ConsumerOperation.java @@ -23,24 +23,29 @@ package org.openecomp.sdc.be.model.operations.impl; import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.dao.titan.TitanGenericDao; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.operations.api.IConsumerOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.resources.data.ConsumerData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import fj.data.Either; +import java.util.Collections; +import java.util.List; + @Component("consumer-operation") public class ConsumerOperation implements IConsumerOperation { - @javax.annotation.Resource private TitanGenericDao titanGenericDao; private static Logger log = LoggerFactory.getLogger(ConsumerOperation.class.getName()); - public ConsumerOperation() { + public ConsumerOperation(@Qualifier("titan-generic-dao") TitanGenericDao titanGenericDao) { + this.titanGenericDao = titanGenericDao; } @Override @@ -58,6 +63,13 @@ public class ConsumerOperation implements IConsumerOperation { return Either.left(consumerData); } + @Override + public Either, StorageOperationStatus> getAll() { + log.debug("retrieving all consumers"); + return titanGenericDao.getByCriteria(NodeTypeEnum.ConsumerCredentials, Collections.emptyMap(), ConsumerData.class) + .right().map(DaoStatusConverter::convertTitanStatusToStorageStatus); + } + @Override public Either createCredentials(ConsumerData consumerData) { return createCredentials(consumerData, false); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ResourceOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ResourceOperation.java index 4dce650f18..2cc78eade2 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ResourceOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ResourceOperation.java @@ -20,20 +20,11 @@ package org.openecomp.sdc.be.model.operations.impl; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.function.Predicate; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanVertex; +import fj.data.Either; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -54,25 +45,7 @@ import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; -import org.openecomp.sdc.be.model.AdditionalInformationDefinition; -import org.openecomp.sdc.be.model.ArtifactDefinition; -import org.openecomp.sdc.be.model.AttributeDefinition; -import org.openecomp.sdc.be.model.CapabilityDefinition; -import org.openecomp.sdc.be.model.Component; -import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; -import org.openecomp.sdc.be.model.ComponentInstanceProperty; -import org.openecomp.sdc.be.model.ComponentParametersView; -import org.openecomp.sdc.be.model.DataTypeDefinition; -import org.openecomp.sdc.be.model.GroupDefinition; -import org.openecomp.sdc.be.model.InputDefinition; -import org.openecomp.sdc.be.model.InterfaceDefinition; -import org.openecomp.sdc.be.model.LifecycleStateEnum; -import org.openecomp.sdc.be.model.Operation; -import org.openecomp.sdc.be.model.PropertyDefinition; -import org.openecomp.sdc.be.model.RequirementDefinition; -import org.openecomp.sdc.be.model.Resource; -import org.openecomp.sdc.be.model.ResourceMetadataDefinition; +import org.openecomp.sdc.be.model.*; import org.openecomp.sdc.be.model.cache.ComponentCache; import org.openecomp.sdc.be.model.category.CategoryDefinition; import org.openecomp.sdc.be.model.category.SubCategoryDefinition; @@ -82,7 +55,7 @@ import org.openecomp.sdc.be.model.operations.api.IAttributeOperation; import org.openecomp.sdc.be.model.operations.api.IElementOperation; import org.openecomp.sdc.be.model.operations.api.IResourceOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; -import org.openecomp.sdc.be.model.operations.migration.MigrationErrorInformer; +import org.openecomp.sdc.be.model.operations.migration.MigrationMalformedDataLogger; import org.openecomp.sdc.be.model.operations.utils.GraphDeleteUtil; import org.openecomp.sdc.be.resources.data.ComponentMetadataData; import org.openecomp.sdc.be.resources.data.PropertyData; @@ -100,13 +73,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.thinkaurelius.titan.core.TitanGraph; -import com.thinkaurelius.titan.core.TitanVertex; - -import fj.Function; -import fj.data.Either; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Collectors; @org.springframework.stereotype.Component("resource-operation") @Deprecated @@ -651,7 +629,7 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp return getPropertiesOfAllDerivedFromRes; } - private TitanOperationStatus associateAttributesToResource(TitanVertex metadataVertex, List attributes, String resourceId) { + private TitanOperationStatus associateAttributesToResource(TitanVertex metadataVertex, List attributes, String resourceId) { TitanOperationStatus operationStatus = TitanOperationStatus.OK; Either, TitanOperationStatus> allDataTypes = applicationDataTypeCache.getAll(); @@ -662,7 +640,7 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp } if (attributes != null) { - Map convertedAttributes = attributes.stream().collect(Collectors.toMap(e -> e.getName(), e -> e)); + Map convertedAttributes = attributes.stream().collect(Collectors.toMap(e -> e.getName(), e -> e)); operationStatus = attributeOperation.addAttributesToGraph(metadataVertex, convertedAttributes, resourceId, allDataTypes.left().value()); } return operationStatus; @@ -805,12 +783,12 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp } private TitanOperationStatus setComponentInstancesAttributesFromGraph(String uniqueId, Resource component) { - Map> resourceInstancesAttributes = new HashMap<>(); + Map> resourceInstancesAttributes = new HashMap<>(); TitanOperationStatus status = TitanOperationStatus.OK; List componentInstances = component.getComponentInstances(); if (componentInstances != null) { for (ComponentInstance resourceInstance : componentInstances) { - Either, TitanOperationStatus> eitherRIAttributes = attributeOperation.getAllAttributesOfResourceInstance(resourceInstance); + Either, TitanOperationStatus> eitherRIAttributes = attributeOperation.getAllAttributesOfResourceInstance(resourceInstance); if (eitherRIAttributes.isRight()) { status = eitherRIAttributes.right().value(); break; @@ -875,8 +853,7 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp } else { Map capabilities = result.left().value(); if (capabilities != null && !capabilities.isEmpty() && resource.getResourceType().equals(ResourceTypeEnum.VF)) { - log.error(String.format("VF %s has direct capabilities.!!!!!!!!!!!!!", resource.getName())); - MigrationErrorInformer.addMalformedVF(resource.getUniqueId()); + MigrationMalformedDataLogger.reportMalformedVF(resource.getUniqueId(), String.format("VF %s with id %s has direct capabilities.!!!!!!!!!!!!!", resource.getName(), resource.getUniqueId())); } if (capabilities == null || capabilities.isEmpty() || resource.getResourceType().equals(ResourceTypeEnum.VF)) { Either>, TitanOperationStatus> eitherCapabilities = super.getCapabilities(resource, NodeTypeEnum.Resource, true); @@ -946,8 +923,7 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp } else { Map requirements = result.left().value(); if (requirements != null && !requirements.isEmpty() && resource.getResourceType().equals(ResourceTypeEnum.VF)) { - log.error(String.format("VF %s has direct requirements.!!!!!!!!!!!!!", resource.getName())); - MigrationErrorInformer.addMalformedVF(resource.getUniqueId()); + MigrationMalformedDataLogger.reportMalformedVF(resource.getUniqueId(), String.format("VF %s with id %s has direct requirements.!!!!!!!!!!!!!", resource.getName(), resource.getUniqueId())); } if (requirements == null || requirements.isEmpty() || resource.getResourceType() == ResourceTypeEnum.VF) { Either>, TitanOperationStatus> eitherCapabilities = super.getRequirements(resource, NodeTypeEnum.Resource, true); @@ -982,7 +958,7 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp private TitanOperationStatus setResourceAttributesFromGraph(String uniqueId, Resource resource) { - List attributes = new ArrayList<>(); + List attributes = new ArrayList<>(); TitanOperationStatus status = attributeOperation.findAllResourceAttributesRecursively(uniqueId, attributes); if (status == TitanOperationStatus.OK) { resource.setAttributes(attributes); @@ -1372,7 +1348,7 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp } private StorageOperationStatus removeAttributesFromResource(Resource resource) { - Either, StorageOperationStatus> deleteAllAttributeAssociatedToNode = attributeOperation.deleteAllAttributeAssociatedToNode(NodeTypeEnum.Resource, resource.getUniqueId()); + Either, StorageOperationStatus> deleteAllAttributeAssociatedToNode = attributeOperation.deleteAllAttributeAssociatedToNode(NodeTypeEnum.Resource, resource.getUniqueId()); return deleteAllAttributeAssociatedToNode.isRight() ? deleteAllAttributeAssociatedToNode.right().value() : StorageOperationStatus.OK; } @@ -1862,25 +1838,23 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp return getResourceListByCriteria(rootToscaResource, false); } - @Override - public Either, StorageOperationStatus> getAll() { - Either, StorageOperationStatus> resourceListByCriteria = getResourceListByCriteria(new HashMap<>(), false); - if (resourceListByCriteria.isRight() && resourceListByCriteria.right().value() == StorageOperationStatus.NOT_FOUND) { - return Either.left(Collections.emptyList()); - } - return resourceListByCriteria; - } - - private Either>, TitanOperationStatus> getDerivingChildren(Resource resource) { return titanGenericDao.getParentNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Resource), resource.getUniqueId(), GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.Resource, ResourceMetadataData.class); } private Either, StorageOperationStatus> convertToResources(List resourcesMetaData) { - List> resources = resourcesMetaData.stream() - .map(resourceMetaData -> this.getResource(resourceMetaData.getMetadataDataDefinition().getUniqueId())) - .collect(Collectors.toList()); - return Either.sequenceLeft(fj.data.List.iterableList(resources)).bimap(fj.data.List::toJavaList, Function.identity()); + List resources = new ArrayList<>(); + for (ResourceMetadataData resourceMetadataData : resourcesMetaData) { + String uniqueId = resourceMetadataData.getMetadataDataDefinition().getUniqueId(); + Either resource = this.getResource(uniqueId); + if (resource.isRight()) { + StorageOperationStatus status = resource.right().value(); + log.error("Failed to fetch resource {} . status is {}", uniqueId, status); + return Either.right(status); + } + resources.add(resource.left().value()); + } + return Either.left(resources); } protected TitanOperationStatus findResourcesPathRecursively(String resourceId, List resourcesPathList) { @@ -2163,19 +2137,23 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp if (byCriteria.isRight()) { return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(byCriteria.right().value())); } - List resources = new ArrayList(); + List resources = new ArrayList<>(); List resourcesDataList = byCriteria.left().value(); for (ResourceMetadataData data : resourcesDataList) { - Either resource = getResource(data.getMetadataDataDefinition().getUniqueId(), inTransaction); - if (resource.isLeft()) { - resources.add(resource.left().value()); - } else { - log.debug("Failed to fetch resource for name = {} and id = {}", data.getUniqueId(), data.getMetadataDataDefinition().getName()); - } + buildResource(inTransaction, resources, data); } return Either.left(resources); } + private void buildResource(boolean inTransaction, List resources, ResourceMetadataData data) { + Either resource = getResource(data.getMetadataDataDefinition().getUniqueId(), inTransaction); + if (resource.isLeft()) { + resources.add(resource.left().value()); + } else { + log.debug("Failed to fetch resource for name = {} and id = {}", data.getUniqueId(), data.getMetadataDataDefinition().getName()); + } + } + public Either, StorageOperationStatus> getResourceListByUuid(String uuid, boolean inTransaction) { return getLatestResourceByUuid(uuid, false, inTransaction); } @@ -2623,7 +2601,7 @@ public class ResourceOperation extends ComponentOperation implements IResourceOp } resource.setInterfaces(interfacesOfResourceOnly.left().value()); - List attributes = new ArrayList<>(); + List attributes = new ArrayList<>(); TitanOperationStatus status = attributeOperation.findNodeNonInheretedAttribues(prevId, NodeTypeEnum.Resource, attributes); if (status != TitanOperationStatus.OK) { return DaoStatusConverter.convertTitanStatusToStorageStatus(status); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/UserAdminOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/UserAdminOperation.java index 7c45f8f384..81ca98444c 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/UserAdminOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/UserAdminOperation.java @@ -33,6 +33,7 @@ import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.dao.titan.TitanGenericDao; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.dao.utils.UserStatusEnum; +import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.FunctionalMenuInfo; import org.openecomp.sdc.be.model.User; @@ -282,7 +283,7 @@ public class UserAdminOperation implements IUserAdminOperation { } } - public Either, StorageOperationStatus> getUserPandingTasksList(User user, Map properties) { + public Either, StorageOperationStatus> getUserPendingTasksList(User user, Map properties) { UserData userData = convertToUserData(user); @@ -316,7 +317,16 @@ public class UserAdminOperation implements IUserAdminOperation { } } } - + + if(log.isDebugEnabled()) { + for (Edge edge : pandingTasks) { + Object resourceUuid = edge.inVertex().property(GraphPropertyEnum.UNIQUE_ID.getProperty()).value(); + Object componentName = edge.inVertex().property(GraphPropertyEnum.NAME.getProperty()).value(); + Object componentState = edge.inVertex().property(GraphPropertyEnum.STATE.getProperty()).value(); + log.debug("The user userId = {} is working on the component name = {} uid = {} in state {}", user.getUserId(), componentName, resourceUuid, componentState); + } + } + return Either.left(pandingTasks); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/migration/MigrationErrorInformer.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/migration/MigrationMalformedDataLogger.java similarity index 82% rename from catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/migration/MigrationErrorInformer.java rename to catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/migration/MigrationMalformedDataLogger.java index 952c0672cc..2d4ca635e7 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/migration/MigrationErrorInformer.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/migration/MigrationMalformedDataLogger.java @@ -14,16 +14,21 @@ import java.util.stream.Collectors; /** * to be moved with all operations to the migration project */ -@Deprecated -public class MigrationErrorInformer { - private static Logger log = LoggerFactory.getLogger(MigrationErrorInformer.class); +public class MigrationMalformedDataLogger { + + private static Logger log = LoggerFactory.getLogger(MigrationMalformedDataLogger.class); private static Set malformedVFs = new HashSet<>(); - public static void addMalformedVF(String vfId) { + public static void reportMalformedVF(String vfId, String errorMsg) { + log.error(errorMsg); malformedVFs.add(vfId); } + public static void logMalformedDataMsg(String errorMsg) { + log.error(errorMsg); + } + public static void logIfServiceUsingMalformedVfs(Component service) { List componentInstances = service.getComponentInstances(); if (componentInstances != null && !componentInstances.isEmpty() && !malformedVFs.isEmpty()) { diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/ToscaPropertyType.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/ToscaPropertyType.java index 079d64a60e..ad226f4e57 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/ToscaPropertyType.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/ToscaPropertyType.java @@ -63,6 +63,8 @@ public enum ToscaPropertyType { FLOAT("float", FloatValidator.getInstance(), ToscaFloatConverter.getInstance(), FloatConverter.getInstance()), INTEGER("integer", IntegerValidator.getInstance(), DefaultConverter.getInstance(), IntegerConverter.getInstance()), + + SCALAR_UNIT("scalar-unit", StringValidator.getInstance(), DefaultConverter.getInstance(), ToscaValueDefaultConverter.getInstance()), SCALAR_UNIT_SIZE("scalar-unit.size", StringValidator.getInstance(), DefaultConverter.getInstance(), ToscaValueDefaultConverter.getInstance()), diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaMapValueConverter.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaMapValueConverter.java index 80b8779e1e..14f63650ac 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaMapValueConverter.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaMapValueConverter.java @@ -168,7 +168,7 @@ public class ToscaMapValueConverter extends ToscaValueBaseConverter implements T return handleComplexJsonValue(entryValue); } - // Tal G ticket 228696523 created / DE272734 / Bug 154492 Fix + // ticket 228696523 created / DE272734 / Bug 154492 Fix if(entryValue instanceof JsonArray) { ArrayList toscaObjectPresentationArray = new ArrayList<>(); JsonArray jsonArray = entryValue.getAsJsonArray(); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentDataTransfer.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentDataTransfer.java index 6eb7b841ab..36b6c574aa 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentDataTransfer.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentDataTransfer.java @@ -7,10 +7,8 @@ import org.openecomp.sdc.be.datatypes.components.ComponentMetadataDataDefinition import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.model.AdditionalInformationDefinition; import org.openecomp.sdc.be.model.ArtifactDefinition; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.CapabilityDefinition; import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceAttribute; import org.openecomp.sdc.be.model.ComponentInstanceInput; import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.GroupDefinition; @@ -48,7 +46,7 @@ public class UiComponentDataTransfer { private Map> componentInstancesProperties; - private Map> componentInstancesAttributes; + private Map> componentInstancesAttributes; private Map> capabilities; @@ -60,7 +58,7 @@ public class UiComponentDataTransfer { protected List additionalInformation; - + public UiComponentDataTransfer(){} public Map getArtifacts() { return artifacts; @@ -192,13 +190,13 @@ public class UiComponentDataTransfer { } - public Map> getComponentInstancesAttributes() { + public Map> getComponentInstancesAttributes() { return componentInstancesAttributes; } public void setComponentInstancesAttributes( - Map> componentInstancesAttributes) { + Map> componentInstancesAttributes) { this.componentInstancesAttributes = componentInstancesAttributes; } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentMetadata.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentMetadata.java index f0679d31de..6dabfc1402 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentMetadata.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiComponentMetadata.java @@ -64,6 +64,7 @@ public abstract class UiComponentMetadata { private String lastUpdaterFullName; + public UiComponentMetadata(){} public UiComponentMetadata (List categories, ComponentMetadataDataDefinition metadata) { diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceDataTransfer.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceDataTransfer.java index c56daa4fc9..2547457abc 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceDataTransfer.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceDataTransfer.java @@ -4,7 +4,6 @@ import java.util.List; import java.util.Map; import org.openecomp.sdc.be.model.AdditionalInformationDefinition; -import org.openecomp.sdc.be.model.AttributeDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.PropertyDefinition; @@ -18,7 +17,7 @@ public class UiResourceDataTransfer extends UiComponentDataTransfer{ private List properties; - private List attributes; + private List attributes; private Map interfaces; @@ -26,6 +25,8 @@ public class UiResourceDataTransfer extends UiComponentDataTransfer{ private List additionalInformation; + public UiResourceDataTransfer(){} + public List getAdditionalInformation() { return additionalInformation; } @@ -66,11 +67,11 @@ public class UiResourceDataTransfer extends UiComponentDataTransfer{ this.properties = properties; } - public List getAttributes() { + public List getAttributes() { return attributes; } - public void setAttributes(List attributes) { + public void setAttributes(List attributes) { this.attributes = attributes; } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceMetadata.java b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceMetadata.java index 19c7246462..3675bc619c 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceMetadata.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/ui/model/UiResourceMetadata.java @@ -16,6 +16,7 @@ public class UiResourceMetadata extends UiComponentMetadata { private String toscaResourceName; private List derivedFrom; + public UiResourceMetadata(List categories, List derivedFrom, ResourceMetadataDataDefinition metadata) { super(categories, metadata); this.vendorName = metadata.getVendorName(); @@ -27,6 +28,8 @@ public class UiResourceMetadata extends UiComponentMetadata { this.derivedFrom = derivedFrom; } + public UiResourceMetadata(){} + public List getDerivedFrom() { return derivedFrom; } diff --git a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts index db03aa53fb..b404a83634 100644 --- a/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts +++ b/catalog-ui/src/app/directives/graphs-v2/composition-graph/composition-graph.directive.ts @@ -168,7 +168,7 @@ export class CompositionGraph implements ng.IDirective { this.ComponentServiceNg2.getCapabilitiesAndRequirements(leftPaletteComponent.componentType, leftPaletteComponent.uniqueId).subscribe((response: ComponentGenericResponse) => { - let component = this.ComponentFactory.createEmptyComponent(leftPaletteComponent.componentType); + let component = this.ComponentFactory.createEmptyComponent(leftPaletteComponent.componentType); component.uniqueId = component.uniqueId; component.capabilities = response.capabilities; component.requirements = response.requirements; @@ -246,6 +246,7 @@ export class CompositionGraph implements ng.IDirective { this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_VERSION_CHANGED, (component:Component) => { scope.component = component; + this._cy.elements().remove(); this.loadGraphData(scope); }); diff --git a/catalog-ui/src/app/directives/property-types/type-map/type-map-directive.ts b/catalog-ui/src/app/directives/property-types/type-map/type-map-directive.ts index a0c9a6c460..fa71e47804 100644 --- a/catalog-ui/src/app/directives/property-types/type-map/type-map-directive.ts +++ b/catalog-ui/src/app/directives/property-types/type-map/type-map-directive.ts @@ -96,15 +96,17 @@ export class TypeMapDirective implements ng.IDirective { } else { scope.parentFormObj[fieldName].$setValidity('keyExist', true); if (!scope.parentFormObj[fieldName].$invalid) { + //To preserve the order of the keys, delete each one and recreate let newObj = {}; - angular.forEach(scope.valueObjRef,function(value:any,key:string){ + angular.copy(scope.valueObjRef , newObj); + angular.forEach(newObj,function(value:any,key:string){ + delete scope.valueObjRef[key]; if(key == oldKey){ - newObj[newKey] = value; + scope.valueObjRef[newKey] = value; }else{ - newObj[key] = value; + scope.valueObjRef[key] = value; } }); - scope.valueObjRef = newObj; } } }; diff --git a/catalog-ui/src/app/models.ts b/catalog-ui/src/app/models.ts index 5b286d0667..838137ba72 100644 --- a/catalog-ui/src/app/models.ts +++ b/catalog-ui/src/app/models.ts @@ -29,6 +29,7 @@ export * from './models/properties-inputs/property-fe-model'; export * from './models/properties-inputs/property-fe-map'; export * from './models/properties-inputs/derived-fe-property'; export * from './models/properties-inputs/input-fe-model'; +export * from './models/properties-inputs/simple-flat-property'; export * from './models/data-types-map'; export * from './models/data-types'; export * from './models/distribution'; @@ -82,3 +83,5 @@ export * from './models/component-metadata'; export * from './models/button'; export * from './models/filter-properties-assignment-data' +export * from './models/properties-inputs/input-be-model' + diff --git a/catalog-ui/src/app/models/components/component.ts b/catalog-ui/src/app/models/components/component.ts index 898285f032..c7cc81fae7 100644 --- a/catalog-ui/src/app/models/components/component.ts +++ b/catalog-ui/src/app/models/components/component.ts @@ -205,7 +205,19 @@ export abstract class Component implements IComponent { //------------------------------------------ API Calls ----------------------------------------------------------------// public changeLifecycleState = (state:string, commentObj:AsdcComment):ng.IPromise => { - return this.componentService.changeLifecycleState(this, state, JSON.stringify(commentObj)); + let deferred = this.$q.defer(); + let onSuccess = (componentMetadata:ComponentMetadata):void => { + this.setComponentMetadata(componentMetadata); + // this.version = componentMetadata.version; + this.lifecycleState = componentMetadata.lifecycleState; + + deferred.resolve(this); + }; + let onError = (error:any):void => { + deferred.reject(error); + }; + this.componentService.changeLifecycleState(this, state, JSON.stringify(commentObj)).then(onSuccess, onError); + return deferred.promise; }; public getComponent = ():ng.IPromise => { @@ -892,7 +904,7 @@ export abstract class Component implements IComponent { this.systemName = componentMetadata.systemName; this.projectCode = componentMetadata.projectCode; this.categories = componentMetadata.categories; - + } public toJSON = ():any => { diff --git a/catalog-ui/src/app/models/graph/graph-links/links-factory.ts b/catalog-ui/src/app/models/graph/graph-links/links-factory.ts index 7fdc0838ed..1744aa0ff3 100644 --- a/catalog-ui/src/app/models/graph/graph-links/links-factory.ts +++ b/catalog-ui/src/app/models/graph/graph-links/links-factory.ts @@ -33,19 +33,20 @@ export class LinksFactory { let newRelation:CompositionCiLinkBase; - let fromNode:CompositionCiNodeBase = cy.getElementById(relation.fromNode).data(); - let toNode:CompositionCiNodeBase = cy.getElementById(relation.toNode).data(); - - if ((relation.fromNode && fromNode.isUcpePart) || (relation.toNode && toNode.isUcpePart )) { //Link from or to node inside ucpe - - if (singleRelation && singleRelation.relationship.type && singleRelation.relationship.type == 'tosca.relationships.HostedOn') { - newRelation = new LinkUcpeHost(relation, singleRelation); - } else if (singleRelation.relationship.type && _.includes(singleRelation.relationship.type.toLowerCase(), 'link')) { - newRelation = new CompositionCiVlUcpeLink(relation, fromNode.isUcpePart, singleRelation); - } else { - newRelation = new CompositionCiUcpeLink(relation, fromNode.isUcpePart, singleRelation); - } - } else if (singleRelation.relationship.type && _.includes(singleRelation.relationship.type.toLowerCase(), 'link')) { + // let fromNode:CompositionCiNodeBase = cy.getElementById(relation.fromNode).data(); + // let toNode:CompositionCiNodeBase = cy.getElementById(relation.toNode).data(); + // + // if ((relation.fromNode && fromNode.isUcpePart) || (relation.toNode && toNode.isUcpePart )) { //Link from or to node inside ucpe + // + // if (singleRelation && singleRelation.relationship.type && singleRelation.relationship.type == 'tosca.relationships.HostedOn') { + // newRelation = new LinkUcpeHost(relation, singleRelation); + // } else if (singleRelation.relationship.type && _.includes(singleRelation.relationship.type.toLowerCase(), 'link')) { + // newRelation = new CompositionCiVlUcpeLink(relation, fromNode.isUcpePart, singleRelation); + // } else { + // newRelation = new CompositionCiUcpeLink(relation, fromNode.isUcpePart, singleRelation); + // } + // } else + if (singleRelation.relationship.type && _.includes(singleRelation.relationship.type.toLowerCase(), 'link')) { newRelation = new CompositionCiVLink(relation, singleRelation); } else { newRelation = new CompositionCiSimpleLink(relation, singleRelation); diff --git a/catalog-ui/src/app/models/properties-inputs/derived-fe-property.ts b/catalog-ui/src/app/models/properties-inputs/derived-fe-property.ts index 1d79353453..f7117e456c 100644 --- a/catalog-ui/src/app/models/properties-inputs/derived-fe-property.ts +++ b/catalog-ui/src/app/models/properties-inputs/derived-fe-property.ts @@ -1,15 +1,11 @@ import { SchemaPropertyGroupModel, SchemaProperty } from '../aschema-property'; -import { PROPERTY_DATA, PROPERTY_TYPES} from 'app/utils'; -import { PropertyBEModel } from '../../models'; +import { DerivedPropertyType, PropertyBEModel } from '../../models'; +import { PROPERTY_TYPES } from 'app/utils'; +import { UUID } from "angular2-uuid"; -export enum DerivedPropertyType { - SIMPLE, - LIST, - MAP, - COMPLEX //other datatype, list of non-simple, or map of non-simple -} export class DerivedFEProperty extends PropertyBEModel { + valueObj: any; parentName: string; propertiesName: string; //"network_assignments#ipv4_subnet#use_ipv4 = parentPath + name derivedDataType: DerivedPropertyType; @@ -17,56 +13,39 @@ export class DerivedFEProperty extends PropertyBEModel { isSelected: boolean; isDisabled: boolean; isChildOfListOrMap: boolean; + canBeDeclared: boolean; + mapKey: string; - constructor(property: PropertyBEModel, parentName?: string) - constructor(name: string, parentName: string, type: string, value: string, isChildOfListOrMap?:boolean, schema?: SchemaPropertyGroupModel); - constructor(nameOrPropertyObj?: string | PropertyBEModel, parentName?: string, type?: string, value?: string, isChildOfListOrMap?: boolean, schema?: SchemaPropertyGroupModel) { - - super(typeof nameOrPropertyObj === 'string' ? null : nameOrPropertyObj); - - if (typeof nameOrPropertyObj !== 'string') { //constructor #1 + constructor(property: PropertyBEModel, parentName?: string, createChildOfListOrMap?: boolean, key?:string, value?:any) { + if (!createChildOfListOrMap) { //creating a standard derived prop + super(property); this.parentName = parentName ? parentName : null; - this.propertiesName = (parentName) ? parentName + '#' + nameOrPropertyObj.name : nameOrPropertyObj.name; - } else { //constructor #2 - this.name = nameOrPropertyObj; - this.type = type; + this.propertiesName = (parentName) ? parentName + '#' + property.name : property.name; + this.canBeDeclared = true; //defaults to true + } else { //creating a direct child of list or map (ie. Item that can be deleted, with UUID instead of name) + super(null); + this.isChildOfListOrMap = true; + this.canBeDeclared = false; + this.name = UUID.UUID(); this.parentName = parentName; - this.propertiesName = parentName + '#' + nameOrPropertyObj; - this.value = value; - if (schema) { - this.schema = new SchemaPropertyGroupModel(new SchemaProperty(schema.property)); + this.propertiesName = parentName + '#' + this.name; + + + if (property.type == PROPERTY_TYPES.LIST) { + this.mapKey = property.schema.property.type.split('.').pop(); + this.type = property.schema.property.type; + } else { //map + this.mapKey = key || ""; + this.type = property.type; } + this.valueObj = (this.type == PROPERTY_TYPES.JSON && typeof value == 'object') ? JSON.stringify(value) : value; + this.schema = new SchemaPropertyGroupModel(new SchemaProperty(property.schema.property)); } this.derivedDataType = this.getDerivedPropertyType(); - this.isChildOfListOrMap = (isChildOfListOrMap) ? isChildOfListOrMap : false; } - - public getDerivedPropertyType = () => { - if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) > -1) { - return DerivedPropertyType.SIMPLE; - } else if (this.type == PROPERTY_TYPES.LIST) { - return DerivedPropertyType.LIST; - } else if (this.type == PROPERTY_TYPES.MAP) { - return DerivedPropertyType.MAP; - } else { - return DerivedPropertyType.COMPLEX; - } - } } export class DerivedFEPropertyMap { [parentPath: string]: Array; } - - -// isDataType: boolean; - - -// canAdd: boolean; -// canCollapse: boolean; -// canBeDeclared: boolean; - -// derivedValue: string; -// derivedValueType: string; -// propertiesName: string; \ No newline at end of file diff --git a/catalog-ui/src/app/models/properties-inputs/input-be-model.ts b/catalog-ui/src/app/models/properties-inputs/input-be-model.ts new file mode 100644 index 0000000000..6d7854a6bf --- /dev/null +++ b/catalog-ui/src/app/models/properties-inputs/input-be-model.ts @@ -0,0 +1,49 @@ +import {PropertyBEModel} from 'app/models'; +/** + * Created by rc2122 on 6/1/2017. + */ +export class InputBEModel extends PropertyBEModel { + properties:Array; + inputs:Array; + + constructor(input?: PropertyBEModel) { + super(input); + } + + + + public toJSON = (): any => { + }; + +} + +export class ComponentInstanceProperty extends PropertyBEModel { + componentInstanceId:string; + componentInstanceName:string; + + constructor(property?: PropertyBEModel) { + super(property); + } + + + + public toJSON = (): any => { + }; + +} + +export class ComponentInstanceInput extends InputBEModel { + componentInstanceId:string; + componentInstanceName:string; + + constructor(property?: PropertyBEModel) { + super(property); + } + + + + public toJSON = (): any => { + }; + +} + diff --git a/catalog-ui/src/app/models/properties-inputs/input-fe-model.ts b/catalog-ui/src/app/models/properties-inputs/input-fe-model.ts index 1261df3d6d..03c923c228 100644 --- a/catalog-ui/src/app/models/properties-inputs/input-fe-model.ts +++ b/catalog-ui/src/app/models/properties-inputs/input-fe-model.ts @@ -1,25 +1,37 @@ import { SchemaPropertyGroupModel, SchemaProperty } from "../aschema-property"; import { PropertyBEModel } from "../../models"; import {PROPERTY_DATA} from "../../utils/constants"; +import {InputBEModel} from "./input-be-model"; -export class InputFEModel extends PropertyBEModel { +export class InputFEModel extends InputBEModel { isSimpleType: boolean; isDataType: boolean; instanceName: string; + instanceId: string; propertyName: string; - constructor(input?: PropertyBEModel) { + constructor(input?: InputBEModel) { super(input); if (input) { this.isSimpleType = PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) > -1; this.isDataType = PROPERTY_DATA.TYPES.indexOf(this.type) == -1; + let propNameIndex:number = this.name.indexOf('_'); this.instanceName = this.name.substring(0, propNameIndex); - if (input.inputPath) { - this.propertyName = input.inputPath.substring(0, input.inputPath.indexOf('#')) - } else { - this.propertyName = this.name.substring(propNameIndex + 1); + + if(input.properties && input.properties.length){ + this.instanceId = input.properties[0].componentInstanceId; + this.propertyName = input.properties[0].name; + }else if(input.inputs && input.inputs.length){ + this.instanceId = input.inputs[0].componentInstanceId; + this.propertyName = input.inputs[0].name; + }else{ + if (input.inputPath) { + this.propertyName = input.inputPath.substring(0, input.inputPath.indexOf('#')) + } else { + this.propertyName = this.name.substring(propNameIndex + 1); + } } } } diff --git a/catalog-ui/src/app/models/properties-inputs/property-be-model.ts b/catalog-ui/src/app/models/properties-inputs/property-be-model.ts index a5279d0668..f5cd4094f5 100644 --- a/catalog-ui/src/app/models/properties-inputs/property-be-model.ts +++ b/catalog-ui/src/app/models/properties-inputs/property-be-model.ts @@ -1,4 +1,11 @@ import { SchemaPropertyGroupModel, SchemaProperty } from "../aschema-property"; +import { PROPERTY_DATA, PROPERTY_TYPES } from 'app/utils'; +export enum DerivedPropertyType { + SIMPLE, + LIST, + MAP, + COMPLEX +} export class PropertyBEModel { @@ -16,6 +23,7 @@ export class PropertyBEModel { definition: boolean; inputPath: string; propertiesName: string; + ownerId: string; input: PropertyBEModel; constructor(property?: PropertyBEModel, childProperty?:PropertyBEModel) { @@ -32,6 +40,7 @@ export class PropertyBEModel { this.uniqueId = property.uniqueId; this.value = property.value ? property.value : property.defaultValue; this.definition = property.definition; + this.ownerId = property.ownerId; if (property.inputPath) { this.inputPath = property.inputPath; } @@ -39,6 +48,8 @@ export class PropertyBEModel { if (childProperty) { this.input = childProperty; this.propertiesName = childProperty.propertiesName; + } else { + this.propertiesName = this.name; } if (!this.schema || !this.schema.property) { @@ -48,7 +59,7 @@ export class PropertyBEModel { } } - + public toJSON = (): any => { let temp = angular.copy(this); @@ -57,6 +68,18 @@ export class PropertyBEModel { return temp; }; + public getDerivedPropertyType = () => { + if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) > -1) { + return DerivedPropertyType.SIMPLE; + } else if (this.type == PROPERTY_TYPES.LIST) { + return DerivedPropertyType.LIST; + } else if (this.type == PROPERTY_TYPES.MAP) { + return DerivedPropertyType.MAP; + } else { + return DerivedPropertyType.COMPLEX; + } + } + } diff --git a/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts b/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts index 29f2c79225..564611c344 100644 --- a/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts +++ b/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts @@ -1,86 +1,40 @@ import {SchemaPropertyGroupModel, SchemaProperty} from '../aschema-property'; -import { PROPERTY_DATA } from 'app/utils'; -import { PropertyBEModel, DerivedFEPropertyMap, DerivedFEProperty } from '../../models'; +import { PROPERTY_DATA, PROPERTY_TYPES } from 'app/utils'; +import { FilterPropertiesAssignmentData, PropertyBEModel, DerivedPropertyType, DerivedFEPropertyMap, DerivedFEProperty } from 'app/models'; export class PropertyFEModel extends PropertyBEModel { - //START - TO REMOVE: - treeNodeId: string; - parent: PropertyFEModel; - - childrenProperties: Array; - isAllChildrenLevelsCalculated: boolean; - uniqueId: string; - valueObjectRef: any; - //END - TO REMOVE: - expandedChildPropertyId: string; flattenedChildren: Array; //[parentPath] : Array - isDataType: boolean; //aka- isComplexType. (Type is NOT: simple, list, or map) isDeclared: boolean; isDisabled: boolean; isSelected: boolean; - isSimpleType: boolean; - - private _derivedFromSimpleTypeName:string; - get derivedFromSimpleTypeName():string { - return this._derivedFromSimpleTypeName; - } - set derivedFromSimpleTypeName(derivedFromSimpleTypeName:string) { - this._derivedFromSimpleTypeName = derivedFromSimpleTypeName; - } - - constructor(property?: PropertyBEModel); - constructor(name: string, type: string, treeNodeId: string, parent: PropertyFEModel, valueObjectRef: any, schema?: SchemaPropertyGroupModel); - constructor(nameOrPropertyObj?: string | PropertyBEModel, type?: string, treeNodeId?: string, parent?: PropertyFEModel, valueObjectRef?: any, schema?: SchemaPropertyGroupModel) { - - super(typeof nameOrPropertyObj === 'string' ? null : nameOrPropertyObj); - - if (typeof nameOrPropertyObj === 'string') { - this.name = nameOrPropertyObj; - this.type = type; - this.treeNodeId = treeNodeId; - this.parent = parent; - this.valueObjectRef = valueObjectRef; - this.value = this.value || this.defaultValue; - if(schema){ - this.schema = new SchemaPropertyGroupModel(new SchemaProperty(schema.property)); - } - } + isSimpleType: boolean; //for convenience only - we can really just check if derivedDataType == derivedPropertyTypes.SIMPLE to know if the prop is simple + uniqueId: string; + valueObj: any; //this is the only value we relate to in the html templates + derivedDataType: DerivedPropertyType; + constructor(property: PropertyBEModel){ + super(property); this.isSimpleType = PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) > -1; - this.isDataType = PROPERTY_DATA.TYPES.indexOf(this.type) == -1; this.setNonDeclared(); + this.derivedDataType = this.getDerivedPropertyType(); + this.flattenedChildren = []; } - public convertChildToInput = (childName: string): void => { - //childName: "mac_count_required" - let childJson = this.flattenedChildren[childName].map((child) => { - }); - }; - - public getChildJsonRecursive = (child: string, value?: string): void => { - //TODO: use array.map for the below - /* value += "{" + this.flattenedChildren[child].name + ":"; - if (this.flattenedChildren[child].valueType == 'simple') { - value += this.flattenedChildren[child].value + '}'; - return value; - } else { - this.flattenedChildren[child].forEach(grandChild => { - if (this.flattenedChildren[grandChild].valueType == 'simple') { - return "{" + this.flattenedChildren[grandChild].name + ':' + this.flattenedChildren[child].value.toString() + "}"; - } else { - return this.getChildJsonRecursive(grandChild + '#' + this.flattenedChildren[child].name); - } - }); + public getJSONValue = (): string => { + //If type is JSON, need to try parsing it before we stringify it so that it appears property in TOSCA - change per Bracha due to AMDOCS + //TODO: handle this.derivedDataType == DerivedPropertyType.MAP + if (this.derivedDataType == DerivedPropertyType.LIST && this.schema.property.type == PROPERTY_TYPES.JSON) { + try { + return JSON.stringify(this.valueObj.map(item => JSON.parse(item))); + } catch (e){} } - return "{" + this.flattenedChildren[child].name + this.flattenedChildren[child].value.toString() + "}"; -*/ - - }; + return (this.derivedDataType == DerivedPropertyType.SIMPLE) ? this.valueObj : JSON.stringify(this.valueObj); + } public setNonDeclared = (childPath?: string): void => { if (!childPath) { //declaring a child prop @@ -102,31 +56,26 @@ export class PropertyFEModel extends PropertyBEModel { } } - - - //For expand-collapse functionality + //For expand-collapse functionality - used within HTML template public updateExpandedChildPropertyId = (childPropertyId: string): void => { if (childPropertyId.lastIndexOf('#') > -1) { this.expandedChildPropertyId = (this.expandedChildPropertyId == childPropertyId) ? (childPropertyId.substring(0, childPropertyId.lastIndexOf('#'))) : childPropertyId; } else { this.expandedChildPropertyId = this.name; } - //console.log("expandedChild is now " + this.expandedChildPropertyId); } - public convertToServerObject: Function = (): any => { //TODO: Idan, Rachel, Nechama: Decide what we need to do here - // let serverObject = {}; - // let mapData = { - // 'type': this.type, - // 'required': this.required || false, - // 'defaultValue': this.defaultValue != '' && this.defaultValue != '[]' && this.defaultValue != '{}' ? this.defaultValue : null, - // 'description': this.description, - // 'isPassword': this.password || false, - // 'schema': this.schema, - // 'name': this.name - // }; - // serverObject[this.name] = mapData; + public getIndexOfChild = (childPropName: string): number => { + return this.flattenedChildren.findIndex(prop => prop.propertiesName.indexOf(childPropName) === 0); + } + + public getCountOfChildren = (childPropName: string):number => { + let matchingChildren:Array = this.flattenedChildren.filter(prop => prop.propertiesName.indexOf(childPropName) === 0) || []; + return matchingChildren.length; + } + + // public getListIndexOfChild = (childPropName: string): number => { //gets list of siblings and then the index within that list + // this.flattenedChildren.filter(prop => prop.parentName == item.parentName).map(prop => prop.propertiesName).indexOf(item.propertiesName) + // } - //return JSON.stringify(serverObject); - }; } diff --git a/catalog-ui/src/app/models/properties-inputs/simple-flat-property.ts b/catalog-ui/src/app/models/properties-inputs/simple-flat-property.ts new file mode 100644 index 0000000000..d67a7d4d14 --- /dev/null +++ b/catalog-ui/src/app/models/properties-inputs/simple-flat-property.ts @@ -0,0 +1,15 @@ +export class SimpleFlatProperty { + uniqueId: string; + path: string; + name: string; + parentName: string; + instanceName: string; + + constructor(uniqueId?: string, path?: string, name?: string, parentName?: string, instanceName?: string) { + this.uniqueId = uniqueId; + this.path = path; + this.name = name; + this.parentName = parentName; + this.instanceName = instanceName; + } +} \ No newline at end of file diff --git a/catalog-ui/src/app/models/property-fe-model.ts b/catalog-ui/src/app/models/property-fe-model.ts deleted file mode 100644 index f83d6d6b51..0000000000 --- a/catalog-ui/src/app/models/property-fe-model.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {SchemaPropertyGroupModel, SchemaProperty} from './aschema-property'; -import { PROPERTY_DATA } from 'app/utils'; -import { FilterPropertiesAssignmentData, PropertyBEModel } from 'app/models'; - -export class PropertyFEModel extends PropertyBEModel { - public static filterData:FilterPropertiesAssignmentData; - childrenProperties: Array; - expandedChildPropertyId: string; - isAllChildrenLevelsCalculated: boolean; - isDataType: boolean; - isDisabled: boolean; - isSelected: boolean; - isSimpleType: boolean; - parent: PropertyFEModel; - treeNodeId: string; - valueObjectRef: any; - private _derivedFromSimpleTypeName:string; - get derivedFromSimpleTypeName():string { - return this._derivedFromSimpleTypeName; - } - set derivedFromSimpleTypeName(derivedFromSimpleTypeName:string) { - this._derivedFromSimpleTypeName = derivedFromSimpleTypeName; - } - - constructor(property?: PropertyBEModel); - constructor(name: string, type: string, treeNodeId: string, parent: PropertyFEModel, valueObjectRef: any, schema?: SchemaPropertyGroupModel); - constructor(nameOrPropertyObj?: string | PropertyBEModel, type?: string, treeNodeId?: string, parent?: PropertyFEModel, valueObjectRef?: any, schema?: SchemaPropertyGroupModel) { - - super(typeof nameOrPropertyObj === 'string' ? null : nameOrPropertyObj); - - if (typeof nameOrPropertyObj === 'string') { - this.name = nameOrPropertyObj; - this.type = type; - this.treeNodeId = treeNodeId; - this.parent = parent; - this.valueObjectRef = valueObjectRef; - this.value = this.value || this.defaultValue; - if(schema){ - this.schema = new SchemaPropertyGroupModel(new SchemaProperty(schema.property)); - } - } - this.isSimpleType = PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) > -1; - this.isDataType = PROPERTY_DATA.TYPES.indexOf(this.type) == -1; - this.setNonDeclared(); - } - - - public setNonDeclared = (): void => { - this.isSelected = false; - this.isDisabled = false; - } - - public setAsDeclared = (): void => { - this.isSelected = true; - this.isDisabled = true; - } - - //For expand-collapse functionality - public updateExpandedChildPropertyId = (childPropertyId: string): void => { - this.expandedChildPropertyId = (this.expandedChildPropertyId == childPropertyId) ? '' : childPropertyId; - } - - public convertToServerObject: Function = (): any => { //TODO: Idan, Rachel, Nechama: Decide what we need to do here - // let serverObject = {}; - // let mapData = { - // 'type': this.type, - // 'required': this.required || false, - // 'defaultValue': this.defaultValue != '' && this.defaultValue != '[]' && this.defaultValue != '{}' ? this.defaultValue : null, - // 'description': this.description, - // 'isPassword': this.password || false, - // 'schema': this.schema, - // 'name': this.name - // }; - // serverObject[this.name] = mapData; - - //return JSON.stringify(serverObject); - }; -} diff --git a/catalog-ui/src/app/modules/view-model-module.ts b/catalog-ui/src/app/modules/view-model-module.ts index 4060fe794e..7bfc014c36 100644 --- a/catalog-ui/src/app/modules/view-model-module.ts +++ b/catalog-ui/src/app/modules/view-model-module.ts @@ -53,7 +53,7 @@ import {ReqAndCapabilitiesViewModel} from "../view-models/workspace/tabs/req-and import {InputFormViewModel} from "../view-models/forms/input-form/input-form-view-modal"; import {HierarchyViewModel} from "../view-models/tabs/hierarchy/hierarchy-view-model"; import {downgradeComponent} from "@angular/upgrade/static"; -import {ConformanceLevelModalViewModel} from "../view-models/workspace/conformance-level-modal/conformance-level-modal-view-model"; +import {ConformanceLevelModalViewModel} from "../view-models/modals/conformance-level-modal/conformance-level-modal-view-model"; // import {NG2ExampleComponent} from "../ng2/view-ng2/ng2.example.component/ng2.example.component"; // import {upgradeAdapter} from "../ng2/app.module"; // import { UpgradeAdapter } from '@angular/upgrade'; diff --git a/catalog-ui/src/app/ng2/app.module.ts b/catalog-ui/src/app/ng2/app.module.ts index 9e122cd288..ea73d382e2 100644 --- a/catalog-ui/src/app/ng2/app.module.ts +++ b/catalog-ui/src/app/ng2/app.module.ts @@ -8,7 +8,7 @@ import {UpgradeModule} from '@angular/upgrade/static'; import {PropertiesAssignmentModule} from './pages/properties-assignment/properties-assignment.module'; import { DataTypesServiceProvider, SharingServiceProvider, CookieServiceProvider, - StateParamsServiceFactory + StateParamsServiceFactory, CacheServiceProvider, EventListenerServiceProvider } from "./utils/ng1-upgraded-provider"; import {ConfigService} from "./services/config.service"; import {HttpService} from "./services/http.service"; @@ -48,6 +48,8 @@ export function configServiceFactory(config:ConfigService) { SharingServiceProvider, CookieServiceProvider, StateParamsServiceFactory, + CacheServiceProvider, + EventListenerServiceProvider, AuthenticationService, Cookie2Service, ConfigService, diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/dynamic-element.component.ts b/catalog-ui/src/app/ng2/components/dynamic-element/dynamic-element.component.ts index de5965e488..84ac46c4cf 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/dynamic-element.component.ts +++ b/catalog-ui/src/app/ng2/components/dynamic-element/dynamic-element.component.ts @@ -4,6 +4,7 @@ import { UiElementDropDownComponent, DropdownValue } from './elements-ui/dropdow import { UiElementInputComponent } from './elements-ui/input/ui-element-input.component'; import {UiElementPopoverInputComponent} from "./elements-ui/popover-input/ui-element-popover-input.component"; import {ValidationConfiguration} from "app/models"; +import {UiElementIntegerInputComponent} from "./elements-ui/integer-input/ui-element-integer-input.component"; @Component({ selector: 'dynamic-element', @@ -13,7 +14,8 @@ import {ValidationConfiguration} from "app/models"; UiElementInputComponent, UiElementDropDownComponent, UiElementCheckBoxComponent, - UiElementPopoverInputComponent + UiElementPopoverInputComponent, + UiElementIntegerInputComponent ] }) export class DynamicElementComponent { @@ -21,6 +23,7 @@ export class DynamicElementComponent { @ViewChild('target', { read: ViewContainerRef }) target: any; @Input() type: any; @Input() name: string; + @Input() readonly:boolean; value:any; // Two way binding for value (need to write the "Change" word like this) @@ -50,17 +53,16 @@ export class DynamicElementComponent { // Factory to create component based on type or peroperty name. switch(this.type) { case 'list': - case 'integer': - this.createComponent(UiElementInputComponent); + case 'integer': + this.createComponent(UiElementIntegerInputComponent); this.cmpRef.instance.pattern = this.validation.validationPatterns.integer; break; case 'string': - switch(this.name.toUpperCase()) { - case 'SUBNETPOOLID': - this.createComponent(UiElementPopoverInputComponent); - break; - default: - this.createComponent(UiElementInputComponent); + if (this.name.toUpperCase().indexOf("SUBNETPOOLID") !== -1) { + this.createComponent(UiElementPopoverInputComponent); + } + else { + this.createComponent(UiElementInputComponent); } break; case 'boolean': @@ -84,6 +86,7 @@ export class DynamicElementComponent { this.cmpRef.instance.name = this.name; this.cmpRef.instance.type = this.type; this.cmpRef.instance.value = this.value; + this.cmpRef.instance.readonly = this.readonly; } // Subscribe to change event of of ui-element-basic and fire event to change the value diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/dynamic-element.module.ts b/catalog-ui/src/app/ng2/components/dynamic-element/dynamic-element.module.ts index 18b044bc9d..f53b8616ac 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/dynamic-element.module.ts +++ b/catalog-ui/src/app/ng2/components/dynamic-element/dynamic-element.module.ts @@ -8,6 +8,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { UiElementPopoverInputComponent } from "./elements-ui/popover-input/ui-element-popover-input.component"; import {PopoverModule} from "../popover/popover.module"; import {TooltipModule} from "../tooltip/tooltip.module"; +import {UiElementIntegerInputComponent} from "./elements-ui/integer-input/ui-element-integer-input.component"; @NgModule({ declarations: [ @@ -15,7 +16,8 @@ import {TooltipModule} from "../tooltip/tooltip.module"; UiElementInputComponent, UiElementCheckBoxComponent, UiElementDropDownComponent, - UiElementPopoverInputComponent + UiElementPopoverInputComponent, + UiElementIntegerInputComponent ], imports: [ BrowserModule, diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/checkbox/ui-element-checkbox.component.html b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/checkbox/ui-element-checkbox.component.html index 2ad3d8e94a..a3e28c5f0b 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/checkbox/ui-element-checkbox.component.html +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/checkbox/ui-element-checkbox.component.html @@ -1 +1 @@ - + diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/dropdown/ui-element-dropdown.component.html b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/dropdown/ui-element-dropdown.component.html index 589d00e42d..bfb927af71 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/dropdown/ui-element-dropdown.component.html +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/dropdown/ui-element-dropdown.component.html @@ -1,3 +1,3 @@ - diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/dropdown/ui-element-dropdown.component.ts b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/dropdown/ui-element-dropdown.component.ts index 208bf54983..b1fb37a186 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/dropdown/ui-element-dropdown.component.ts +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/dropdown/ui-element-dropdown.component.ts @@ -18,7 +18,6 @@ export class DropdownValue { styleUrls: ['./ui-element-dropdown.component.less'], }) export class UiElementDropDownComponent extends UiElementBase implements UiElementBaseInterface { - @Input() values: DropdownValue[]; @@ -27,7 +26,7 @@ export class UiElementDropDownComponent extends UiElementBase implements UiEleme } onSave() { - this.baseEmitter.emit(this.value); + this.baseEmitter.emit(JSON.parse(this.value)); } } diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/input/ui-element-input.component.html b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/input/ui-element-input.component.html index 00fea65b72..814ebfd28b 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/input/ui-element-input.component.html +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/input/ui-element-input.component.html @@ -10,4 +10,6 @@ [pattern]="pattern" [formControl]="control" tooltip="{{value}}" + [readonly]="readonly" + [ngClass]="{'disabled':readonly}" /> diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/input/ui-element-input.component.ts b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/input/ui-element-input.component.ts index 5a14d8f206..2d64d9b713 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/input/ui-element-input.component.ts +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/input/ui-element-input.component.ts @@ -1,4 +1,4 @@ -import { Component, ViewChild, ElementRef, ContentChildren } from '@angular/core'; +import {Component, ViewChild, ElementRef, ContentChildren, Input} from '@angular/core'; import { BrowserModule } from '@angular/platform-browser' import { UiElementBase, UiElementBaseInterface } from './../ui-element-base.component'; @@ -8,7 +8,6 @@ import { UiElementBase, UiElementBaseInterface } from './../ui-element-base.comp styleUrls: ['./ui-element-input.component.less'], }) export class UiElementInputComponent extends UiElementBase implements UiElementBaseInterface { - constructor() { super(); this.pattern = this.validation.validationPatterns.comment; diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.html b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.html new file mode 100644 index 0000000000..e5518d453f --- /dev/null +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.html @@ -0,0 +1,15 @@ + diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.less b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.less new file mode 100644 index 0000000000..8073c3858e --- /dev/null +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.less @@ -0,0 +1,17 @@ +@import '../../../../../../assets/styles/variables'; + +/deep/ ui-element-integer-input { + + input { + text-indent: 6px; + border: solid 1px @main_color_o; + } + + .error { + border: solid 1px @func_color_q; + color: @func_color_q; + outline: none; + box-sizing: border-box; + } + +} diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.ts b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.ts new file mode 100644 index 0000000000..d42c80a89e --- /dev/null +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/integer-input/ui-element-integer-input.component.ts @@ -0,0 +1,21 @@ +import {Component, ViewChild, ElementRef, ContentChildren, Input} from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser' +import { UiElementBase, UiElementBaseInterface } from './../ui-element-base.component'; + +@Component({ + selector: 'ui-element-integer-input', + templateUrl: './ui-element-integer-input.component.html', + styleUrls: ['./ui-element-integer-input.component.less'], +}) +export class UiElementIntegerInputComponent extends UiElementBase implements UiElementBaseInterface { + constructor() { + super(); + this.pattern = this.validation.validationPatterns.comment; + } + + onSave() { + if (!this.control.invalid){ + this.baseEmitter.emit(JSON.parse(this.value)); + } + } +} diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/popover-input/ui-element-popover-input.component.html b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/popover-input/ui-element-popover-input.component.html index 5adceb49a0..3bd51b4e36 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/popover-input/ui-element-popover-input.component.html +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/popover-input/ui-element-popover-input.component.html @@ -4,10 +4,10 @@ type="text" [ngClass]="{'error': control.invalid}" [name]="name" - [value]="value" + [value]="value!=undefined?value:''" disabled /> - + diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/popover-input/ui-element-popover-input.component.ts b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/popover-input/ui-element-popover-input.component.ts index 7300417686..84dd884d1f 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/popover-input/ui-element-popover-input.component.ts +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/popover-input/ui-element-popover-input.component.ts @@ -1,4 +1,4 @@ -import {Component, ViewChild, ElementRef} from '@angular/core'; +import {Component, ViewChild, ElementRef, Input} from '@angular/core'; import {UiElementBase, UiElementBaseInterface} from "../ui-element-base.component"; import {ButtonsModelMap, ButtonModel} from "app/models"; import { PopoverContentComponent } from "app/ng2/components/popover/popover-content.component" @@ -10,7 +10,6 @@ import { PopoverComponent } from "app/ng2/components/popover/popover.component" styleUrls: ['./ui-element-popover-input.component.less'] }) export class UiElementPopoverInputComponent extends UiElementBase implements UiElementBaseInterface { - @ViewChild('textArea') textArea: ElementRef; @ViewChild('popoverForm') popoverContentComponent: PopoverContentComponent; diff --git a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/ui-element-base.component.ts b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/ui-element-base.component.ts index b60271f6f0..fa2be1048c 100644 --- a/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/ui-element-base.component.ts +++ b/catalog-ui/src/app/ng2/components/dynamic-element/elements-ui/ui-element-base.component.ts @@ -25,6 +25,7 @@ export class UiElementBase { protected type: string; protected value: any; protected pattern: any; + protected readonly:boolean; constructor() { //this.control = new FormControl('', [Validators.required]); diff --git a/catalog-ui/src/app/ng2/components/filter-properties-assignment/filter-properties-assignment.component.less b/catalog-ui/src/app/ng2/components/filter-properties-assignment/filter-properties-assignment.component.less index c1341b8dcf..afed54672c 100644 --- a/catalog-ui/src/app/ng2/components/filter-properties-assignment/filter-properties-assignment.component.less +++ b/catalog-ui/src/app/ng2/components/filter-properties-assignment/filter-properties-assignment.component.less @@ -6,6 +6,13 @@ form{ &:not(:last-child){ border-bottom: solid 1px @main_color_o; } + input{ + &::-webkit-input-placeholder { font-style: italic; } /* Safari, Chrome and Opera */ + &:-moz-placeholder { font-style: italic; } /* Firefox 18- */ + &::-moz-placeholder { font-style: italic; } /* Firefox 19+ */ + &:-ms-input-placeholder { font-style: italic; } /* IE 10+ */ + &:-ms-input-placeholder { font-style: italic; } /* Edge */ + } } /deep/ [ng-reflect-checked="true"]{ /deep/ .checkbox-label-content{ @@ -16,7 +23,7 @@ form{ .open-filter-button{ cursor: pointer; - width: 25px; + width: 32px; height: 34px; display: inline-block; &.open{ @@ -29,6 +36,7 @@ form{ } .filter-icon{ top: 8px; + right: 2px; position: relative; } } diff --git a/catalog-ui/src/app/ng2/components/inputs-table/confirmation-delete-input/confirmation-delete-input.component.html b/catalog-ui/src/app/ng2/components/inputs-table/confirmation-delete-input/confirmation-delete-input.component.html new file mode 100644 index 0000000000..7fdd95b304 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/inputs-table/confirmation-delete-input/confirmation-delete-input.component.html @@ -0,0 +1,3 @@ + + Are you sure you want to delete this input? + diff --git a/catalog-ui/src/app/ng2/components/inputs-table/confirmation-delete-input/confirmation-delete-input.component.ts b/catalog-ui/src/app/ng2/components/inputs-table/confirmation-delete-input/confirmation-delete-input.component.ts new file mode 100644 index 0000000000..24c37b5636 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/inputs-table/confirmation-delete-input/confirmation-delete-input.component.ts @@ -0,0 +1,38 @@ +/** + * Created by rc2122 on 6/1/2017. + */ +import {Component, Output, EventEmitter, ViewChild} from "@angular/core"; +import {ButtonsModelMap, ButtonModel} from "app/models/button"; +import {ModalComponent} from "app/ng2/components/modal/modal.component"; + +@Component({ + selector: 'confirm-delete-input', + templateUrl: './confirmation-delete-input.component.html' +}) +export class ConfirmationDeleteInputComponent { + + @Output() deleteInput: EventEmitter = new EventEmitter(); + @ViewChild ('confirmationModal') confirmationModal:ModalComponent; + footerButtons:ButtonsModelMap = {}; + + constructor (){ + } + + ngOnInit() { + this.footerButtons['Delete'] = new ButtonModel('Delete', 'blue', this.onDeleteInput); + this.footerButtons['Close'] = new ButtonModel('Close', 'grey', this.closeModal); + } + + onDeleteInput = (input) => { + this.deleteInput.emit(input); + this.closeModal(); + }; + + openModal = () => { + this.confirmationModal.open(); + } + + closeModal = () => { + this.confirmationModal.close(); + } +} diff --git a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.html b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.html index e7801b82cf..fb6b04013f 100644 --- a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.html +++ b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.html @@ -1,4 +1,5 @@
+
Property Name
Type
@@ -7,31 +8,39 @@
No data to display
-
-
- {{input.name}} - -
-
{{input.type | contentAfterLastDot}}
-
{{input.schema && input.schema.property && input.schema.property.type ? (input.schema.property.type | contentAfterLastDot) : ''}}
-
- - -
- +
+
+
+
{{input.name}}
+ +
+
+
+ {{input.type | contentAfterLastDot}} +
+
+
{{input.schema && input.schema.property && input.schema.property.type ? (input.schema.property.type | contentAfterLastDot) : ''}}
+
+ + +
+ +
-
+
+ diff --git a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less new file mode 100644 index 0000000000..93f96470bc --- /dev/null +++ b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.less @@ -0,0 +1,178 @@ + +@import './../../../../assets/styles/variables.less'; + +:host /deep/ input { width:100%;} + +.properties-table { + display:flex; + flex-direction:column; + flex: 1; + height:100%; + text-align:left; + + dynamic-property { + width:100%; + } + + /deep/ .dynamic-property-row { + border-top:solid #d2d2d2 1px; + } + + /deep/ dynamic-property dynamic-property:first-of-type .dynamic-property-row:not(.with-top-border) { + border-top: none; + } + + .table-header { + font-weight:bold; + border-top: #d2d2d2 solid 1px; + background-color: #eaeaea; + + .valueCol { + justify-content: flex-start; + padding: 5px; + } + } + .table-header, .table-row { + display: flex; + flex-direction:row; + flex: 0 0 auto; + } + + .table-body { + display:flex; + flex-direction: column; + overflow-y:auto; + flex: 1; + + .no-data { + border: #d2d2d2 solid 1px; + border-top:none; + text-align: center; + height: 100%; + padding: 20px; + } + /deep/.selected{ + background-color: #e6f6fb; + color: #009fdb; + } + } + + .table-rows-header { + font-size:16px; + flex:1; + border: #d2d2d2 solid 1px; + border-top:none; + padding: 5px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + background-color: @tlv_color_v; + } + + .table-row { + &:hover { + background-color:#f8f8f8; cursor:pointer; + } + + &:last-child { + flex: 1 0 auto; + } + .selected-row { + background-color:#e6f6fb; + } + } + .cut-inner-long-text{ + text-overflow: ellipsis; + overflow: hidden; + } + .table-cell { + font-size:13px; + flex:1; + border: #d2d2d2 solid 1px; + border-right:none; + border-top:none; + padding: 5px; + text-overflow: ellipsis; + white-space: nowrap; + + + &:last-child { + border-right:#d2d2d2 solid 1px; + } + &.col1 { + flex: 0 0 300px; + max-width:300px; + display: flex; + justify-content: space-between; + + .property-name { + flex: 1; + } + + .property-description-icon { + float: right; + margin-top: 4px; + margin-left: 5px; + flex: 0 0 auto; + } + } + &.col2 { + flex: 0 0 150px; + max-width:150px; + } + + &.col3 { + flex:0 0 120px; + max-width:120px; + } + + &.valueCol { + flex: 1 0 auto; + min-width: 350px; + display: flex; + justify-content: flex-end; + padding: 0px; + + .value-input { + flex: 1; + max-height: 24px; + border: none; + background-color: inherit; + + &:focus, &:active { + border:none; + outline:none; + } + } + + .delete-btn { + flex: 0 0 auto; + } + + .delete-button-container { + max-height: 24px; + } + + &.inner-table-container { + padding: 0px; + + .delete-button-container { + padding: 3px 5px 0 0 ; + } + } + } + + &.input-value-col { + padding: 5px; + } + + + } + + .filtered { + /deep/ .checkbox-label-content{ + background-color: yellow; + } + } + +} diff --git a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.ts b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.ts index ea01edf043..83c0bda991 100644 --- a/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.ts +++ b/catalog-ui/src/app/ng2/components/inputs-table/inputs-table.component.ts @@ -1,20 +1,25 @@ /** * Created by rc2122 on 5/4/2017. */ -import {Component, Input, Output, EventEmitter} from "@angular/core"; +import {Component, Input, Output, EventEmitter, ViewChild} from "@angular/core"; import {InputFEModel} from "app/models"; +import {ConfirmationDeleteInputComponent} from "./confirmation-delete-input/confirmation-delete-input.component"; @Component({ selector: 'inputs-table', templateUrl: './inputs-table.component.html', - styleUrls: ['../properties-table/properties-table.component.less'] + styleUrls: ['../inputs-table/inputs-table.component.less'] }) export class InputsTableComponent { @Input() inputs: Array; - + @Input() readonly:boolean; + @Input() isLoading:boolean; @Output() inputValueChanged: EventEmitter = new EventEmitter(); @Output() deleteInput: EventEmitter = new EventEmitter(); + @ViewChild ('deleteInputConfirmation') deleteInputConfirmation:ConfirmationDeleteInputComponent; + + selectedInputToDelete:InputFEModel; constructor (){ } @@ -23,11 +28,14 @@ export class InputsTableComponent { this.inputValueChanged.emit(input); }; - onDeleteInput = (input) => { - this.deleteInput.emit(input); - } - + onDeleteInput = () => { + this.deleteInput.emit(this.selectedInputToDelete); + }; + openDeleteModal = (input:InputFEModel) => { + this.selectedInputToDelete = input; + this.deleteInputConfirmation.openModal(); + } } diff --git a/catalog-ui/src/app/ng2/components/loader/loader.component.html b/catalog-ui/src/app/ng2/components/loader/loader.component.html new file mode 100644 index 0000000000..0e13cee674 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/loader/loader.component.html @@ -0,0 +1,5 @@ +
+
+
+
+ diff --git a/catalog-ui/src/app/ng2/components/loader/loader.component.less b/catalog-ui/src/app/ng2/components/loader/loader.component.less new file mode 100644 index 0000000000..054b6021a1 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/loader/loader.component.less @@ -0,0 +1,75 @@ +@import '../../../../assets/styles/variables'; +.tlv-loader-back { + background-color: @main_color_p; + position: fixed; + top: 50px; + left: 0; + right: 0; + bottom: 0; + z-index: 9999; + opacity: 0.5; +} + +.tlv-loader-relative { position: absolute; top: 0;} + +.tlv-loader { + z-index: 10002; +} + +@keyframes fadein { + from { opacity: 0; } + to { opacity: 0.8; } +} + +/* Firefox < 16 */ +@-moz-keyframes fadein { + from { opacity: 0; } + to { opacity: 0.8; } +} + +/* Safari, Chrome and Opera > 12.1 */ +@-webkit-keyframes fadein { + from { opacity: 0; } + to { opacity: 0.8; } +} + +/* Internet Explorer */ +@-ms-keyframes fadein { + from { opacity: 0; } + to { opacity: 0.8; } +} + +/* Opera < 12.1 */ +@-o-keyframes fadein { + from { opacity: 0; } + to { opacity: 0.8; } +} + +@keyframes fadeout { + from { opacity: 0.8; } + to { opacity: 0; } +} + +/* Firefox < 16 */ +@-moz-keyframes fadeout { + from { opacity: 0.8; } + to { opacity: 0; } +} + +/* Safari, Chrome and Opera > 12.1 */ +@-webkit-keyframes fadeout { + from { opacity: 0.8; } + to { opacity: 0; } +} + +/* Internet Explorer */ +@-ms-keyframes fadeout { + from { opacity: 0.8; } + to { opacity: 0; } +} + +/* Opera < 12.1 */ +@-o-keyframes fadeout { + from { opacity: 0.8; } + to { opacity: 0; } +} diff --git a/catalog-ui/src/app/ng2/components/loader/loader.component.ts b/catalog-ui/src/app/ng2/components/loader/loader.component.ts new file mode 100644 index 0000000000..4d90b2853d --- /dev/null +++ b/catalog-ui/src/app/ng2/components/loader/loader.component.ts @@ -0,0 +1,92 @@ +/** + * Created by rc2122 on 6/6/2017. + */ +import {Component, Input, ElementRef, Renderer, SimpleChanges} from "@angular/core"; +@Component({ + selector: 'loader', + templateUrl: './loader.component.html', + styleUrls: ['./loader.component.less'] +}) +export class LoaderComponent { + + @Input() display:boolean; + @Input() size:string;// small || medium || large + @Input() elementSelector:string; // required if is relative true + @Input() relative:boolean; + + interval; + + constructor (private el: ElementRef, private renderer: Renderer){ + } + + ngOnInit() { + + if (this.elementSelector) { + let elemParent = angular.element(this.elementSelector); + let positionStyle:string = elemParent.css('position'); + this.setStyle(positionStyle); + } + + if (this.relative === true) { + let positionStyle:string = this.el.nativeElement.parentElement.style.position; + this.setStyle(positionStyle); + } + if (!this.size) { + this.size = 'large'; + } + } + + ngOnDestroy(){ + clearInterval(this.interval); + } + + calculateSizesForFixPosition = (positionStyle:string):void => { + // This is problematic, I do not want to change the parent position. + // set the loader on all the screen + let parentLeft = this.el.nativeElement.parentElement.offsetLeft; + let parentTop = this.el.nativeElement.parentElement.offsetTop; + let parentWidth = this.el.nativeElement.parentElement.offsetWidth; + let parentHeight = this.el.nativeElement.parentElement.offsetHeight; + this.renderer.setElementStyle(this.el.nativeElement, 'position', positionStyle); + this.renderer.setElementStyle(this.el.nativeElement, 'top', parentTop); + this.renderer.setElementStyle(this.el.nativeElement, 'left', parentLeft); + this.renderer.setElementStyle(this.el.nativeElement, 'width', parentWidth); + this.renderer.setElementStyle(this.el.nativeElement, 'height', parentHeight); + }; + + setStyle = (positionStyle:string):void => { + + switch (positionStyle) { + case 'absolute': + case 'fixed': + // The parent size is not set yet, still loading, so need to use interval to update the size. + this.interval = window.setInterval(()=> { + this.calculateSizesForFixPosition(positionStyle); + }, 2000); + break; + default: + // Can change the parent position to relative without causing style issues. + this.renderer.setElementStyle(this.el.nativeElement.parentElement,'position', 'relative'); + break; + } + }; + + ngOnChanges(changes: SimpleChanges) { + if(changes.display){ + this.changeLoaderDisplay(false); + if ( this.display ) { + window.setTimeout(():void => { + this.changeLoaderDisplay(true); + }, 500); + } else { + window.setTimeout(():void => { + this.changeLoaderDisplay(false); + }, 0); + } + } + } + + changeLoaderDisplay = (display:boolean):void => { + this.renderer.setElementStyle(this.el.nativeElement, 'display', display ? 'block' : 'none'); + } +} diff --git a/catalog-ui/src/app/ng2/components/modal/modal.component.html b/catalog-ui/src/app/ng2/components/modal/modal.component.html new file mode 100644 index 0000000000..4882449596 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/modal/modal.component.html @@ -0,0 +1,18 @@ +
+
+
+ {{ title }} + +
+
+ +
+ +
+
+ diff --git a/catalog-ui/src/app/ng2/components/modal/modal.component.less b/catalog-ui/src/app/ng2/components/modal/modal.component.less new file mode 100644 index 0000000000..a35f829e6a --- /dev/null +++ b/catalog-ui/src/app/ng2/components/modal/modal.component.less @@ -0,0 +1,115 @@ +@import '../../../../assets/styles/variables'; +@import '../../../../assets/styles/mixins'; +@import '../../../../assets/styles/sprite-old'; +/deep/ modal { + display: none; + + .custom-modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1000; + overflow: auto; + margin: auto; + display: flex; + align-items: center; + + .ng2-modal-content { + background: #fff; + width: 100%; + box-shadow: 0 5px 15px rgba(0,0,0,.5); + border-radius: 4px; + .ng2-modal-body{ + padding: 20px; + } + + .ng2-modal-header{ + .m_18_m; + font-weight: bold; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + height: 50px; + line-height: 50px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + text-align: left; + border-bottom: solid 1px @main_color_o; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin: 0px 20px; + .title{ + -webkit-box-flex: 999; + -ms-flex-positive: 999; + flex-grow: 999; + } + .close-button{ + .sprite; + .sprite.x-btn-black; + cursor: pointer; + } + } + + .ng2-modal-footer{ + background-color: @tlv_color_t; + padding: 17px 30px; + clear: both; + -webkit-box-flex: 1; + -ms-flex-positive: 1; + flex-grow: 1; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + border-radius: 4px; + button{ + margin: 0 12px 0 6px; + } + } + } + } + + .modal-background { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: #000; + opacity: 0.5; + z-index: 900; + } +} + +.xl { + width: 1200px; +} + +.l { + width: 875px; +} + +.md { + width: 650px; +} + +.sm { + width: 552px; +} + +.xsm { + width: 432px; +} + +body.modal-open { + overflow: hidden; +} diff --git a/catalog-ui/src/app/ng2/components/modal/modal.component.ts b/catalog-ui/src/app/ng2/components/modal/modal.component.ts new file mode 100644 index 0000000000..4a00871b21 --- /dev/null +++ b/catalog-ui/src/app/ng2/components/modal/modal.component.ts @@ -0,0 +1,46 @@ +/** + * Created by rc2122 on 6/1/2017. + */ +import { Component, ElementRef, Input, OnInit, OnDestroy } from '@angular/core'; +import * as $ from 'jquery'; +import {ButtonsModelMap} from "app/models/button"; + +@Component({ + selector: 'modal', + templateUrl: './modal.component.html', + styleUrls:['modal.component.less'] +}) + +export class ModalComponent implements OnInit, OnDestroy { + @Input() size: string; 'xl|l|md|sm|xsm' + @Input() title: string; + @Input() public buttons:ButtonsModelMap; + private modalElement: JQuery; + private buttonsNames:Array; + + constructor( el: ElementRef ) { + this.modalElement = $(el.nativeElement); + } + + ngOnInit(): void { + let modal = this; + this.modalElement.appendTo('body'); + if(this.buttons){ + this.buttonsNames = Object.keys(this.buttons); + } + } + + ngOnDestroy(): void { + this.modalElement.remove(); + } + + open(): void { + this.modalElement.show(); + $('body').addClass('modal-open'); + } + + close(): void { + this.modalElement.hide(); + $('body').removeClass('modal-open'); + } +} diff --git a/catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.html b/catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.html deleted file mode 100644 index 6e7d4e882b..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.html +++ /dev/null @@ -1,24 +0,0 @@ - -
-
- -
- -
-
-
-
-
- {{propertyObj.type | contentAfterLastDot }} - V -
-
-
-
- {{propertyObj.name}} -
-
-
-
-
- diff --git a/catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.less b/catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.less deleted file mode 100644 index 3102c5ceb8..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.less +++ /dev/null @@ -1,35 +0,0 @@ -.derived-property-row { - display:flex; - flex-direction:row; - position:relative; - border-top: #d2d2d2 solid 1px; - - &:first-child { - border-top:none; - } - .table-cell { - flex: 0 0 50%; - padding:5px; - position:relative; - text-overflow: ellipsis; - white-space: nowrap; - - &:first-child { - border-right:#d2d2d2 solid 1px; - overflow:hidden; - } - span.expand-icon { - position: absolute; - right: 10px; - transition: 200ms transform ease-in-out; - } - span.expand-icon.expanded { - transform: rotate(-180deg); - } - } -} -.filtered { - /deep/ .checkbox-label-content{ - background-color: yellow; - } -} diff --git a/catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.ts b/catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.ts deleted file mode 100644 index 16f069a685..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/derived-property/derived-property.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Created by rc2122 on 4/20/2017. - */ -import {Component, Input, Output, EventEmitter} from "@angular/core"; -import { DerivedFEProperty, DerivedPropertyType} from "app/models"; -import {PropertiesService} from "../../../services/properties.service"; - -@Component({ - selector: 'derived-property', - templateUrl: './derived-property.component.html', - styleUrls: ['./derived-property.component.less'] -}) -export class DerivedPropertyComponent { - - derivedPropertyTypes = DerivedPropertyType; //http://stackoverflow.com/questions/35835984/how-to-use-a-typescript-enum-value-in-an-angular2-ngswitch-statement - - @Input() propertyObj: DerivedFEProperty; - @Input() propertyNameSearchText: string; - @Input() expanded: boolean; - @Output() valueChanged: EventEmitter = new EventEmitter(); - @Output() expandChild: EventEmitter = new EventEmitter(); - @Output() selectProperty: EventEmitter = new EventEmitter(); - - - constructor ( private propertiesService:PropertiesService){ - } - - - propValueChanged = () => { - this.valueChanged.emit(this.propertyObj); - }; - - expandChildById = (id: string) => { - this.expandChild.emit(id); - } - - checkedChange = (isChecked:boolean) => { - this.selectProperty.emit(isChecked); - } - - addRows = (flatProperty: DerivedFEProperty): void => { - console.log("ADDING A ROW OF TYPE " + flatProperty.type); - console.log(flatProperty); - } - -} diff --git a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html index 17e4002ae5..d6ee568c0c 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html +++ b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html @@ -1,66 +1,65 @@
- + -
- +
{{property.name}}
+
+ +
- - -
+ + +
- - - -
- {{property.type | contentAfterLastDot }} -
-
- -
-
-
-
- {{property.schema.property.type | contentAfterLastDot }} -
-
- - -
- - V + +
{{property.type | contentAfterLastDot }}
+
{{property.schema.property.type | contentAfterLastDot }}
+
+ +
+
+ + + + + V
- - - + +
+ - +
diff --git a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.less b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.less index 53cde3035a..cb7cd39640 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.less +++ b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.less @@ -1,40 +1,40 @@ +.flat-children-container { + dynamic-property:first-child .dynamic-property-row:not(.with-top-border) { + border-top:none; + } + .dynamic-property-row { + border-top: solid 1px #CCC; + } +} .dynamic-property-row { display:flex; flex-direction:row; - position:relative; - + align-items: center; + .table-cell { - flex: 1 0 50%; + flex: 1; padding:5px; - position:relative; text-overflow: ellipsis; white-space: nowrap; - + overflow:hidden; + min-height:32px; - &.full-width { - border-right:none; - flex: 0 0 100%; - } - - &:first-child:not(:only-child) { + &:first-child { + flex: 0 0 50%; border-right:#d2d2d2 solid 1px; - overflow:hidden; + + + &:only-of-type { + flex: 1 1 100%; + border-right:none; + } } - - } - span.delete-item-icon{ - position: absolute; - right: 25px; - top: 10px; } - span.add-item-icon { - float:right; + .property-icon { + flex: 0 0 auto; } span.expand-icon { - position: absolute; - top:6px; - right: 10px; transition: 200ms transform ease-in-out; } span.expand-icon.expanded { diff --git a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts index 0ca93a773f..1c7fbfac7a 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts +++ b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts @@ -3,7 +3,6 @@ import { PropertyBEModel, PropertyFEModel, DerivedFEProperty, DerivedPropertyTyp import { PROPERTY_DATA, PROPERTY_TYPES } from 'app/utils'; import { PropertiesUtils } from "app/ng2/pages/properties-assignment/properties.utils"; import { DataTypeService } from "../../../services/data-type.service"; -import { UUID } from "angular2-uuid"; @Component({ @@ -17,64 +16,33 @@ export class DynamicPropertyComponent { propType: DerivedPropertyType; propPath: string; isPropertyFEModel: boolean; - mapOfIDsAndKeys: Map = new Map(); //used for map and list + childrenCount: number; - childrenCanBeDeclared: boolean; @Input() canBeDeclared: boolean; @Input() property: PropertyFEModel | DerivedFEProperty; - @Input() propChildren: Array; @Input() expandedChildId: string; @Input() selectedPropertyId: string; + @Input() propertyNameSearchText: string; + @Input() readonly: boolean; @Output() valueChanged: EventEmitter = new EventEmitter(); @Output() expandChild: EventEmitter = new EventEmitter(); @Output() checkProperty: EventEmitter = new EventEmitter(); @Output() deleteItem: EventEmitter = new EventEmitter(); @Output() clickOnPropertyRow: EventEmitter = new EventEmitter(); + @Output() mapKeyChanged: EventEmitter = new EventEmitter(); + @Output() addChildPropsToParent: EventEmitter> = new EventEmitter>(); + constructor(private propertiesUtils: PropertiesUtils, private dataTypeService: DataTypeService) { } ngOnInit() { this.isPropertyFEModel = this.property instanceof PropertyFEModel; - if (this.property instanceof PropertyFEModel) { - this.propType = this.getDerivedPropertyType(this.property.type); - this.propPath = this.property.name; - } else { - this.propType = this.property.derivedDataType; - this.propPath = this.property.propertiesName; - } - - this.childrenCanBeDeclared = this.canBeDeclared && this.propType != this.derivedPropertyTypes.MAP && this.propType != this.derivedPropertyTypes.LIST; - - if (this.propType == this.derivedPropertyTypes.LIST || this.propType == this.derivedPropertyTypes.MAP) { - this.initializeValues(); - } - + this.propType = this.property.derivedDataType; + this.propPath = (this.property instanceof PropertyFEModel) ? this.property.name : this.property.propertiesName; } - initializeValues = () => { - let tempValue: any; - if (this.property.value) { - tempValue = JSON.parse(this.property.value); - if (!_.isEmpty(tempValue)) { - tempValue.forEach((element, key) => { - let newChildID: string = this.createNewChildProperty(JSON.stringify(element)); - this.mapOfIDsAndKeys[newChildID] = key; - console.log(this.mapOfIDsAndKeys); - }); - } - } - //this.pseudoChildren = []; - //this.valueObjRef = []; - //TODO: generate necessary elements for existing values here - // if (this.propType == this.derivedPropertyTypes.LIST) { - // this.valueObjRef = (this.property.value) ? JSON.parse(this.property.value) : []; - // } else if (this.propType == this.derivedPropertyTypes.MAP) { - // this.valueObjRef = (this.property.value)? JSON.parse(this.property.value) : {}; - // } - console.log(this.property.value); - } onClickPropertyRow = (property, event) => { // Because DynamicPropertyComponent is recrusive second time the event is fire event.stopPropagation = undefined @@ -82,68 +50,106 @@ export class DynamicPropertyComponent { this.clickOnPropertyRow.emit(property); } - deleteListOrMapItem = (itemName: string) => { - this.propChildren = this.propChildren.filter(prop => prop.propertiesName.indexOf(itemName) != 0); //remove item and children; - } - - propValueChanged = (property) => { - console.log("property value change!! Prop type: " + property.type + " New value: " + property.value); - this.valueChanged.emit(property); - }; expandChildById = (id: string) => { this.expandedChildId = id; - this.expandChild.emit(id); + this.expandChild.emit(id); } checkedChange = (propName: string) => { this.checkProperty.emit(propName); } + hasChildren = (): number => { + return (this.property.valueObj && typeof this.property.valueObj == 'object') ? Object.keys(this.property.valueObj).length : 0; + } + createNewChildProperty = (): void => { + + let newProps: Array = this.propertiesUtils.createListOrMapChildren(this.property, "", null); + if (this.property instanceof PropertyFEModel) { + this.addChildProps(newProps, this.property.name); + } else { + this.addChildPropsToParent.emit(newProps); + } + } - addRows = (): void => { //from within the template, when creating empty item - let childPropId = this.createNewChildProperty(); - this.expandChildById(this.propPath + "#" + childPropId); + addChildProps = (newProps: Array, childPropName: string) => { + + if (this.property instanceof PropertyFEModel) { + let insertIndex: number = this.property.getIndexOfChild(childPropName) + this.property.getCountOfChildren(childPropName); //insert after parent prop and existing children + this.property.flattenedChildren.splice(insertIndex, 0, ...newProps); //using ES6 spread operator + this.expandChildById(newProps[0].propertiesName); + } } - createNewChildProperty = (value?:string):string => { - let propUUID:string = UUID.UUID(); - let newProp: DerivedFEProperty; - if (this.propType == this.derivedPropertyTypes.LIST) { //for list - create new prop of schema type - newProp = new DerivedFEProperty(propUUID, this.propPath, this.property.schema.property.type, value, true); - } else { //for map - create new prop of type map, with schema, but with flag that its a child - newProp = new DerivedFEProperty(propUUID, this.propPath, this.property.type, value, true, this.property.schema); + childValueChanged = (property: DerivedFEProperty) => { //value of child property changed + + if (this.property instanceof PropertyFEModel) { // will always be the case + let parentNames = this.getParentNamesArray(property.propertiesName, []); + if (parentNames.length) { + _.set(this.property.valueObj, parentNames.join('.'), property.valueObj); + } + console.log(parentNames); + this.valueChanged.emit(this.property.name); } + } + deleteListOrMapItem = (item: DerivedFEProperty) => { + if (this.property instanceof PropertyFEModel) { + this.removeValueFromParent(item); + this.property.flattenedChildren.splice(this.property.getIndexOfChild(item.propertiesName), this.property.getCountOfChildren(item.propertiesName)); + this.expandChildById(item.propertiesName); + } + } - this.propChildren = this.propChildren || []; - this.propChildren.push(newProp); + removeValueFromParent = (item: DerivedFEProperty, replaceKey?: string) => { + if (this.property instanceof PropertyFEModel) { + let itemParent = (item.parentName == this.property.name) ? this.property : this.property.flattenedChildren.find(prop => prop.propertiesName == item.parentName); + + if (item.derivedDataType == DerivedPropertyType.MAP) { + let oldKey = item.mapKey; + if (typeof replaceKey == 'string') { //allow saving empty string + _.set(itemParent.valueObj, replaceKey, itemParent.valueObj[oldKey]); + item.mapKey = replaceKey; + } + delete itemParent.valueObj[oldKey]; + } else { + let itemIndex: number = this.property.flattenedChildren.filter(prop => prop.parentName == item.parentName).map(prop => prop.propertiesName).indexOf(item.propertiesName); + itemParent.valueObj.splice(itemIndex, 1); + } - //if it's a complex type, add children properties - if (!this.property.schema.property.isSimpleType) { - let schemaDataType: DataTypeModel = this.dataTypeService.getDataTypeByTypeName(this.property.schema.property.type); - this.dataTypeService.getDerivedDataTypeProperties(schemaDataType, this.propChildren, newProp.propertiesName); - this.propertiesUtils.assignValuesRecursively(JSON.parse(value), this.propChildren, newProp.propertiesName); - console.log(JSON.stringify(this.propChildren)); + if (itemParent instanceof PropertyFEModel) { //direct child + this.valueChanged.emit(this.property.name); + } else { //nested child - need to update parent prop by getting flattened name (recurse through parents and replace map/list keys, etc) + this.childValueChanged(itemParent); + } } + } - return propUUID; - } + getParentNamesArray = (parentPropName: string, parentNames?: Array): Array => { + if (this.property instanceof PropertyFEModel) { + if (parentPropName.indexOf("#") == -1) { return parentNames; } //finished recursing parents. return - //TODO: remove this and move to somewhere central!! (or make all properties be the same type...) - getDerivedPropertyType = (type) => { - if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(type) > -1) { - return DerivedPropertyType.SIMPLE; - } else if (type == PROPERTY_TYPES.LIST) { - return DerivedPropertyType.LIST; - } else if (type == PROPERTY_TYPES.MAP) { - return DerivedPropertyType.MAP; - } else { - return DerivedPropertyType.COMPLEX; + let parentProp: DerivedFEProperty = this.property.flattenedChildren.find(prop => prop.propertiesName === parentPropName); + let nameToInsert: string = parentProp.name; + + if (parentProp.isChildOfListOrMap) { + if (parentProp.derivedDataType == DerivedPropertyType.MAP) { + nameToInsert = parentProp.mapKey; + } else { //LIST + let siblingProps = this.property.flattenedChildren.filter(prop => prop.parentName == parentProp.parentName).map(prop => prop.propertiesName); + nameToInsert = siblingProps.indexOf(parentProp.propertiesName).toString(); + } + } + + parentNames.splice(0, 0, nameToInsert); //add prop name to array + return this.getParentNamesArray(parentProp.parentName, parentNames); //continue recursing + } } + } diff --git a/catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.html b/catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.html deleted file mode 100644 index a251d33649..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.html +++ /dev/null @@ -1,33 +0,0 @@ -
-
-
-
- -
- - -
-
-
- - -
diff --git a/catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.less b/catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.less deleted file mode 100644 index 7c4d90a38d..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.less +++ /dev/null @@ -1,3 +0,0 @@ -.simple-list-item{ - position: relative; -} diff --git a/catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.ts b/catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.ts deleted file mode 100644 index 96f8c680a2..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/list-property/list-property.component.ts +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Created by rc2122 on 4/23/2017. - */ -import {Component, Input, Output, EventEmitter} from "@angular/core"; -import { PropertyFEModel} from "app/models"; -import {PropertiesService} from "app/ng2/services/properties.service"; -import { ContentAfterLastDotPipe } from "app/ng2/pipes/contentAfterLastDot.pipe"; -import {UUID} from "angular2-uuid"; -import {ComponentType} from "app/utils"; - -@Component({ - selector: 'list-property', - templateUrl: './list-property.component.html', - styleUrls: ['../properties-value-inner-table/properties-value-inner-table.component.less', './list-property.component.less'] -}) -export class ListPropertyComponent { - - @Input() property: PropertyFEModel; - @Input() selectedPropertyId: string; - @Input() propertyNameSearchText:string; - - @Output() valueChanged: EventEmitter = new EventEmitter(); - @Output() selectChildProperty: EventEmitter = new EventEmitter(); - - constructor ( private propertiesService:PropertiesService, private contentAfterLastDotPipe:ContentAfterLastDotPipe ){ - } - - propValueChanged = () => { - this.valueChanged.emit(this.property); - }; - - onChildPropertySelected = (property) => { - this.selectChildProperty.emit(property); - }; - - getNumber = (valueObjectRef: any): Array => { - let num: number = (valueObjectRef) ? valueObjectRef.length : 0; - return new Array(num); - } - - createNewChildProperty = ():void => { - let newProperty: PropertyFEModel = new PropertyFEModel(this.contentAfterLastDotPipe.transform(this.property.schema.property.type), - this.property.schema.property.type, - UUID.UUID(), - this.property, - this.property.valueObjectRef[this.property.childrenProperties.length] - ); - this.propertiesService.createPropertiesTreeForProp(newProperty); - this.property.childrenProperties.push(newProperty); - } - - addListItem = ():void => { - this.property.valueObjectRef = this.property.valueObjectRef || []; - this.property.childrenProperties = this.property.childrenProperties || []; - if (this.property.schema.property.isSimpleType){ - if( this.property.valueObjectRef.indexOf("") == -1 ) {//prevent insert multiple empty simple type items to list - this.property.valueObjectRef.push(""); - } - }else{ - this.property.valueObjectRef[this.property.childrenProperties.length] = {}; - this.property.childrenProperties = this.property.childrenProperties || []; - this.createNewChildProperty(); - this.valueChanged.emit(this.property); - } - } - - deleteListItem = (indexInList:number):void => { - this.property.valueObjectRef.splice(indexInList, 1); - if(this.property.childrenProperties){ - this.property.childrenProperties.splice(indexInList, 1); - } - if (!this.property.valueObjectRef.length) {//only when user removes all items from list - put the default - if ( this.property.defaultValue ) { - angular.copy(JSON.parse(this.property.defaultValue), this.property.valueObjectRef); - if (this.property.schema.property.isDataType){ - _.forEach(this.property.valueObjectRef, () => { - this.createNewChildProperty(); - }); - } - } - } - this.valueChanged.emit(this.property); - } - -} diff --git a/catalog-ui/src/app/ng2/components/properties-table/map-property/map-property.component.html b/catalog-ui/src/app/ng2/components/properties-table/map-property/map-property.component.html deleted file mode 100644 index e1975175a8..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/map-property/map-property.component.html +++ /dev/null @@ -1,38 +0,0 @@ -
-
-
- - - - diff --git a/catalog-ui/src/app/ng2/components/properties-table/map-property/map-property.component.ts b/catalog-ui/src/app/ng2/components/properties-table/map-property/map-property.component.ts deleted file mode 100644 index d62d0b94e3..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/map-property/map-property.component.ts +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Created by rc2122 on 4/24/2017. - */ -/** - * Created by rc2122 on 4/23/2017. - */ -import {Component, Input, Output, EventEmitter} from "@angular/core"; -import { PropertyFEModel} from "app/models"; -import { PropertiesService } from "../../../services/properties.service"; -import {ComponentType} from "app/utils"; -import {UUID} from "angular2-uuid"; - -@Component({ - selector: 'map-property', - templateUrl: './map-property.component.html', - styleUrls: ['../properties-value-inner-table/properties-value-inner-table.component.less'] -}) -export class MapPropertyComponent { - - @Input() property: PropertyFEModel; - @Input() selectedPropertyId: string; - @Input() propertyNameSearchText:string; - - @Output() valueChanged: EventEmitter = new EventEmitter(); - @Output() selectChildProperty: EventEmitter = new EventEmitter(); - - constructor ( private propertiesService:PropertiesService){ - } - - mapKeys:Array; - - ngOnInit() { - this.mapKeys = Object.keys(this.property.valueObjectRef); - } - - propValueChanged = () => { - this.valueChanged.emit(this.property); - }; - - onChildPropertySelected = (property) => { - this.selectChildProperty.emit(property); - }; - - getNumber = (num:number):Array => { - return new Array(num); - } - - createNewChildProperty = (mapKey:string):void => { - - let newProperty: PropertyFEModel = new PropertyFEModel(mapKey, - this.property.schema.property.type, - UUID.UUID(), this.property, - this.property.valueObjectRef[mapKey]); - this.propertiesService.createPropertiesTreeForProp(newProperty); - this.property.childrenProperties = this.property.childrenProperties || []; - this.property.childrenProperties.push(newProperty); - } - - //get: new key and the index of this item in the map - //This method checks if the new key isn't exist already in the map and update the object and the children array with the new key - changeKeyOfMap = (newKey:string, index:number):void => { - //let fieldName:string = "mapKey" + this.property.treeNodeId + index; - let oldKey:string = Object.keys(this.property.valueObjectRef)[index]; - let existsKeyIndex:number = Object.keys(this.property.valueObjectRef).indexOf(newKey); - if (existsKeyIndex > -1 && existsKeyIndex != index) { - //error for exists key validation - } else { - //remove error for exists key validation and if the form is valid - update the map object - let newObj = {}; - angular.forEach(this.property.valueObjectRef,function(value:any,key:string){ - if(key == oldKey){ - newObj[newKey] = value; - }else{ - newObj[key] = value; - } - }); - this.property.valueObjectRef = newObj; - this.property.parent.valueObjectRef[this.property.name] = this.property.valueObjectRef;//in order to prevent break ref - if(this.property.childrenProperties){ - this.property.childrenProperties[index].name = newKey;//update this property childrenProperties with the new key - } - } - } - - //get: index of the item in the map - //This method removes item from map. - deleteMapItem = (index:number):void=> { - delete this.property.valueObjectRef[this.mapKeys[index]]; - this.mapKeys.splice(index, 1); - if(this.property.childrenProperties){ - this.property.childrenProperties.splice(index, 1); - } - if (!this.mapKeys.length) {//only when user removes all pairs of key-value fields - put the default - if (this.property.defaultValue) { - angular.copy(JSON.parse(this.property.defaultValue), this.property.valueObjectRef); - this.mapKeys = Object.keys(this.property.valueObjectRef); - if (this.property.schema.property.isDataType){ - angular.forEach(this.property.valueObjectRef, (value, key) => { - this.createNewChildProperty(key); - }, this); - } - } - } - this.valueChanged.emit(this.property); - } - - //This method inserts new empty item to map - addMapItemFields = ():void => { - this.property.valueObjectRef = this.property.valueObjectRef || {}; - if (this.property.schema.property.isSimpleType){ - this.property.valueObjectRef[''] = null; - }else{ - if(!this.property.valueObjectRef['']){ - this.property.valueObjectRef[''] = {}; - this.createNewChildProperty(''); - } - } - this.mapKeys = Object.keys(this.property.valueObjectRef); - } -} - diff --git a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.html b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.html index 3ab47074e7..426ae3ab23 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.html +++ b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.html @@ -1,6 +1,5 @@ - -
+
Property Name
Type
@@ -13,16 +12,27 @@
{{instanceName | contentAfterLastDot}}
-
-
- - +
+ +
+
+ +
+ {{property.name}} +
+
+ +
+
+
+ {{property.type | contentAfterLastDot}} +
-
{{property.type | contentAfterLastDot}}
{{property.schema && property.schema.property && property.schema.property.type ? (property.schema.property.type | contentAfterLastDot) : ''}}
@@ -32,7 +42,8 @@ [canBeDeclared]="true" [property]="property" [expandedChildId]="property.expandedChildPropertyId" - [propChildren]="property.flattenedChildren | filterChildProperties : property.expandedChildPropertyId" + [propertyNameSearchText]="propertyNameSearchText" + [readonly]="readonly" (valueChanged)="propValueChanged(property);" (expandChild)="property.updateExpandedChildPropertyId($event)" (clickOnPropertyRow)="onClickPropertyInnerRow($event, instanceName)" @@ -42,94 +53,8 @@
- - -
- - - - diff --git a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less index de080dfdc9..bb019a768b 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less +++ b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.less @@ -10,38 +10,17 @@ height:100%; text-align:left; - - .child-property-container { - display:flex; - flex-direction:column; - - &.table-cell { - padding:0; - } - - .child-property-row { - border-bottom: #d2d2d2 solid 1px; - &:last-child { - border-bottom:none; - } - } - } - - - derived-property, dynamic-property { - width:100%; - } - - /deep/ dynamic-property dynamic-property .dynamic-property-row { - border-top:solid #d2d2d2 1px; - } - - /deep/ dynamic-property dynamic-property:first-of-type .dynamic-property-row:not(.with-top-border) { - border-top: none; + .inner-cell-div{ + max-width: 100%; + text-overflow: ellipsis; + overflow: hidden; + height: 20px; } - - properties-value-inner-table { - width: 100%; + + .table-header, .table-row { + display: flex; + flex-direction:row; + flex: 0 0 auto; } .table-header { @@ -54,10 +33,17 @@ padding: 5px; } } - .table-header, .table-row { - display: flex; - flex-direction:row; - flex: 0 0 auto; + + .table-rows-header { + font-size:16px; + flex:1; + border: #d2d2d2 solid 1px; + border-top:none; + padding: 5px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + background-color: @tlv_color_v; } .table-body { @@ -79,17 +65,6 @@ } } - .table-rows-header { - font-size:16px; - flex:1; - border: #d2d2d2 solid 1px; - border-top:none; - padding: 5px; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - background-color: @tlv_color_v; - } .table-row { &:hover { @@ -102,6 +77,10 @@ .selected-row { background-color:#e6f6fb; } + } + .cut-inner-long-text{ + text-overflow: ellipsis; + overflow: hidden; } .table-cell { font-size:13px; @@ -112,7 +91,7 @@ padding: 5px; text-overflow: ellipsis; white-space: nowrap; - overflow: hidden; + display: flex; &:last-child { border-right:#d2d2d2 solid 1px; @@ -120,10 +99,24 @@ &.col1 { flex: 0 0 300px; max-width:300px; + display: flex; + justify-content: space-between; + + .property-name { + flex: 1; + display: flex; + max-width: 270px; + } .property-description-icon { float: right; margin-top: 4px; + margin-left: 5px; + flex: 0 0 auto; + } + + /deep/ .checkbox-container { + margin-right: 5px; } } &.col2 { @@ -137,46 +130,12 @@ } &.valueCol { - flex: 1 0 auto; + flex: 1; min-width: 350px; display: flex; justify-content: flex-end; padding: 0px; - - .value-input { - flex: 1; - max-height: 24px; - border: none; - background-color: inherit; - - &:focus, &:active { - border:none; - outline:none; - } - } - - .delete-btn { - flex: 0 0 auto; - } - - .delete-button-container { - max-height: 24px; - } - - &.inner-table-container { - padding: 0px; - - .delete-button-container { - padding: 3px 5px 0 0 ; - } - } } - - &.input-value-col { - padding: 5px; - } - - } .filtered { @@ -184,5 +143,9 @@ background-color: yellow; } } + + dynamic-property { + width:100%; + } } diff --git a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.ts b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.ts index d5a9b40425..58214ca16b 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.ts +++ b/catalog-ui/src/app/ng2/components/properties-table/properties-table.component.ts @@ -2,8 +2,6 @@ import { Component, Input, Output, EventEmitter, SimpleChanges, ViewChild, Eleme import { trigger, state, style, transition, animate} from '@angular/core'; import {PropertyFEModel, DerivedFEProperty, DerivedPropertyType, InstanceFePropertiesMap} from "app/models"; import {PropertiesService} from "../../services/properties.service"; -// import { GroupByPipe } from 'app/ng2/pipes/groupBy.pipe'; -//import {PropertiesValueInnerTableComponent} from "./properties-table/properties-value-inner-table/properties-value-inner-table"; import { DynamicElementComponent } from 'app/ng2/components/dynamic-element/dynamic-element.component'; import { KeysPipe } from 'app/ng2/pipes/keys.pipe'; @@ -19,7 +17,10 @@ export class PropertiesTableComponent { @Input() selectedPropertyId: string; @Input() displayDeleteButton: boolean; @Input() propertyNameSearchText:string; - + @Input() searchTerm:string; + @Input() readonly:boolean; + @Input() isLoading:boolean; + @Output() valueChanged: EventEmitter = new EventEmitter(); @Output() selectPropertyRow: EventEmitter = new EventEmitter(); @Output() updateCheckedPropertyCount: EventEmitter = new EventEmitter(); @@ -50,6 +51,7 @@ export class PropertiesTableComponent { // Click on main row (row of propertyFEModel) onClickPropertyRow = (property:PropertyFEModel, instanceName:string, event?) => { //event && event.stopPropagation(); + this.selectedPropertyId = property.name; let propertyRowSelectedEvent:PropertyRowSelectedEvent = new PropertyRowSelectedEvent(property, instanceName); this.selectPropertyRow.emit(propertyRowSelectedEvent); }; @@ -72,14 +74,6 @@ export class PropertiesTableComponent { this.updateCheckedPropertyCount.emit(isChecked); } - putDefaultValueInEmptyProperty = (property:PropertyFEModel):void => { - property.value = property.value || property.defaultValue; - } - - // clickOnInstanceRow = (instanceName:string) =>{ - // this.selectInstanceRow.emit(instanceName); - // }; - } export class PropertyRowSelectedEvent { diff --git a/catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.html b/catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.html deleted file mode 100644 index 61555cac50..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - diff --git a/catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.less b/catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.less deleted file mode 100644 index 1b7f6d4cd1..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.less +++ /dev/null @@ -1,71 +0,0 @@ -table { width:100%;} -tr {border-bottom: #d2d2d2 solid 1px;} -tr:last-child { border-bottom:none;} -td { border:none; padding:5px;} -td:first-child { border-right:#d2d2d2 solid 1px;} - -.prop-value{ - span { - position: absolute; - top: 5px; - right: 2px; - - &.delete-span { - right:20px; - } - - &.datatype-text { - position:static; - } - - } -} - -.add-data-row { - padding:5px; - text-align:right; - border-bottom: #d2d2d2 solid 1px; - - &:last-child { - border-bottom:none; - } -} -.table-inner-row { - display:flex; - flex-direction:row; - border-bottom: #d2d2d2 solid 1px; - flex: 0 0 100%; - position:relative; - - &:last-child { - border-bottom:none; - } - - .table-cell { - flex: 0 0 50%; - padding:5px; - position:relative; - text-overflow: ellipsis; - white-space: nowrap; - - &:first-child { - border-right:#d2d2d2 solid 1px; - overflow:hidden; - } - - - } - - .table-inner-container, .inner-table-container { - flex: 0 0 100%; - } -} -/deep/ map-property, /deep/ properties-value-inner-table, /deep/ list-property{ - width:100%; -} - -.filtered { - /deep/ .checkbox-label-content{ - background-color: yellow; - } -} diff --git a/catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.ts b/catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.ts deleted file mode 100644 index 7d0b219ffe..0000000000 --- a/catalog-ui/src/app/ng2/components/properties-table/properties-value-inner-table/properties-value-inner-table.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Created by rc2122 on 4/20/2017. - */ -import {Component, Input, Output, EventEmitter} from "@angular/core"; -import {PropertyFEModel} from "app/models"; -import {PropertiesService} from "../../../services/properties.service"; - -@Component({ - selector: 'properties-value-inner-table', - templateUrl: './properties-value-inner-table.component.html', - styleUrls: ['./properties-value-inner-table.component.less'] -}) -export class PropertiesValueInnerTableComponent { - - @Input() property: PropertyFEModel; - @Input() selectedPropertyId: string; - @Input() propertyNameSearchText:string; - - @Output() selectChildProperty: EventEmitter = new EventEmitter(); - @Output() valueChanged: EventEmitter = new EventEmitter(); - - constructor ( private propertiesService:PropertiesService){ - } - - - onChildPropertySelected = (property) => { - this.selectChildProperty.emit(property); - }; - - propValueChanged = () => { - this.valueChanged.emit(this.property); - }; - - putDefaultValueInEmptyChildProperty = (childProp:PropertyFEModel):void => { - this.property.valueObjectRef[childProp.name] = this.property.valueObjectRef[childProp.name] || childProp.defaultValue; - } -} diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.module.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.module.ts index 6ef3e57678..b59ef9dbda 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.module.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.module.ts @@ -13,21 +13,20 @@ import { SearchFilterPipe } from "../../pipes/searchFilter.pipe"; import { FilterChildPropertiesPipe } from "../../pipes/filterChildProperties.pipe"; import { DataTypeService } from './../../services/data-type.service'; import { PropertiesService } from './../../services/properties.service'; +import { HierarchyNavService } from './../../services/hierarchy-nav.service'; import { PropertiesUtils } from './properties.utils'; import { PostsService } from "../../services/posts.service"; -import { PropertiesValueInnerTableComponent } from "./../../components/properties-table/properties-value-inner-table/properties-value-inner-table.component"; -import { ListPropertyComponent } from "./../../components/properties-table/list-property/list-property.component"; -import { MapPropertyComponent } from "./../../components/properties-table/map-property/map-property.component"; import { DynamicElementModule } from 'app/ng2/components/dynamic-element/dynamic-element.module'; import { DynamicPropertyComponent } from './../../components/properties-table/dynamic-property/dynamic-property.component'; -import { DerivedPropertyComponent } from './../../components/properties-table/derived-property/derived-property.component'; -// import {PopoverContentComponent} from "../../components/popover/popover-content.component" -// import {PopoverComponent} from "../../components/popover/popover.component" +import {ConfirmationDeleteInputComponent} from "app/ng2/components/inputs-table/confirmation-delete-input/confirmation-delete-input.component" import { PopoverModule } from "../../components/popover/popover.module" import { FilterPropertiesAssignmentComponent } from "./../../components/filter-properties-assignment/filter-properties-assignment.component"; import { GroupByPipe } from 'app/ng2/pipes/groupBy.pipe'; import { KeysPipe } from 'app/ng2/pipes/keys.pipe'; import {TooltipModule} from "../../components/tooltip/tooltip.module"; +import { ComponentModeService } from "app/ng2/services/component-mode.service" +import { ModalComponent } from "app/ng2/components/modal/modal.component" +import {LoaderComponent} from "app/ng2/components/loader/loader.component" @NgModule({ declarations: [ @@ -40,14 +39,13 @@ import {TooltipModule} from "../../components/tooltip/tooltip.module"; SearchFilterPipe, FilterChildPropertiesPipe, HierarchyNavigationComponent, - PropertiesValueInnerTableComponent, - ListPropertyComponent, - MapPropertyComponent, - DerivedPropertyComponent, DynamicPropertyComponent, // PopoverContentComponent, // PopoverComponent, - FilterPropertiesAssignmentComponent + FilterPropertiesAssignmentComponent, + ModalComponent, + ConfirmationDeleteInputComponent, + LoaderComponent ], imports: [ BrowserModule, @@ -65,7 +63,7 @@ import {TooltipModule} from "../../components/tooltip/tooltip.module"; // PopoverContentComponent, // PopoverComponent ], - providers: [PropertiesService, PropertiesUtils, DataTypeService, PostsService, ContentAfterLastDotPipe, GroupByPipe, KeysPipe] + providers: [PropertiesService, HierarchyNavService, PropertiesUtils, DataTypeService, PostsService, ContentAfterLastDotPipe, GroupByPipe, KeysPipe, ComponentModeService] }) export class PropertiesAssignmentModule { diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html index d1b671cff2..317a1fc827 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html @@ -4,9 +4,12 @@ - +
- - Clear All + + Clear All
- +
-
{{component.name}}
-
No data to display
- + +
+ {{component.name}} +
+
No data to display
+
-
{{propertyStructureHeader || selectedFlatProperty.name || "No Property Selected"}}
-
No data to display
- +
+ {{!isInpusTabSelected ? (propertyStructureHeader || selectedFlatProperty.name || "No Property Selected") : "No Property Selected"}} +
+
No data to display
+
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.less b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.less index f7a62bbcb5..e56374a2c2 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.less +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.less @@ -145,6 +145,12 @@ text-align: left; background-color: @ng2-light-gray; font-size: 13px; + span{ + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + max-width: 290px; + } } .hierarchy-nav { diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts index 299615b122..98fdc7391a 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts @@ -1,18 +1,23 @@ import {Component, ViewChild, ElementRef, Renderer, Inject} from "@angular/core"; import {PostsService} from "../../services/posts.service"; -import {PropertiesService, SimpleFlatProperty} from "../../services/properties.service"; +import { PropertiesService } from "../../services/properties.service"; +import { HierarchyNavService } from "../../services/hierarchy-nav.service"; import { PropertiesUtils } from './properties.utils'; import { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, InstancePropertiesAPIMap, Component as ComponentData, FilterPropertiesAssignmentData } from "app/models"; import { PROPERTY_TYPES, ResourceType } from "app/utils"; import property = require("lodash/property"); import {ComponentServiceNg2} from "../../services/component-services/component.service"; import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service" -import {InputFEModel, ComponentInstance, PropertyBEModel, DerivedFEProperty, ResourceInstance} from "app/models"; +import { InputFEModel, ComponentInstance, PropertyBEModel, DerivedPropertyType, DerivedFEProperty, ResourceInstance, SimpleFlatProperty } from "app/models"; import {HierarchyDisplayOptions} from "../../components/hierarchy-navigtion/hierarchy-display-options" import {PropertyRowSelectedEvent} from "./../../components/properties-table/properties-table.component"; import { KeysPipe } from 'app/ng2/pipes/keys.pipe'; import {FilterPropertiesAssignmentComponent} from "../../components/filter-properties-assignment/filter-properties-assignment.component"; - +import { ComponentModeService } from "app/ng2/services/component-mode.service" +import {WorkspaceMode, EVENTS} from "../../../utils/constants"; +import {ComponentInstanceProperty, InputBEModel} from "app/models" +import {ComponentInstanceInput} from "../../../models/properties-inputs/input-be-model"; +import {EventListenerService} from "app/services/event-listener-service" @Component({ templateUrl: './properties-assignment.page.component.html', styleUrls: ['./properties-assignment.page.component.less'] @@ -29,39 +34,60 @@ export class PropertiesAssignmentComponent { inputs: Array = []; instances: Array = []; searchQuery: string; - propertyStructureHeader: string + propertyStructureHeader: string; selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty(); selectedInstanceType: string; selectedInstanceData: ComponentInstance = new ComponentInstance(); checkedPropertiesCount: number = 0; - hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'childrens'); + hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens'); hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name'); displayClearSearch = false; searchPropertyName:string; - hideAdvanceSearch:boolean; + isInpusTabSelected:boolean; + isReadonly:boolean; + loadingInstances:boolean = false; + loadingInputs:boolean = false; + loadingProperties:boolean = false; @ViewChild('hierarchyNavTabs') hierarchyNavTabs: ElementRef; @ViewChild('propertyInputTabs') propertyInputTabs: ElementRef; @ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent; - constructor(private propertiesService:PropertiesService, + constructor(private propertiesService: PropertiesService, + private hierarchyNavService: HierarchyNavService, private propertiesUtils:PropertiesUtils, private componentServiceNg2:ComponentServiceNg2, private componentInstanceServiceNg2:ComponentInstanceServiceNg2, @Inject("$stateParams") _stateParams, - private renderer: Renderer) { + private renderer: Renderer, + private componentModeService:ComponentModeService, + private EventListenerService:EventListenerService) { this.instanceFePropertiesMap = new InstanceFePropertiesMap(); /* This is the way you can access the component data, please do not use any data except metadata, all other data should be received from the new api calls on the first time than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/ this.component = _stateParams.component; + this.EventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.onCheckout); + this.updateViewMode(); } ngOnInit() { console.log("==>" + this.constructor.name + ": ngOnInit"); + this.loadingInputs = true; + this.loadingInstances = true; + this.loadingProperties = true; + this.componentServiceNg2 + .getComponentInputs(this.component) + .subscribe(response => { + _.forEach(response.inputs, (input: InputBEModel) => { + this.inputs.push(new InputFEModel(input)); + }); + this.loadingInputs = false; + + }); this.componentServiceNg2 .getComponentResourceInstances(this.component) .subscribe(response => { @@ -70,95 +96,33 @@ export class PropertiesAssignmentComponent { _.forEach(this.instances, (instance) => { this.instancesNavigationData.push(instance); }); - + this.loadingInstances = false; + if (this.instancesNavigationData[0] == undefined) { + this.loadingProperties = false; + } this.selectFirstInstanceByDefault(); }); + }; - this.componentServiceNg2 - .getComponentInputs(this.component) - .subscribe(response => { - _.forEach(response.inputs, (input: PropertyBEModel) => { - this.inputs.push(new InputFEModel(input)); - }); - }) + ngOnDestroy() { + this.EventListenerService.unRegisterObserver(EVENTS.ON_CHECKOUT); } selectFirstInstanceByDefault = () => { if (this.instancesNavigationData[0] !== undefined) { this.onInstanceSelectedUpdate(this.instancesNavigationData[0]); } - } - - propertyValueChanged = (event) => { - console.log("==>" + this.constructor.name + ": propertyValueChanged " + event); - - if(this.selectedInstanceData.originType === ResourceType.VF) { - console.log("I want to update input value on the resource instance"); - let inputToUpdate = new PropertyBEModel(event); - this.componentInstanceServiceNg2 - .updateInstanceInput(this.component, this.selectedInstanceData.uniqueId, inputToUpdate) - .subscribe(response => { - console.log("update resource instance input and got this response: ",response); - }) - } - else { - // Copying the actual value from the object ref into the value if it's from a complex type - if(event.isDataType) { - event.value = JSON.stringify(event.valueObjectRef); - } - let propertyBe = new PropertyBEModel(event); - this.componentInstanceServiceNg2 - .updateInstanceProperty(this.component, this.selectedInstanceData.uniqueId, propertyBe) - .subscribe(response => { - console.log("updated resource instance property and got this response: ",response); - }); - console.log(event); - } - - }; - - inputValueChanged = (event) => { - console.log("==>" + this.constructor.name + ": inputValueChanged"); - let inputToUpdate = new PropertyBEModel(event); - - this.componentServiceNg2 - .updateComponentInput(this.component, inputToUpdate) - .subscribe(response => { - console.log("updated the component input and got this response: ", response); - }) }; - declareProperties = ():void => { - console.log("==>" + this.constructor.name + ": declareProperties"); - - let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap(); - - let instancesNames = new KeysPipe().transform(this.instanceFePropertiesMap,[]); - angular.forEach(instancesNames, (instanceName:string):void=>{ - selectedProperties[instanceName] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceName]); - //selectedProperties[this.selectedInstanceData.uniqueId] = this.propertiesService.getCheckedProperties(this.properties); - }); + updateViewMode = () => { + this.isReadonly = this.componentModeService.getComponentMode(this.component) === WorkspaceMode.VIEW; + } - let inputsToCreate: InstancePropertiesAPIMap; - if (this.selectedInstanceType !== ResourceType.VF) { - inputsToCreate = new InstancePropertiesAPIMap(null, selectedProperties); - } else { - inputsToCreate = new InstancePropertiesAPIMap(selectedProperties, null); - } - this.componentServiceNg2 - .createInput(this.component, inputsToCreate) - .subscribe(response => { - this.setInputTabIndication(response.length); - this.checkedPropertiesCount = 0; - _.forEach(response, (input: PropertyBEModel) => { this.inputs.push(new InputFEModel(input)); }); - this.findAndDisableDeclaredProperties(); - }); + onCheckout = (component:ComponentData) => { + this.component = component; + this.updateViewMode(); } - //TODO: Can remove? no one use it - // getSelectedFEProps = (): Array => { - // return this.properties.filter(prop => prop.isSelected && !prop.isDeclared); - // } onInstanceSelectedUpdate = (resourceInstance: ResourceInstance) => { console.log("==>" + this.constructor.name + ": onInstanceSelectedUpdate"); @@ -166,12 +130,15 @@ export class PropertiesAssignmentComponent { this.selectedInstanceData = resourceInstance; this.selectedInstanceType = resourceInstance.originType; + this.loadingProperties = true; if(resourceInstance.originType === ResourceType.VF) { this.componentInstanceServiceNg2 .getComponentInstanceInputs(this.component, resourceInstance) .subscribe(response => { instanceBePropertiesMap[resourceInstance.uniqueId] = response; this.processInstancePropertiesResponse(instanceBePropertiesMap); + this.loadingProperties = false; + }); } else { this.componentInstanceServiceNg2 @@ -179,23 +146,68 @@ export class PropertiesAssignmentComponent { .subscribe(response => { instanceBePropertiesMap[resourceInstance.uniqueId] = response; this.processInstancePropertiesResponse(instanceBePropertiesMap); + this.loadingProperties = false; }); } if( this.searchPropertyName ){ this.clearSearch(); } + //clear selected property from the navigation + this.selectedFlatProperty = new SimpleFlatProperty(); + this.propertiesNavigationData = []; }; /** * Entry point handling response from server */ processInstancePropertiesResponse = (instanceBePropertiesMap:InstanceBePropertiesMap) => { - this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap); //create flattened children - this.findAndDisableDeclaredProperties(); //disable properties or flattened children that are declared + this.instanceFePropertiesMap = this.propertiesUtils.convertPropertiesMapToFEAndCreateChildren(instanceBePropertiesMap, this.inputs); //create flattened children, disable declared props, and init values this.checkedPropertiesCount = 0; }; + + /*** VALUE CHANGE EVENTS ***/ + propertyValueChanged = (event: PropertyFEModel) => { + console.log("==>" + this.constructor.name + ": propertyValueChanged " + event); + // Copying the actual value from the object ref into the value if it's from a complex type + event.value = event.getJSONValue(); + + if (this.selectedInstanceData.originType === ResourceType.VF) { + console.log("I want to update input value on the resource instance"); + let inputToUpdate = new PropertyBEModel(event); + this.componentInstanceServiceNg2 + .updateInstanceInput(this.component, this.selectedInstanceData.uniqueId, inputToUpdate) + .subscribe(response => { + console.log("update resource instance input and got this response: ", response); + }) + } + else { + let propertyBe = new PropertyBEModel(event); + this.componentInstanceServiceNg2 + .updateInstanceProperty(this.component, this.selectedInstanceData.uniqueId, propertyBe) + .subscribe(response => { + console.log("updated resource instance property and got this response: ", response); + }); + console.log(event); + } + + }; + + inputValueChanged = (event) => { + console.log("==>" + this.constructor.name + ": inputValueChanged"); + let inputToUpdate = new PropertyBEModel(event); + + this.componentServiceNg2 + .updateComponentInput(this.component, inputToUpdate) + .subscribe(response => { + console.log("updated the component input and got this response: ", response); + }) + }; + + + /*** HEIRARCHY/NAV RELATED FUNCTIONS ***/ + /** * Handle select node in navigation area, and select the row in table */ @@ -219,13 +231,13 @@ export class PropertiesAssignmentComponent { if(this.selectedInstanceData.originType !== ResourceType.VF) { let simpleFlatProperty:Array; if (property instanceof PropertyFEModel) { - simpleFlatProperty = this.propertiesService.getSimplePropertiesTree(property, instanceName); + simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName); } else if (property instanceof DerivedFEProperty) { // Need to find parent PropertyFEModel let parentPropertyFEModel:PropertyFEModel = _.find(this.instanceFePropertiesMap[instanceName], (tmpFeProperty):boolean => { return property.propertiesName.indexOf(tmpFeProperty.name)===0; }); - simpleFlatProperty = this.propertiesService.getSimplePropertiesTree(parentPropertyFEModel, instanceName); + simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(parentPropertyFEModel, instanceName); } this.propertiesNavigationData = simpleFlatProperty; } @@ -236,20 +248,10 @@ export class PropertiesAssignmentComponent { } // Set selected property in table - this.selectedFlatProperty = new SimpleFlatProperty(property.uniqueId, null, property.name, null); + this.selectedFlatProperty = this.hierarchyNavService.createSimpleFlatProperty(property, instanceName); this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Property Structure']); }; - //TODO: Can remove? no one use it - // findParentProperty = (childProp: DerivedFEProperty): PropertyFEModel => { - // return this.properties.find(prop => prop.name == childProp.propertiesName.substring(0, childProp.propertiesName.indexOf("#"))); - // } - - //used for declare button, to keep count of newly checked properties (and ignore declared properties) - updateCheckedPropertyCount = (increment: boolean):void => { - this.checkedPropertiesCount += (increment) ? 1 : -1; - console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount); - } selectInstanceRow = ($event) => {//get instance name this.selectedInstanceData = _.find(this.instancesNavigationData, (instance:ComponentInstance) => { @@ -257,15 +259,90 @@ export class PropertiesAssignmentComponent { }); this.renderer.invokeElementMethod( this.hierarchyNavTabs, 'triggerTabChange', ['Composition']); - } + }; tabChanged = (event) => { console.log("==>" + this.constructor.name + ": tabChanged " + event); - this.hideAdvanceSearch = event.title !== "Properties"; + this.isInpusTabSelected = event.title === "Inputs"; + this.propertyStructureHeader = null; this.searchQuery = ''; }; - deleteInput = (input:InputFEModel) => { + + + /*** DECLARE PROPERTIES/INPUTS ***/ + declareProperties = (): void => { + console.log("==>" + this.constructor.name + ": declareProperties"); + + let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap(); + + let instancesNames = new KeysPipe().transform(this.instanceFePropertiesMap, []); + angular.forEach(instancesNames, (instanceName: string): void => { + selectedProperties[instanceName] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceName]); + //selectedProperties[this.selectedInstanceData.uniqueId] = this.propertiesService.getCheckedProperties(this.properties); + }); + + let inputsToCreate: InstancePropertiesAPIMap; + if (this.selectedInstanceType !== ResourceType.VF) { + inputsToCreate = new InstancePropertiesAPIMap(null, selectedProperties); + } else { + inputsToCreate = new InstancePropertiesAPIMap(selectedProperties, null); + } + this.componentServiceNg2 + .createInput(this.component, inputsToCreate) + .subscribe(response => { + this.setInputTabIndication(response.length); + this.checkedPropertiesCount = 0; + _.forEach(response, (input: InputBEModel) => { + this.inputs.push(new InputFEModel(input)); + this.updatePropertyValueAfterDeclare(input); + }); + }); + }; + + updatePropertyValueAfterDeclare = (input: InputBEModel) => { + _.forEach(input.properties, (property: ComponentInstanceProperty) => { + this.updatePropertyOrInputValueAfterDeclare(property, input); + }); + + _.forEach(input.inputs, (inputInstance: ComponentInstanceInput) => { + this.updatePropertyOrInputValueAfterDeclare(inputInstance, input); + }); + } + + updatePropertyOrInputValueAfterDeclare = (inputSource: ComponentInstanceProperty | ComponentInstanceInput, input: InputBEModel) => { + if (this.instanceFePropertiesMap[inputSource.componentInstanceId]) { + let propertyForUpdatindVal = _.find(this.instanceFePropertiesMap[inputSource.componentInstanceId], (feProperty: PropertyFEModel) => { + return feProperty.name == inputSource.name; + }); + + if (input.inputPath == propertyForUpdatindVal.name) input.inputPath = null; //Fix - if inputPath is sent for parent props, remove it + + propertyForUpdatindVal.setAsDeclared(input.inputPath); //set prop as declared before assigning value + this.propertiesService.disableRelatedProperties(propertyForUpdatindVal, input.inputPath); + this.propertiesUtils.resetPropertyValue(propertyForUpdatindVal, inputSource.value, input.inputPath); + // if (input.inputPath) { + // let childProp = _.find(propertyForUpdatindVal.flattenedChildren, (child: DerivedFEProperty) => { + // return child.propertiesName == input.inputPath; + // }); + // this.propertiesUtils.assignFlattenedChildrenValues(JSON.parse(inputSource.value), [childProp], inputSource.name); + // } else { + // propertyForUpdatindVal.valueObj = inputSource.value; + // } + } + } + + //used for declare button, to keep count of newly checked properties (and ignore declared properties) + updateCheckedPropertyCount = (increment: boolean): void => { + this.checkedPropertiesCount += (increment) ? 1 : -1; + console.log("CheckedProperties count is now.... " + this.checkedPropertiesCount); + }; + + setInputTabIndication = (numInputs: number): void => { + this.renderer.invokeElementMethod(this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]); + }; + + deleteInput = (input: InputFEModel) => { console.log("==>" + this.constructor.name + ": deleteInput"); let inputToDelete = new PropertyBEModel(input); @@ -273,51 +350,45 @@ export class PropertiesAssignmentComponent { .deleteInput(this.component, inputToDelete) .subscribe(response => { this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId); - let propToEnable: PropertyFEModel = this.instanceFePropertiesMap[input.instanceName].find(prop => prop.name == input.propertyName); - propToEnable.setNonDeclared(response.inputPath); - this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath); - //this.propertiesService.initValueObjectRef(propToEnable); //TODO:speak to BE about value returned by server - }); - } - setInputTabIndication = (numInputs: number): void => { - this.renderer.invokeElementMethod( this.propertyInputTabs, 'setTabIndication', ['Inputs', numInputs]); - } + //Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead! + this.onInstanceSelectedUpdate(this.selectedInstanceData); + // let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)]; + + // if (instanceFeProperties) { + // let propToEnable: PropertyFEModel = instanceFeProperties.find((prop) => { + // return prop.name == input.propertyName; + // }); + + // if (propToEnable) { + // if (propToEnable.name == response.inputPath) response.inputPath = null; + // propToEnable.setNonDeclared(response.inputPath); + // //this.propertiesUtils.resetPropertyValue(propToEnable, newValue, response.inputPath); + // this.propertiesService.undoDisableRelatedProperties(propToEnable, response.inputPath); + // } + // } + }); + }; - findAndDisableDeclaredProperties = () => { - this.inputs.filter(input => input.instanceName === this.selectedInstanceData.normalizedName).forEach(input => { - let prop: PropertyFEModel = this.instanceFePropertiesMap[this.selectedInstanceData.uniqueId].find(prop => prop.name === input.propertyName); - if (prop) { - prop.setAsDeclared(input.inputPath); //if a path was sent, its a child prop. this param is optional - this.propertiesService.disableRelatedProperties(prop, input.inputPath) - //this.propertiesService.initValueObjectRef(prop); - } + getInstanceUniqueId = (instanceName: string): string => { + let wantedInstance: ComponentInstance = this.instances.find((instance) => { + return instance.normalizedName === instanceName; }); + + return wantedInstance.uniqueId; }; + + + /*** SEARCH RELATED FUNCTIONS ***/ searchPropertiesInstances = (filterData:FilterPropertiesAssignmentData) => { - //let filteredProperties = this.componentServiceNg2.filterComponentInstanceProperties(this.component, filterData); let instanceBePropertiesMap:InstanceBePropertiesMap; this.componentServiceNg2 .filterComponentInstanceProperties(this.component, filterData) .subscribe(response => { - //instanceBePropertiesMap=response; - //console.log("================filter results============="); - //console.table(instanceBePropertiesMap); - this.processInstancePropertiesResponse(response); - - - //this.properties = []; - // _.forEach(instanceBePropertiesMap, (InstanceProperties:Array, instanceName:string) => { - // this.properties = this.properties.concat(this.propertiesService.convertPropertiesToFEAndCreateChildren(InstanceProperties, instanceName)); - // }); - - - // this.instancesNavigationData = _.filter(this.instancesNavigationData, (instance:ComponentInstance) => { - // return instanceBePropertiesMap[instance.name]; - // }); - // this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree + this.processInstancePropertiesResponse(response); + this.hierarchyPropertiesDisplayOptions.searchText = filterData.propertyName;//mark results in tree this.searchPropertyName = filterData.propertyName;//mark in table this.renderer.invokeElementMethod(this.hierarchyNavTabs, 'triggerTabChange', ['Composition']); this.propertiesNavigationData = []; @@ -332,13 +403,13 @@ export class PropertiesAssignmentComponent { this.hierarchyPropertiesDisplayOptions.searchText = ""; this.displayClearSearch = false; this.advanceSearch.clearAll(); - } + }; clickOnClearSearch = () => { this.clearSearch(); this.selectFirstInstanceByDefault(); this.renderer.invokeElementMethod( this.hierarchyNavTabs, 'triggerTabChange', ['Composition']); - } + }; } diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties.utils.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties.utils.ts index 79769e21b5..dfde2a40b2 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties.utils.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties.utils.ts @@ -1,78 +1,154 @@ import { Injectable } from '@angular/core'; import { DataTypeModel, PropertyFEModel, PropertyBEModel, InstanceBePropertiesMap, InstanceFePropertiesMap, SchemaProperty, DerivedFEProperty, DerivedFEPropertyMap, DerivedPropertyType, InputFEModel} from "app/models"; import { DataTypeService } from "app/ng2/services/data-type.service"; +import { PropertiesService } from "app/ng2/services/properties.service"; import { PROPERTY_TYPES } from "app/utils"; import { UUID } from "angular2-uuid"; @Injectable() export class PropertiesUtils { - constructor(private dataTypeService:DataTypeService) {} + constructor(private dataTypeService:DataTypeService, private propertiesService: PropertiesService) {} /** * Entry point when getting properties from server - * Returning InstanceFePropertiesMap + * For each instance, loop through each property, and: + * 1. Create flattened children + * 2. Check against inputs to see if any props are declared and disable them + * 3. Initialize valueObj (which also creates any new list/map flattened children as needed) + * Returns InstanceFePropertiesMap */ - public convertPropertiesMapToFEAndCreateChildren = (instancePropertiesMap:InstanceBePropertiesMap): InstanceFePropertiesMap => { + public convertPropertiesMapToFEAndCreateChildren = (instancePropertiesMap:InstanceBePropertiesMap, inputs:Array): InstanceFePropertiesMap => { let instanceFePropertiesMap:InstanceFePropertiesMap = new InstanceFePropertiesMap(); angular.forEach(instancePropertiesMap, (properties:Array, instanceName:string) => { - instanceFePropertiesMap[instanceName] = this.convertPropertiesToFEAndCreateChildren(properties); + let instanceInputs: Array = inputs.filter(input => input.instanceName == instanceName.split('.').pop()); + let propertyFeArray: Array = []; + _.forEach(properties, (property: PropertyBEModel) => { + + if (!this.dataTypeService.getDataTypeByTypeName(property.type)) { // if type not exist in data types remove property from list + console.log("ERROR: missing type " + property.type + " in dataTypes , of property ", property); + } else { + + let newFEProp: PropertyFEModel = new PropertyFEModel(property); //Convert property to FE + + if (newFEProp.derivedDataType == DerivedPropertyType.COMPLEX) { //Create children if prop is not simple, list, or map. + newFEProp.flattenedChildren = this.createFlattenedChildren(newFEProp.type, newFEProp.name); + } + if (instanceInputs.length) { //if this prop (or any children) are declared, set isDeclared and disable checkbox on parents/children + instanceInputs.filter(input => input.propertyName == newFEProp.name).forEach((input) => { + newFEProp.setAsDeclared(input.inputPath); //if a path was sent, its a child prop. this param is optional + this.propertiesService.disableRelatedProperties(newFEProp, input.inputPath); + }); + } + this.initValueObjectRef(newFEProp); //initialize valueObj. + propertyFeArray.push(newFEProp); + newFEProp.updateExpandedChildPropertyId(newFEProp.name); //display only the first level of children + } + }); + instanceFePropertiesMap[instanceName] = propertyFeArray; + }); return instanceFePropertiesMap; } + private createListOrMapChildrenFromValueObj = (property: PropertyFEModel) => { + if ((property.derivedDataType == DerivedPropertyType.LIST || property.derivedDataType == DerivedPropertyType.MAP) + && Object.keys(property.valueObj).length) { - /** - * Convert the properties Array to Array - */ - private convertPropertiesToFEAndCreateChildren = (properties: Array): Array => { - let propertyFeArray: Array = []; - _.forEach(properties, (property: PropertyBEModel, index: number) => { - //console.log("=======" + property.name + "========"); - if(!this.dataTypeService.getDataTypeByTypeName(property.type)){ // if type not exist in data types remove property from list - console.log("ERROR: missing type " + property.type + " in dataTypes , of property ",property); - return; - } - let propertyFe:PropertyFEModel = new PropertyFEModel(property); - if (propertyFe.isDataType) { //prop is not simple, list, or map. Need to create children. - let tempProps: Array = []; - let dataTypeObj: DataTypeModel = this.dataTypeService.getDataTypeByTypeName(propertyFe.type); - this.dataTypeService.getDerivedDataTypeProperties(dataTypeObj, tempProps, propertyFe.name); - propertyFe.flattenedChildren = tempProps; - propertyFe.expandedChildPropertyId = propertyFe.name; - this.initValueObjectRef(propertyFe); - } - propertyFeArray.push(propertyFe); - + Object.keys(property.valueObj).forEach((key) => { + let newProps: Array = this.createListOrMapChildren(property, key, property.valueObj[key]); + property.flattenedChildren.push(...newProps); + }); + + } + } - }); - return propertyFeArray; + public createListOrMapChildren = (property:PropertyBEModel, key: string, valueObj: any): Array => { + let newProps: Array = []; + let parentProp = new DerivedFEProperty(property, property.propertiesName, true, key, valueObj); + newProps.push(parentProp); - //TODO: need to look at schema to create the nested properties for the following cases: - // 1 - when value is populated for a complex type (list or map) - // 2 - when adding new entries to a complex type (eg. adding a new entry to a list of AddressRequirements) + if (!property.schema.property.isSimpleType) { + let additionalChildren:Array = this.createFlattenedChildren(property.schema.property.type, parentProp.propertiesName); + this.assignFlattenedChildrenValues(parentProp.valueObj, additionalChildren, parentProp.propertiesName); + additionalChildren.forEach(prop => prop.canBeDeclared = false); + newProps.push(...additionalChildren); + } + return newProps; } + /** + * Creates derivedFEProperties of a specified type and returns them. + */ + private createFlattenedChildren = (type: string, parentName: string):Array => { + let tempProps: Array = []; + let dataTypeObj: DataTypeModel = this.dataTypeService.getDataTypeByTypeName(type); + this.dataTypeService.getDerivedDataTypeProperties(dataTypeObj, tempProps, parentName); + return tempProps; + } + + /* Sets the valueObj of parent property and its children. + * Note: This logic is different than assignflattenedchildrenvalues - here we merge values, there we pick either the parents value, props value, or default value - without merging. + */ public initValueObjectRef = (property: PropertyFEModel): void => { - //console.log("Property " + property.name + " has value: " + property.value); - if (!property.isDataType || property.isDeclared) { //if property is declared, it gets a simple input instead. List and map values and pseudo-children will be handled in property component - property.value = property.value || property.defaultValue; - } else if (property.value){ //we have a complex property with a value. Lets parse property.value and populate our flattened children with those values - this.assignValuesRecursively(JSON.parse(property.value), property.flattenedChildren, property.name); + if (property.derivedDataType == DerivedPropertyType.SIMPLE || property.isDeclared) { //if property is declared, it gets a simple input instead. List and map values and pseudo-children will be handled in property component + property.valueObj = property.value || property.defaultValue; + + if (property.isDeclared && typeof property.valueObj == 'object') property.valueObj = JSON.stringify(property.valueObj); + } else { + if (property.derivedDataType == DerivedPropertyType.LIST) { + property.valueObj = _.merge([], JSON.parse(property.defaultValue || '[]'), JSON.parse(property.value || '[]')); //value object should be merged value and default value. Value takes higher precendence. Set valueObj to empty obj if undefined. + } else { + property.valueObj = _.merge({}, JSON.parse(property.defaultValue || '{}'), JSON.parse(property.value || '{}')); //value object should be merged value and default value. Value takes higher precendence. Set valueObj to empty obj if undefined. + } + if (property.derivedDataType == DerivedPropertyType.COMPLEX) { + this.assignFlattenedChildrenValues(property.valueObj, property.flattenedChildren, property.name); + } else { + this.createListOrMapChildrenFromValueObj(property); + } } } - public assignValuesRecursively = (valueJSON: any, derivedPropArray: Array, propName: string) => { - if (valueJSON && Object.keys(valueJSON)) { - Object.keys(valueJSON).forEach(valueKey => { - let childProp: DerivedFEProperty = derivedPropArray.find(prop => prop.propertiesName == propName + "#" + valueKey); - if (!childProp) return; - if (childProp.isDeclared || (childProp.derivedDataType != DerivedPropertyType.COMPLEX && !_.isEmpty(valueJSON[valueKey]))) { - childProp.value = (typeof valueJSON[valueKey] === 'object')? JSON.stringify(valueJSON[valueKey]) : valueJSON[valueKey]; - } else { - this.assignValuesRecursively(valueJSON[valueKey], derivedPropArray, childProp.propertiesName) + /* + * Loops through flattened properties array and to assign values + * Then, convert any neccessary strings to objects, and vis-versa + * For list or map property, creates new children props if valueObj has values + */ + public assignFlattenedChildrenValues = (parentValueJSON: any, derivedPropArray: Array, parentName: string) => { + if (!derivedPropArray || !parentName) return; + derivedPropArray.forEach((prop, index) => { + + let propNameInObj = prop.propertiesName.substring(prop.propertiesName.indexOf(parentName) + parentName.length + 1).split('#').join('.'); //extract everything after parent name + prop.valueObj = _.get(parentValueJSON, propNameInObj, prop.value || prop.defaultValue); //assign value -first value of parent if exists. If not, prop.value if not, prop.defaultvalue + + if ((prop.derivedDataType == DerivedPropertyType.SIMPLE || prop.isDeclared) && typeof prop.valueObj == 'object') { //Stringify objects that should be strings + prop.valueObj = JSON.stringify(prop.valueObj); + } else { //parse strings that should be objects + if ((prop.derivedDataType == DerivedPropertyType.COMPLEX || prop.derivedDataType == DerivedPropertyType.MAP) && typeof prop.valueObj != 'object') { + prop.valueObj = JSON.parse(prop.valueObj || '{}'); + } else if (prop.derivedDataType == DerivedPropertyType.LIST && typeof prop.valueObj != 'object') { + prop.valueObj = JSON.parse(prop.valueObj || '[]'); } - }); + if ((prop.derivedDataType == DerivedPropertyType.LIST || prop.derivedDataType == DerivedPropertyType.MAP) && Object.keys(prop.valueObj).length) { + let newProps: Array = []; + Object.keys(prop.valueObj).forEach((key) => { + newProps.push(...this.createListOrMapChildren(prop, key, prop.valueObj[key]));//create new children, assign their values, and then add to array + }); + derivedPropArray.splice(index + 1, 0, ...newProps); + } + } + }); + } + + public resetPropertyValue = (property: PropertyFEModel, newValue: string, inputPath?: string): void => { + property.value = newValue; + if (inputPath) { + let newProp = property.flattenedChildren.find(prop => prop.propertiesName == inputPath); + newProp && this.assignFlattenedChildrenValues(JSON.parse(newValue), [newProp], property.name); + } else { + this.initValueObjectRef(property); } } + + } diff --git a/catalog-ui/src/app/ng2/pipes/searchFilter.pipe.ts b/catalog-ui/src/app/ng2/pipes/searchFilter.pipe.ts index 7e017e8590..3a0c85dda2 100644 --- a/catalog-ui/src/app/ng2/pipes/searchFilter.pipe.ts +++ b/catalog-ui/src/app/ng2/pipes/searchFilter.pipe.ts @@ -8,11 +8,10 @@ export class SearchFilterPipe implements PipeTransform { if (!term || !term.length) return value; return value.filter((item) => { if (item.hasOwnProperty(key)) { - let regExp = new RegExp(term, 'gi'); - return regExp.test(item[key]); + return item[key].indexOf(term) > -1; } else { return false; } }); } -} \ No newline at end of file +} diff --git a/catalog-ui/src/app/ng2/services/component-mode.service.ts b/catalog-ui/src/app/ng2/services/component-mode.service.ts new file mode 100644 index 0000000000..12a581e5f9 --- /dev/null +++ b/catalog-ui/src/app/ng2/services/component-mode.service.ts @@ -0,0 +1,29 @@ +/** + * Created by rc2122 on 5/23/2017. + */ +import { Injectable } from '@angular/core'; +import {WorkspaceMode, ComponentState, Role} from "../../utils/constants"; +import { Component as ComponentData } from "app/models"; +import { CacheService } from "app/services/cache-service" + +@Injectable() + +export class ComponentModeService { + + constructor(private cacheService:CacheService) { + } + + public getComponentMode = (component:ComponentData):WorkspaceMode => {//return if is edit or view for resource or service + let mode = WorkspaceMode.VIEW; + + let user = this.cacheService.get("user"); + if (component.lifecycleState === ComponentState.NOT_CERTIFIED_CHECKOUT && + component.lastUpdaterUserId === user.userId) { + if ((component.isService() || component.isResource()) && user.role == Role.DESIGNER) { + mode = WorkspaceMode.EDIT; + } + } + return mode; + } +} + diff --git a/catalog-ui/src/app/ng2/services/component-services/service.service.ts b/catalog-ui/src/app/ng2/services/component-services/service.service.ts index b47b64c5c2..d2f7078599 100644 --- a/catalog-ui/src/app/ng2/services/component-services/service.service.ts +++ b/catalog-ui/src/app/ng2/services/component-services/service.service.ts @@ -20,7 +20,7 @@ export class ServiceServiceNg2 { validateConformanceLevel(service: Service): Observable { - return this.http.get(this.baseUrl + service.getTypeUrl() + service.uniqueId + '/conformanceLevelValidation') + return this.http.get(this.baseUrl + service.getTypeUrl() + service.uuid + '/conformanceLevelValidation') .map((res: Response) => { return res.json(); }); diff --git a/catalog-ui/src/app/ng2/services/data-type.service.ts b/catalog-ui/src/app/ng2/services/data-type.service.ts index e7ea1a8430..be2388144f 100644 --- a/catalog-ui/src/app/ng2/services/data-type.service.ts +++ b/catalog-ui/src/app/ng2/services/data-type.service.ts @@ -49,12 +49,14 @@ export class DataTypeService { return propertiesArray; } */ - + public getDerivedDataTypeProperties(dataTypeObj: DataTypeModel, propertiesArray: Array, parentName: string) { //push all child properties to array if (dataTypeObj.properties) { dataTypeObj.properties.forEach((derivedProperty) => { - propertiesArray.push(new DerivedFEProperty(derivedProperty, parentName)); + if(dataTypeObj.name !== PROPERTY_DATA.OPENECOMP_ROOT || derivedProperty.name !== PROPERTY_DATA.SUPPLEMENTAL_DATA){//The requirement is to not display the property supplemental_data + propertiesArray.push(new DerivedFEProperty(derivedProperty, parentName)); + } let derivedDataTypeObj: DataTypeModel = this.getDataTypeByTypeName(derivedProperty.type); this.getDerivedDataTypeProperties(derivedDataTypeObj, propertiesArray, parentName + "#" + derivedProperty.name); }); @@ -62,8 +64,8 @@ export class DataTypeService { //recurse parent (derivedFrom), in case one of parents contains properties if (PROPERTY_DATA.ROOT_DATA_TYPE !== dataTypeObj.derivedFrom.name) { this.getDerivedDataTypeProperties(dataTypeObj.derivedFrom, propertiesArray, parentName); - } - } - + } + } + } diff --git a/catalog-ui/src/app/ng2/services/hierarchy-nav.service.ts b/catalog-ui/src/app/ng2/services/hierarchy-nav.service.ts new file mode 100644 index 0000000000..512505d7c6 --- /dev/null +++ b/catalog-ui/src/app/ng2/services/hierarchy-nav.service.ts @@ -0,0 +1,63 @@ +import { Injectable } from '@angular/core'; +import { SimpleFlatProperty, PropertyFEModel, DerivedFEProperty } from 'app/models'; + + +@Injectable() +export class HierarchyNavService { + /** + * Build hirarchy structure for the tree when user selects on table row. + * First create Array and insert also the parent (PropertyFEModel) to this array. + * The Array is flat and contains SimpleFlatProperty that has parentName and uniqueId. + * Now we build hirarchy from this Array (that includes childrens) and return it for the tree + * + * @argument property: PropertyFEModel - property contains flattenedChildren array of DerivedFEProperty + * @returns Array - containing childrens Array, augmantin childrens to SimpleFlatProperty. + */ + public getSimplePropertiesTree(property: PropertyFEModel, instanceName: string): Array { + // Build Array of SimpleFlatProperty before unflatten function + let flattenProperties: Array = []; + flattenProperties.push(this.createSimpleFlatProperty(property, instanceName)); // Push the root property + _.each(property.flattenedChildren, (child: DerivedFEProperty): void => { + if (child.isChildOfListOrMap && child.schema.property.isSimpleType) return; //do not display non-complex children of list or map + flattenProperties.push(this.createSimpleFlatProperty(child, instanceName)); + }); + + let tree = this.unflatten(flattenProperties, '', []); + return tree[0].childrens; // Return the childrens without the root. + } + + public createSimpleFlatProperty = (property: PropertyFEModel | DerivedFEProperty, instanceName:string): SimpleFlatProperty => { + if (property instanceof PropertyFEModel) { + return new SimpleFlatProperty(property.uniqueId, property.name, property.name, '', instanceName); + } else { + let propName: string = (property.isChildOfListOrMap) ? property.mapKey : property.name; + return new SimpleFlatProperty(property.uniqueId, property.propertiesName, propName, property.parentName, instanceName); + } + + } + + /** + * Unflatten Array and build hirarchy. + * The result will be Array that augmantin with childrens for each SimpleFlatProperty. + */ + private unflatten(array: Array, parent: any, tree?: any): any { + tree = typeof tree !== 'undefined' ? tree : []; + parent = typeof parent !== 'undefined' && parent !== '' ? parent : { path: '' }; + + var childrens = _.filter(array, (child: SimpleFlatProperty): boolean => { + return child.parentName == parent.path; + }); + + if (!_.isEmpty(childrens)) { + if (parent.path == '') { + tree = childrens; + } else { + parent['childrens'] = childrens; + } + _.each(childrens, (child): void => { + this.unflatten(array, child); + }); + } + return tree; + } +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/services/properties.service.ts b/catalog-ui/src/app/ng2/services/properties.service.ts index 638e537cd1..a22e2aed20 100644 --- a/catalog-ui/src/app/ng2/services/properties.service.ts +++ b/catalog-ui/src/app/ng2/services/properties.service.ts @@ -8,11 +8,11 @@ import { UUID } from "angular2-uuid"; @Injectable() export class PropertiesService { - constructor(private dataTypeService:DataTypeService, private contentAfterLastDotPipe:ContentAfterLastDotPipe) { + constructor(private dataTypeService: DataTypeService, private contentAfterLastDotPipe: ContentAfterLastDotPipe) { } - public getParentPropertyFEModelFromPath = (properties:Array, path:string) => { - let parent:PropertyFEModel = _.find(properties, (property:PropertyFEModel):boolean=>{ + public getParentPropertyFEModelFromPath = (properties: Array, path: string) => { + let parent: PropertyFEModel = _.find(properties, (property: PropertyFEModel): boolean => { return property.name === path.substring(0, path.indexOf('#')); }); return parent; @@ -33,7 +33,7 @@ export class PropertiesService { } //disable parents and children of prop - public disableRelatedProperties = (property:PropertyFEModel, childPath?: string): void => { + public disableRelatedProperties = (property: PropertyFEModel, childPath?: string): void => { if (!childPath) { //selecting the parent property property.isSelected = true; property.flattenedChildren && property.flattenedChildren.map(child => { child.isSelected = false; child.isDisabled = true; }); @@ -41,18 +41,18 @@ export class PropertiesService { property.isSelected = false; property.isDisabled = true; property.flattenedChildren.filter((childProp: DerivedFEProperty) => { - return (childProp.propertiesName.indexOf(childPath + "#") > -1 //is child of prop to disable - || childPath.indexOf(childProp.propertiesName + "#") > -1); //is parent of prop to disable + return (childProp.propertiesName.indexOf(childPath + "#") === 0 //is child of prop to disable + || childPath.indexOf(childProp.propertiesName + "#") === 0); //is parent of prop to disable }).map((child: DerivedFEProperty) => { child.isSelected = false; child.isDisabled = true; }); } } - public getCheckedProperties = (properties:Array): Array => { + public getCheckedProperties = (properties: Array): Array => { let selectedProps: Array = []; properties.forEach(prop => { if (prop.isSelected && !prop.isDeclared && !prop.isDisabled) { selectedProps.push(new PropertyBEModel(prop)); - } else if(prop.flattenedChildren) { + } else if (prop.flattenedChildren) { prop.flattenedChildren.forEach((child) => { if (child.isSelected && !child.isDeclared && !child.isDisabled) { let childProp = new PropertyBEModel(prop, child); //create it from the parent @@ -64,186 +64,5 @@ export class PropertiesService { return selectedProps; } - /** - * Build hirarchy structure for the tree when user selects on table row. - * First create Array and insert also the parent (PropertyFEModel) to this array. - * The Array is flat and contains SimpleFlatProperty that has parentName and uniqueId. - * Now we build hirarchy from this Array (that includes childrens) and return it for the tree - * - * @argument property: PropertyFEModel - property contains flattenedChildren array of DerivedFEProperty - * @returns Array - containing childrens Array, augmantin childrens to SimpleFlatProperty. - */ - public getSimplePropertiesTree(property: PropertyFEModel, instanceName:string):Array { - // Build Array of SimpleFlatProperty before unflatten function - let flattenProperties:Array = []; - flattenProperties.push(new SimpleFlatProperty(property.uniqueId, property.name, property.name, '', instanceName)); // Push the root property - _.each(property.flattenedChildren, (child:DerivedFEProperty):void => { - flattenProperties.push(new SimpleFlatProperty(child.uniqueId, child.propertiesName, child.name, child.parentName, instanceName)); - }); - - let tree = this.unflatten(flattenProperties, '', []); - return tree[0].childrens; // Return the childrens without the root. - } - - /** - * Unflatten Array and build hirarchy. - * The result will be Array that augmantin with childrens for each SimpleFlatProperty. - */ - private unflatten( array:Array, parent:any, tree?:any ):any { - tree = typeof tree!=='undefined' ? tree : []; - parent = typeof parent!=='undefined' && parent!=='' ? parent : { path: '' }; - - var childrens = _.filter( array, (child:SimpleFlatProperty):boolean => { - return child.parentName == parent.path; - }); - - if( !_.isEmpty( childrens ) ){ - if( parent.path == '' ){ - tree = childrens; - } else { - parent['childrens'] = childrens; - } - _.each( childrens, ( child ):void => { - this.unflatten( array, child ); - }); - } - return tree; - } - - // TODO: To remove - // public convertPropertiesToFEAndInitialize(properties: Array): Array { - // let props:Array = []; - // _.forEach(properties, (property: PropertyFEModel, index: number) => { - // props[index] = new PropertyFEModel(property); - // this.initValueObjectRef(props[index]); - // if (props[index].isDataType || - // ((props[index].type === PROPERTY_TYPES.MAP || props[index].type === PROPERTY_TYPES.LIST) && props[index].schema.property.isDataType)) { - // props[index].valueObjectRef = props[index].valueObjectRef || {}; - // let defaultValueObject:any = props[index].defaultValue ? JSON.parse(props[index].defaultValue): null; - // this.createPropertiesTreeForProp(props[index], true, defaultValueObject); - // } - // }); - // return props; - // } - - /** - * Converts a property's map values to properties and adds them to property.childrenProperties - * @param property - property to add children to - * @param onlyFirstLevel - recursively retrieve properties for each dataType? - */ - //TODO: To remove - // public createPropertyNodesForMapOfDataTypes(property: PropertyFEModel, onlyFirstLevel:boolean):void { - // property.childrenProperties = []; - // angular.forEach(property.valueObjectRef,function(itemInMap:any, keyInMap:string){ - // let newProperty: PropertyFEModel = new PropertyFEModel(keyInMap, - // property.schema.property.type, - // UUID.UUID(), - // property, - // property.valueObjectRef[keyInMap]); - // !onlyFirstLevel && this.createPropertiesTreeForProp(newProperty); - // property.childrenProperties.push(newProperty); - // },this); - // } - - - /** - * Converts a property's list values to properties and adds them to property.childrenProperties - * @param property - property to add children to - * @param onlyFirstLevel - recursively retrieve properties for each dataType? - */ - //TODO: To remove - // public createPropertyNodesForListOfDataTypes(property: PropertyFEModel, onlyFirstLevel:boolean):void { - // property.childrenProperties = []; - // property.valueObjectRef.forEach((itemInList:any, index:number):void =>{ - // let newProperty: PropertyFEModel = new PropertyFEModel(this.contentAfterLastDotPipe.transform(property.schema.property.type), - // property.schema.property.type, - // UUID.UUID(), - // property, - // property.valueObjectRef[index]); - // !onlyFirstLevel && this.createPropertiesTreeForProp(newProperty); - // property.childrenProperties.push(newProperty); - // }); - // } - - // private checkIfPropertyDerivedFromSimpleAndUpdateProp(property:PropertyFEModel | SchemaProperty): boolean{ - // property.derivedFromSimpleTypeName = this.dataTypeService.getTypeForDataTypeDerivedFromSimple(property.type); - // if(property.derivedFromSimpleTypeName){ - // property.isSimpleType = true; - // property.isDataType = false; - // } - // return property.isSimpleType; - // } - - // TODO: Remove - public createPropertiesTreeForProp(property: PropertyFEModel, onlyFirstLevel?: boolean, defaultValueObj?: any): void { - } - - public getPropertyFEModelFromDerivedPropertyUniqueId(properties: Array, uniqueId: string): PropertyFEModel { - // _.each(properties, (property):void => { - // property.flattenedChildren - - // }); - - // let rootProperty = _.find(properties, (property):boolean => { return property.uniqueId === uniqueId; }); - // if - return null; - } - - /** - * Utilizes the dataTypeService to retrieve children properties from dataTypes recursively. - * @param property - * @param onlyFirstLevel - */ - // TODO: To remove - // public createPropertiesTreeForProp(property: PropertyFEModel, onlyFirstLevel?:boolean, defaultValueObj?:any ):void{ - // if (property.isDataType && !this.checkIfPropertyDerivedFromSimpleAndUpdateProp(property)){ - // let dataType: DataTypeModel = this.dataTypeService.getDataTypeByTypeName(property.type); - // property.childrenProperties = []; - // let childrenProperties = this.dataTypeService.getDataTypePropertiesRecursively(dataType); - // childrenProperties.forEach((childProperty: PropertyBEModel):void => { - // let childDataTypePropertyObj: PropertyFEModel = new PropertyFEModel(childProperty.name, childProperty.type,UUID.UUID(),property, {}, childProperty.schema); - // //init empty object in valueObjectRef[childProperty.name] because this property's children should has ref to this obj. - // if(!property.valueObjectRef[childDataTypePropertyObj.name]){ - // if ((childDataTypePropertyObj.isDataType && !this.checkIfPropertyDerivedFromSimpleAndUpdateProp(childDataTypePropertyObj)) - // || childDataTypePropertyObj.type === PROPERTY_TYPES.MAP){ - // property.valueObjectRef[childDataTypePropertyObj.name] = {}; - // }else if(childDataTypePropertyObj.type === PROPERTY_TYPES.LIST){ - // property.valueObjectRef[childDataTypePropertyObj.name] = []; - // } - // } - // childDataTypePropertyObj.valueObjectRef = property.valueObjectRef[childDataTypePropertyObj.name]; - // property.valueObjectRef[childDataTypePropertyObj.name] = property.valueObjectRef[childProperty.name] || childDataTypePropertyObj.defaultValue; - // if( !childDataTypePropertyObj.isDataType && defaultValueObj ){//init property default value - // childDataTypePropertyObj.defaultValue = JSON.stringify(defaultValueObj[childDataTypePropertyObj.name]); - // } - // property.childrenProperties.push(childDataTypePropertyObj); - // !onlyFirstLevel && this.createPropertiesTreeForProp(childDataTypePropertyObj, false, (defaultValueObj ? defaultValueObj[childDataTypePropertyObj.name] : null)); - // }); - // } else if (property.type == PROPERTY_TYPES.MAP && property.schema.property.isDataType && !this.checkIfPropertyDerivedFromSimpleAndUpdateProp(property.schema.property)){ - // if( property.valueObjectRef && !_.isEmpty(property.valueObjectRef)){ - // this.createPropertyNodesForMapOfDataTypes(property, onlyFirstLevel); - // } - // } else if (property.type == PROPERTY_TYPES.LIST && property.schema.property.isDataType && !this.checkIfPropertyDerivedFromSimpleAndUpdateProp(property.schema.property)){ - // if( property.valueObjectRef && property.valueObjectRef.length){ - // this.createPropertyNodesForListOfDataTypes(property, onlyFirstLevel); - // } - // } - // } -} - -export class SimpleFlatProperty { - uniqueId:string; - path:string; - name:string; - parentName:string; - instanceName:string; - - constructor(uniqueId?:string, path?:string, name?: string, parentName?:string, instanceName?:string) { - this.uniqueId = uniqueId; - this.path = path; - this.name = name; - this.parentName = parentName; - this.instanceName = instanceName; - } -} +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/shared/tabs/tabs.component.less b/catalog-ui/src/app/ng2/shared/tabs/tabs.component.less index aa59428a64..fa05249ea4 100644 --- a/catalog-ui/src/app/ng2/shared/tabs/tabs.component.less +++ b/catalog-ui/src/app/ng2/shared/tabs/tabs.component.less @@ -15,7 +15,6 @@ .tab-content-container { flex: 1; height: 100%; - overflow: hidden; width:100%; } @@ -59,7 +58,7 @@ width: 25px; height: 25px; text-align: center; - + } } diff --git a/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts b/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts index c8c1d9b721..ed1ecd87bd 100644 --- a/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts +++ b/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts @@ -5,6 +5,8 @@ import {DataTypesService} from "../../services/data-types-service"; import ICacheObject = angular.ICacheObject; import {SharingService} from "../../services/sharing-service"; import {CookieService} from "../../services/cookie-service"; +import {CacheService} from "../../services/cache-service"; +import {EventListenerService} from "app/services/event-listener-service"; /** Services we need to upgrade from angular1 to angular2 - in the future we need to rewrite them all to angular2 **/ @@ -24,6 +26,14 @@ export function stateParamsServiceFactory(cacheObj: ICacheObject) { return cacheObj.get('$stateParams'); } +export function cacheServiceFactory(cacheObj: ICacheObject) { + return cacheObj.get('Sdc.Services.CacheService'); +} + +export function eventListenerServiceServiceFactory(cacheObj: ICacheObject) { + return cacheObj.get('EventListenerService'); +} + export const DataTypesServiceProvider = { provide: DataTypesService, useFactory: dataTypesServiceFactory, @@ -49,3 +59,15 @@ export const StateParamsServiceFactory = { useFactory: stateParamsServiceFactory, deps: ['$injector'] }; + +export const CacheServiceProvider = { + provide: CacheService, + useFactory: cacheServiceFactory, + deps: ['$injector'] +}; + +export const EventListenerServiceProvider = { + provide: EventListenerService, + useFactory: eventListenerServiceServiceFactory, + deps: ['$injector'] +}; diff --git a/catalog-ui/src/app/services/components/component-service.ts b/catalog-ui/src/app/services/components/component-service.ts index 1a6b9a8a14..7e031baa08 100644 --- a/catalog-ui/src/app/services/components/component-service.ts +++ b/catalog-ui/src/app/services/components/component-service.ts @@ -22,12 +22,13 @@ import {ArtifactModel, IFileDownload, InstancesInputsPropertiesMap, InputModel, AttributeModel, IAppConfigurtaion, Resource, Module, DisplayModule, ArtifactGroupModel, InputsAndProperties} from "app/models"; import {ComponentInstanceFactory, CommonUtils} from "app/utils"; import {SharingService} from "../sharing-service"; +import {ComponentMetadata} from "../../models/component-metadata"; export interface IComponentService { getComponent(id:string); updateComponent(component:Component):ng.IPromise; - changeLifecycleState(component:Component, state:string, userRemarks:any):ng.IPromise ; + changeLifecycleState(component:Component, state:string, userRemarks:any):ng.IPromise ; validateName(newName:string, subtype?:string):ng.IPromise; createComponent(component:Component):ng.IPromise; addOrUpdateArtifact(componentId:string, artifact:ArtifactModel):ng.IPromise; @@ -213,11 +214,11 @@ export class ComponentService implements IComponentService { return deferred.promise; }; - public changeLifecycleState = (component:Component, state:string, userRemarks:any):ng.IPromise => { + public changeLifecycleState = (component:Component, state:string, userRemarks:any):ng.IPromise => { let deferred = this.$q.defer(); - this.restangular.one(component.uniqueId).one(state).customPOST(userRemarks).then((response:Component) => { + this.restangular.one(component.uniqueId).one(state).customPOST(userRemarks).then((response:ComponentMetadata) => { this.sharingService.addUuidValue(response.uniqueId, response.uuid); - let component:Component = this.createComponentObject(response); + let component:ComponentMetadata = new ComponentMetadata().deserialize(response); deferred.resolve(component); }, (err)=> { deferred.reject(err); diff --git a/catalog-ui/src/app/utils/component-factory.ts b/catalog-ui/src/app/utils/component-factory.ts index 18edbfb02c..13f1d761f2 100644 --- a/catalog-ui/src/app/utils/component-factory.ts +++ b/catalog-ui/src/app/utils/component-factory.ts @@ -106,6 +106,7 @@ export class ComponentFactory { newResource.csarVersion = csar.version; newResource.packageId = csar.packageId; newResource.description = csar.description; + newResource.filterTerm = newResource.name + ' ' + newResource.description + ' ' + newResource.vendorName + ' ' + newResource.csarVersion return newResource; }; diff --git a/catalog-ui/src/app/utils/constants.ts b/catalog-ui/src/app/utils/constants.ts index d55079d662..7426c7c92b 100644 --- a/catalog-ui/src/app/utils/constants.ts +++ b/catalog-ui/src/app/utils/constants.ts @@ -91,11 +91,13 @@ export class PROPERTY_DATA { public static TYPES = [PROPERTY_TYPES.STRING, PROPERTY_TYPES.INTEGER, PROPERTY_TYPES.FLOAT, PROPERTY_TYPES.BOOLEAN, PROPERTY_TYPES.JSON, PROPERTY_TYPES.LIST, PROPERTY_TYPES.MAP]; public static SIMPLE_TYPES = [PROPERTY_TYPES.STRING, PROPERTY_TYPES.INTEGER, PROPERTY_TYPES.FLOAT, PROPERTY_TYPES.BOOLEAN, PROPERTY_TYPES.JSON]; public static ROOT_DATA_TYPE = "tosca.datatypes.Root"; + public static OPENECOMP_ROOT = "org.openecomp.datatypes.Root"; + public static SUPPLEMENTAL_DATA = "supplemental_data"; public static SOURCES = [SOURCES.A_AND_AI, SOURCES.ORDER, SOURCES.RUNTIME]; } export class PROPERTY_VALUE_CONSTRAINTS { - public static MAX_LENGTH = 100; + public static MAX_LENGTH = 2500; public static JSON_MAX_LENGTH = 4096; } @@ -216,6 +218,7 @@ export class EVENTS { static ON_WORKSPACE_SAVE_BUTTON_CLICK = "onWorkspaceSaveButtonClick"; static ON_WORKSPACE_SAVE_BUTTON_SUCCESS = "onWorkspaceSaveButtonSuccess"; static ON_WORKSPACE_SAVE_BUTTON_ERROR = "onWorkspaceSaveButtonError"; + static ON_CHECKOUT = "onCheckout"; //Loader events static SHOW_LOADER_EVENT = "showLoaderEvent"; diff --git a/catalog-ui/src/app/utils/modals-handler.ts b/catalog-ui/src/app/utils/modals-handler.ts index fe864cb658..c6d1d36fc7 100644 --- a/catalog-ui/src/app/utils/modals-handler.ts +++ b/catalog-ui/src/app/utils/modals-handler.ts @@ -372,7 +372,7 @@ export class ModalsHandler implements IModalsHandler { public openConformanceLevelModal = ():ng.IPromise => { let deferred = this.$q.defer(); let modalOptions:ng.ui.bootstrap.IModalSettings = { - templateUrl: '../view-models/workspace/conformance-level-modal/conformance-level-modal-view.html', + templateUrl: '../view-models/modals/conformance-level-modal/conformance-level-modal-view.html', controller: 'Sdc.ViewModels.ConformanceLevelModalViewModel', size: 'sdc-sm', backdrop: 'static', diff --git a/catalog-ui/src/app/view-models/forms/attribute-form/attribute-form-view.html b/catalog-ui/src/app/view-models/forms/attribute-form/attribute-form-view.html index 90b8f67df4..daa7a90bf8 100644 --- a/catalog-ui/src/app/view-models/forms/attribute-form/attribute-form-view.html +++ b/catalog-ui/src/app/view-models/forms/attribute-form/attribute-form-view.html @@ -103,9 +103,9 @@ + ng-model-options="{ debounce: 300 }" />
@@ -38,16 +38,16 @@
-
- + {{component.name}}
@@ -71,7 +71,7 @@
-
+
VSP Description:
diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts index e2d95280c8..670655ea4b 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/composition-view-model.ts @@ -215,6 +215,10 @@ export class CompositionViewModel { if (this.$state.current.name === 'workspace.composition.api') { this.$state.go('workspace.composition.details'); } + + if(this.$scope.selectedComponent.isService() && this.$state.current.name === 'workspace.composition.relations'){ + this.$state.go('workspace.composition.api'); + } }; this.$scope.openUpdateModal = ():void => { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts index 0ac5fd0799..5d03563042 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view-model.ts @@ -179,7 +179,7 @@ export class ResourceArtifactsViewModel { this.$scope.currentComponent.selectedInstance.artifacts = artifacts; break; } - this.loadComponentArtifactIfNeeded(); + this.initArtifactArr(this.$scope.artifactType); }; let onError = ()=> { diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html index b0d81b3437..bd4864771e 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/artifacts/artifacts-view.html @@ -49,7 +49,7 @@ data-tests-id="edit-parameters-of-{{artifact.artifactDisplayName}}"> + artifact="artifact" component="currentComponent" data-tests-id="download_{{artifact.artifactDisplayName}}" instance="isComponentInstanceSelected()"> { //latest checked in + let latestVersionComponent:LeftPaletteComponent = _.maxBy(_.filter(this.LeftPaletteLoaderService.getLeftPanelComponentsForDisplay(this.$scope.currentComponent.componentType), (component:LeftPaletteComponent) => { //latest checked in return (component.systemName === this.$scope.selectedComponent.systemName || component.uuid === this.$scope.selectedComponent.uuid); - }); + }),(component)=>{return component.version}); + let latestVersion:string = latestVersionComponent ? latestVersionComponent.version : highestVersion; if (highestVersion != latestVersion) { //highest is checked out - remove from options diff --git a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties-view-model.ts index 84769d7a62..90cb556c75 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/composition/tabs/properties-and-attributes/properties-view-model.ts @@ -118,7 +118,9 @@ export class ResourcePropertiesViewModel { (this.$scope.isPropertyOwner() ? this.$scope.properties[property.parentUniqueId] : this.$scope.properties[property.resourceInstanceUniqueId]) || [], - this.isPropertyValueOwner()).then(() => { + this.isPropertyValueOwner()).then((updatedProperty:PropertyModel) => { + let oldProp = _.find(this.$scope.properties[updatedProperty.resourceInstanceUniqueId], (prop:PropertyModel) => {return prop.uniqueId == updatedProperty.uniqueId;}); + oldProp.value = updatedProperty.value; }); }; diff --git a/catalog-ui/src/app/view-models/workspace/tabs/deployment-artifacts/deployment-artifacts-view.html b/catalog-ui/src/app/view-models/workspace/tabs/deployment-artifacts/deployment-artifacts-view.html index cc914b07a8..a36eb1b74d 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/deployment-artifacts/deployment-artifacts-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/deployment-artifacts/deployment-artifacts-view.html @@ -28,7 +28,7 @@
- {{artifact.artifactDisplayName}} + {{artifact.artifactDisplayName}} this.$scope.component).csarVersion = this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG); @@ -424,12 +424,17 @@ export class WorkspaceViewModel { //when checking out a major(certified) version this.components.unshift(component); } + this.EventListenerService.notifyObservers(EVENTS.ON_CHECKOUT, component); + // this.$state.go(this.$state.current.name, { + // id: component.uniqueId, + // type: component.componentType.toLowerCase(), + // components: this.components + // }); + this.$scope.mode = this.initViewMode(); + this.initChangeLifecycleStateButtons(); + this.initVersionObject(); + this.$scope.isLoading = false; - this.$state.go(this.$state.current.name, { - id: component.uniqueId, - type: component.componentType.toLowerCase(), - components: this.components - }); this.Notification.success({ message: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TEXT"), title: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TITLE") diff --git a/common-app-api/src/main/java/org/openecomp/sdc/be/config/Configuration.java b/common-app-api/src/main/java/org/openecomp/sdc/be/config/Configuration.java index 47fd5a28f7..7d37de7965 100644 --- a/common-app-api/src/main/java/org/openecomp/sdc/be/config/Configuration.java +++ b/common-app-api/src/main/java/org/openecomp/sdc/be/config/Configuration.java @@ -71,6 +71,7 @@ public class Configuration extends BasicConfiguration { private String titanCfgFile; private String titanMigrationKeySpaceCfgFile; private Boolean titanInMemoryGraph; + private int startMigrationFrom; private Long titanLockTimeout; private Long titanReconnectIntervalInSeconds; private Long titanHealthCheckReadTimeout; @@ -293,6 +294,14 @@ public class Configuration extends BasicConfiguration { this.titanInMemoryGraph = titanInMemoryGraph; } + public int getStartMigrationFrom() { + return startMigrationFrom; + } + + public void setStartMigrationFrom(int startMigrationFrom) { + this.startMigrationFrom = startMigrationFrom; + } + public Long getTitanLockTimeout() { return titanLockTimeout; } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java index 102c7dde6e..24d801262c 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/components/ComponentMetadataDataDefinition.java @@ -348,6 +348,14 @@ public abstract class ComponentMetadataDataDefinition extends ToscaDataDefinitio this.conformanceLevel = conformanceLevel; } + public String getLifecycleState() { + return state; + } + + public void setLifecycleState(String state) { + this.state = state; + } + @Override public String toString() { return "ComponentMetadataDataDefinition [uniqueId=" + uniqueId + ", name=" + name + ", version=" + version diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/AttributeDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/AttributeDataDefinition.java deleted file mode 100644 index a753270bbd..0000000000 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/AttributeDataDefinition.java +++ /dev/null @@ -1,209 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -package org.openecomp.sdc.be.datatypes.elements; - -import java.io.Serializable; -import java.util.Objects; - -import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; -import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; - -/** - * Represents AttributeDataDefinition - * - * @author mshitrit - * - */ -public class AttributeDataDefinition extends ToscaDataDefinition implements Serializable { - - /** - * - */ - private static final long serialVersionUID = -3046831950009259569L; - - private String uniqueId; - private String name; - private String type; - private String description; - - private String defaultValue; - private String value; - - private String status; - private SchemaDefinition schema; - - public AttributeDataDefinition() { - // Used From Attribute Defenition - } - - /** - * Clone Constructor - * - * @param attribute - */ - public AttributeDataDefinition(AttributeDataDefinition attribute) { - this.uniqueId = attribute.uniqueId; - this.name = attribute.name; - this.type = attribute.type; - this.description = attribute.description; - this.defaultValue = attribute.defaultValue; - this.value = attribute.value; - this.status = attribute.status; - this.schema = attribute.schema; - } - - public String getUniqueId() { - return uniqueId; - } - - public void setUniqueId(String uniqueId) { - this.uniqueId = uniqueId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getDefaultValue() { - return defaultValue; - } - - public void setDefaultValue(String defaultValue) { - this.defaultValue = defaultValue; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public SchemaDefinition getSchema() { - return schema; - } - - public void setSchema(SchemaDefinition entrySchema) { - this.schema = entrySchema; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((defaultValue == null) ? 0 : defaultValue.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); - result = prime * result + ((description == null) ? 0 : description.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((type == null) ? 0 : type.hashCode()); - result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode()); - result = prime * result + ((status == null) ? 0 : status.hashCode()); - result = prime * result + ((schema == null) ? 0 : schema.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - boolean equals = true; - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - - AttributeDataDefinition other = (AttributeDataDefinition) obj; - if (!Objects.equals(defaultValue, other.defaultValue)) { - equals = false; - } else if (!Objects.equals(value, other.value)) { - equals = false; - } else if (!Objects.equals(description, other.description)) { - equals = false; - } else if (!Objects.equals(name, other.name)) { - equals = false; - } else if (!Objects.equals(type, other.type)) { - equals = false; - } else if (!Objects.equals(uniqueId, other.uniqueId)) { - equals = false; - } else if (!Objects.equals(status, other.status)) { - equals = false; - } else if (!Objects.equals(schema, other.schema)) { - equals = false; - } - return equals; - } - - @Override - public String toString() { - return "AttributeDataDefinition [uniqueId=" + uniqueId + ", name=" + name + ", type=" + type + ", description=" - + description + ", defaultValue=" + defaultValue + ", value=" + value + ", status=" + status - + ", entrySchema=" + schema + "]"; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public Object getToscaPresentationValue(JsonPresentationFields field) { - switch (field) { - case NAME: - return name; - case UNIQUE_ID: - return uniqueId; - case TYPE: - return type; - case DESCRIPTION: - return description; - case VALUE: - return value; - case DEFAULT_VALUE: - return defaultValue; - default: - return super.getToscaPresentationValue(field); - } - } -} diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListCapabilityDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListCapabilityDataDefinition.java index 3057c72c67..c986c0fe7e 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListCapabilityDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListCapabilityDataDefinition.java @@ -33,10 +33,4 @@ public class ListCapabilityDataDefinition extends ListDataDefinition mapByName = listToMapByName(); - Map mapOtherByName = other.listToMapByName(); - mapByName.putAll(mapOtherByName); - return new ListCapabilityDataDefinition(mapByName.values().stream().collect(Collectors.toList())); - } } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListDataDefinition.java index 2eb8dcad2e..c9bf851e17 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListDataDefinition.java @@ -55,15 +55,17 @@ public class ListDataDefinition extends ToscaData listToscaDataDefinition.forEach(e -> e.setOwnerIdIfEmpty(ownerId)); } } - - - public Map listToMapByName() { - Map mapByName = new HashMap<>(); - listToscaDataDefinition.forEach(e -> mapByName.put((String)e.getToscaPresentationValue(JsonPresentationFields.NAME), e)); - return mapByName; - } - + @Override + public S mergeFunction(S other, boolean allowDefaultValueOverride){ + Map mapByName = listToMapByName(listToscaDataDefinition); + List otherList = ((ListDataDefinition)other).getListToscaDataDefinition(); + for(T item : otherList){ + mapByName.merge(item.getName(), item, (thisItem, otherItem) -> thisItem.mergeFunction(otherItem, allowDefaultValueOverride)); + } + ((ListDataDefinition)other).listToscaDataDefinition = mapByName.values().stream().collect(Collectors.toList()); + return other; + } } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListRequirementDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListRequirementDataDefinition.java index 4c69958e62..fb1248d100 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListRequirementDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ListRequirementDataDefinition.java @@ -6,6 +6,7 @@ import java.util.stream.Collectors; import org.codehaus.jackson.annotate.JsonCreator; import org.codehaus.jackson.annotate.JsonValue; +import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; public class ListRequirementDataDefinition extends ListDataDefinition { @@ -33,11 +34,8 @@ public class ListRequirementDataDefinition extends ListDataDefinition mapByName = listToMapByName(); - Map mapOtherByName = other.listToMapByName(); - mapByName.putAll(mapOtherByName); - return new ListRequirementDataDefinition(mapByName.values().stream().collect(Collectors.toList())); - } + + + } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/MapAttributesDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/MapAttributesDataDefinition.java deleted file mode 100644 index 817fbebd5c..0000000000 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/MapAttributesDataDefinition.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.openecomp.sdc.be.datatypes.elements; - -import java.util.Map; - -import org.codehaus.jackson.annotate.JsonCreator; -import org.codehaus.jackson.annotate.JsonValue; - -public class MapAttributesDataDefinition extends MapDataDefinition{ - - private String parentName; - - public MapAttributesDataDefinition(MapDataDefinition cdt, String parentName) { - super(cdt); - this.parentName = parentName; - } - - @JsonCreator - public MapAttributesDataDefinition(Map mapToscaDataDefinition) { - super(mapToscaDataDefinition); - } - public MapAttributesDataDefinition() { - super(); - - } - @JsonValue - @Override - public Map getMapToscaDataDefinition() { - return mapToscaDataDefinition; - } - - - public void setMapToscaDataDefinition(Map mapToscaDataDefinition) { - this.mapToscaDataDefinition = mapToscaDataDefinition; - } - - public String getParentName() { - return parentName; - } - - public void setParentName(String parentName) { - this.parentName = parentName; - } - - -} diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java index ed94ce0d87..4c798521c5 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java @@ -21,6 +21,7 @@ package org.openecomp.sdc.be.datatypes.elements; import java.io.Serializable; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -60,12 +61,11 @@ public class PropertyDataDefinition extends ToscaDataDefinition implements Seria private String value; private String label; - private Boolean hidden = Boolean.FALSE;; + protected Boolean hidden = Boolean.FALSE; private Boolean immutable = Boolean.FALSE; private String inputPath; - - + private String status; /** * The resource id which this property belongs to @@ -104,9 +104,10 @@ public class PropertyDataDefinition extends ToscaDataDefinition implements Seria this.setOwnerId(p.getOwnerId()); this.setGetInputValues(p.getInputValues); this.setInputPath(p.getInputPath()); + this.setStatus(p.getStatus()); } - + public String getInputPath() { return inputPath; } @@ -115,7 +116,6 @@ public class PropertyDataDefinition extends ToscaDataDefinition implements Seria this.inputPath = inputPath; } - public String getName() { return name; } @@ -238,6 +238,15 @@ public class PropertyDataDefinition extends ToscaDataDefinition implements Seria public void setGetInputValues(List getInputValues) { this.getInputValues = getInputValues; } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + @Override public String toString() { return "PropertyDataDefinition [uniqueId=" + uniqueId + ", type=" + type + ", required=" + required + ", defaultValue=" + defaultValue + ", description=" + description + ", entrySchema=" + schema + ", parentUniqueId=" + parentUniqueId + ", password=" + password + "]"; @@ -256,6 +265,7 @@ public class PropertyDataDefinition extends ToscaDataDefinition implements Seria result = prime * result + ((type == null) ? 0 : type.hashCode()); result = prime * result + ((uniqueId == null) ? 0 : uniqueId.hashCode()); result = prime * result + ((parentUniqueId == null) ? 0 : parentUniqueId.hashCode()); + result = prime * result + ((status == null) ? 0 : status.hashCode()); return result; } @@ -307,6 +317,11 @@ public class PropertyDataDefinition extends ToscaDataDefinition implements Seria return false; } else if (!uniqueId.equals(other.uniqueId)) return false; + if (status == null) { + if (other.status != null) + return false; + } else if (!status.equals(other.status)) + return false; return true; } @@ -332,34 +347,23 @@ public class PropertyDataDefinition extends ToscaDataDefinition implements Seria } } - protected T overrideDataDefinition(T other, boolean allowDefaultValueOverride){ - if(this.getType().equals(other.getType())){ + private boolean compareSchemaType(T other){ + return !"list".equals(type) && !"map".equals(type) || this.getSchema().getProperty().getType().equals(((PropertyDataDefinition)other).getSchema().getProperty().getType()); + } + + + @Override + public T mergeFunction(T other, boolean allowDefaultValueOverride){ + if(this.getType().equals(other.getType()) && compareSchemaType(other)){ other.setOwnerId(getOwnerId()); if(allowDefaultValueOverride) - other.setDefaultValue(getDefaultValue()); + other.setToscaPresentationValue(JsonPresentationFields.DEFAULT_VALUE, getDefaultValue()); return other; } return null; } - - - //return Either.right(propertyName) if an illegal merge was attempted (overriding data type is forbidden) - public static Either, String> mergeProperties(Map derivedProps, Map importedProps, boolean allowDefaultValueOverride){ - for(T property : importedProps.values()){ - derivedProps.merge(property.getName(), property, (derivedProp, importedProp) -> derivedProp.overrideDataDefinition(importedProp, allowDefaultValueOverride)); - //validate merge success - if(!derivedProps.containsKey(property.getName())) - return Either.right(property.getName()); - } - return Either.left(derivedProps); - } - - - public static Map listToMapByName(List propertiesList) { - return propertiesList.stream() - .collect(Collectors.toMap(p -> p.getName(), p -> p)); - } + } diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java index 6004e65949..f5cc2b661b 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/JsonPresentationFields.java @@ -38,8 +38,8 @@ public enum JsonPresentationFields { CONTACT_ID ("contactId", null), PROJECT_CODE ("projectCode", null), DISTRIBUTION_STATUS ("distributionStatus", GraphPropertyEnum.DISTRIBUTION_STATUS), - DERIVED_FROM_GENERIC_TYPE("derivedFromGenericType", null), - DERIVED_FROM_GENERIC_VERSION("derivedFromGenericVersion", null), + DERIVED_FROM_GENERIC_TYPE ("derivedFromGenericType", null), + DERIVED_FROM_GENERIC_VERSION ("derivedFromGenericVersion", null), ////Artifact ARTIFACT_TYPE ("artifactType", null), @@ -68,7 +68,7 @@ public enum JsonPresentationFields { REQUIRED_ARTIFACTS ("requiredArtifacts", null), DUPLICATED ("duplicated", null), HEAT_PARAMETERS ("heatParameters", null), - GENERATED_FROM_ID ("generatedFromId", null), + GENERATED_FROM_ID ("generatedFromId", null), // end artifacts @@ -89,10 +89,11 @@ public enum JsonPresentationFields { COMPONENT_INSTANCES ("componentInstances", null), RELATIONS ("relations", null), - + //attribute + STATUS ("status", null), //capability VALID_SOURCE_TYPE ("validSourceTypes", null), - CREATION_TIME ("creationTime", null), + CREATION_TIME ("creationTime", null), MODIFICATION_TIME ("modificationTime", null), CAPABILITY_SOURCES ("capabilitySources", null), MAX_OCCURRENCES ("maxOccurrences", null), @@ -124,17 +125,17 @@ public enum JsonPresentationFields { GROUP_UUID ("groupUUID", null), GROUP_MEMBER ("members", null), GROUP_ARTIFACTS ("artifacts", null), - GROUP_ARTIFACTS_UUID (" artifactsUuid", null), - GROUP_PROPERTIES (" properties", null), - GROUP_UNIQUE_ID (" groupUid", null), - POS_X (" posX", null), - POS_Y (" posY", null), - PROPERTY_VALUE_COUNTER (" propertyValueCounter", null), - CUSTOMIZATION_UUID (" customizationUUID", null), - GROUP_NAME (" groupName", null), - GROUP_INSTANCE_ARTIFACTS (" groupInstanceArtifacts", null), - GROUP_INSTANCE_ARTIFACTS_UUID (" groupInstanceArtifactsUuid", null), - GROUP_INSTANCE_PROPERTIES (" groupInstancesProperties", null), + GROUP_ARTIFACTS_UUID ("artifactsUuid", null), + GROUP_PROPERTIES ("properties", null), + GROUP_UNIQUE_ID ("groupUid", null), + POS_X ("posX", null), + POS_Y ("posY", null), + PROPERTY_VALUE_COUNTER ("propertyValueCounter", null), + CUSTOMIZATION_UUID ("customizationUUID", null), + GROUP_NAME ("groupName", null), + GROUP_INSTANCE_ARTIFACTS ("groupInstanceArtifacts", null), + GROUP_INSTANCE_ARTIFACTS_UUID ("groupInstanceArtifactsUuid", null), + GROUP_INSTANCE_PROPERTIES ("groupInstancesProperties", null), ; diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/tosca/ToscaDataDefinition.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/tosca/ToscaDataDefinition.java index d0f480b588..bf51ba4e28 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/tosca/ToscaDataDefinition.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/tosca/ToscaDataDefinition.java @@ -1,13 +1,19 @@ package org.openecomp.sdc.be.datatypes.tosca; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; import org.codehaus.jackson.annotate.JsonCreator; import org.codehaus.jackson.annotate.JsonIgnore; import org.codehaus.jackson.annotate.JsonValue; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; +import fj.data.Either; + public abstract class ToscaDataDefinition { protected Map toscaPresentation; @@ -47,4 +53,39 @@ public abstract class ToscaDataDefinition { public String getOwnerId(){ return (String) getToscaPresentationValue(JsonPresentationFields.OWNER_ID); } + + + public String getType(){ + return (String) getToscaPresentationValue(JsonPresentationFields.TYPE); + } + + public String getName(){ + return (String) getToscaPresentationValue(JsonPresentationFields.NAME); + } + + //default merge function for merging data maps - implement where needed and use mergeDataMaps method where applicable instead of map1.putAll(map2) + public T mergeFunction(T other, boolean allowDefaultValueOverride){ + other.setOwnerId(getOwnerId()); + return other; + } + + public static Either, String> mergeDataMaps(Map map1, Map map2){ + return mergeDataMaps(map1, map2, false); + } + + //return Either.right(item key) if an illegal merge was attempted (overriding data type is forbidden) + public static Either, String> mergeDataMaps(Map map1, Map map2, boolean allowDefaultValueOverride){ + for(Entry entry : map2.entrySet()){ + map1.merge(entry.getKey(), entry.getValue(), (item1, item2) -> item1.mergeFunction(item2, allowDefaultValueOverride)); + //validate merge success + if(!map1.containsKey(entry.getKey())) + return Either.right(entry.getKey()); + } + return Either.left(map1); + } + + public static Map listToMapByName(List dataList) { + return null == dataList? new HashMap<>() : dataList.stream() + .collect(Collectors.toMap(p -> p.getName(), p -> p)); + } } diff --git a/common/openecomp-common-configuration-management/openecomp-configuration-management-cli/dependency-reduced-pom.xml b/common/openecomp-common-configuration-management/openecomp-configuration-management-cli/dependency-reduced-pom.xml deleted file mode 100644 index 6c03f26d52..0000000000 --- a/common/openecomp-common-configuration-management/openecomp-configuration-management-cli/dependency-reduced-pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - openecomp-common-configuration-management - org.openecomp.sdc.common - 1.1.0-SNAPSHOT - .. - - 4.0.0 - org.openecomp.sdc.common - openecomp-configuration-management-cli - openecomp-configuration-management-cli - - - - maven-shade-plugin - 1.5 - - - package - - shade - - - - - org.openecomp.config.gui.app.Configuration - - - - - - - - - - - org.testng - testng - 6.8.8 - test - - - bsh - org.beanshell - - - jcommander - com.beust - - - - - junit - junit - RELEASE - test - - - hamcrest-core - org.hamcrest - - - - - - diff --git a/common/openecomp-sdc-artifact-generator-lib/openecomp-sdc-artifact-generator-core/src/main/java/org/openecomp/sdc/generator/aai/AaiArtifactGenerator.java b/common/openecomp-sdc-artifact-generator-lib/openecomp-sdc-artifact-generator-core/src/main/java/org/openecomp/sdc/generator/aai/AaiArtifactGenerator.java index 552e11e91d..c8e7be53d6 100644 --- a/common/openecomp-sdc-artifact-generator-lib/openecomp-sdc-artifact-generator-core/src/main/java/org/openecomp/sdc/generator/aai/AaiArtifactGenerator.java +++ b/common/openecomp-sdc-artifact-generator-lib/openecomp-sdc-artifact-generator-core/src/main/java/org/openecomp/sdc/generator/aai/AaiArtifactGenerator.java @@ -554,6 +554,7 @@ public class AaiArtifactGenerator implements ArtifactGenerator { ToscaTemplate tosca = null; if (checksum.equalsIgnoreCase(input.getChecksum())) { try { + log.debug("Input yaml name " + input.getName() + "payload " + new String(decodedInput)); tosca = GeneratorUtil.translateTosca(new String(decodedInput), ToscaTemplate.class); tosca.getMetadata().put("version", serviceVersion); return tosca; diff --git a/common/openecomp-sdc-artifact-generator-lib/openecomp-sdc-artifact-generator-core/src/test/java/org/openecomp/sdc/generator/ArtifactGenerationServiceTest.java b/common/openecomp-sdc-artifact-generator-lib/openecomp-sdc-artifact-generator-core/src/test/java/org/openecomp/sdc/generator/ArtifactGenerationServiceTest.java index 0ebe41c9a4..01029e8adc 100644 --- a/common/openecomp-sdc-artifact-generator-lib/openecomp-sdc-artifact-generator-core/src/test/java/org/openecomp/sdc/generator/ArtifactGenerationServiceTest.java +++ b/common/openecomp-sdc-artifact-generator-lib/openecomp-sdc-artifact-generator-core/src/test/java/org/openecomp/sdc/generator/ArtifactGenerationServiceTest.java @@ -863,7 +863,7 @@ public class ArtifactGenerationServiceTest { } } - //@Test +// @Test public void testErrorWhenAllottedResourceWithOutProvidingServiceId() { try { Map outputArtifactMap = new HashMap<>(); diff --git a/common/openecomp-tosca-datatype/src/main/resources/globalTypes/openecomp/nodes.yml b/common/openecomp-tosca-datatype/src/main/resources/globalTypes/openecomp/nodes.yml index c9c11a7da3..fd1a8e5f9a 100644 --- a/common/openecomp-tosca-datatype/src/main/resources/globalTypes/openecomp/nodes.yml +++ b/common/openecomp-tosca-datatype/src/main/resources/globalTypes/openecomp/nodes.yml @@ -408,7 +408,23 @@ node_types: type: list entry_schema: type: org.openecomp.datatypes.network.IpRequirements - required: true + required: true + network_role: + description: identical to VL network_role + type: string + required: false + order: + description: The order of the CP on the compute instance (e.g. eth2). + type: integer + required: false + exCP_naming: + description: CP Name + type: org.openecomp.datatypes.Naming + required: false + subnetpoolid: + description: subnet pool id + type: string + required: false capabilities: network.incoming.packets.rate: description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VendorSoftwareProducts.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VendorSoftwareProducts.java index 3ead86dc14..53fe2af31d 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VendorSoftwareProducts.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VendorSoftwareProducts.java @@ -141,7 +141,7 @@ public interface VendorSoftwareProducts extends VspEntities { notes = "Exports translated file to a zip file", response = File.class) Response getTranslatedFile(@PathParam("vspId") String vspId, - @QueryParam("version") String version, + @QueryParam("versionId") String versionId, @HeaderParam(USER_ID_HEADER_PARAM) String user); @GET diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VendorSoftwareProductsImpl.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VendorSoftwareProductsImpl.java index 9f8f3d366f..c730066770 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VendorSoftwareProductsImpl.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VendorSoftwareProductsImpl.java @@ -38,9 +38,20 @@ import org.openecomp.sdc.vendorsoftwareproduct.types.VersionedVendorSoftwareProd import org.openecomp.sdc.versioning.dao.types.Version; import org.openecomp.sdc.versioning.types.VersionInfo; import org.openecomp.sdc.versioning.types.VersionableEntityAction; -import org.openecomp.sdcrests.vendorsoftwareproducts.types.*; +import org.openecomp.sdcrests.vendorsoftwareproducts.types.PackageInfoDto; +import org.openecomp.sdcrests.vendorsoftwareproducts.types.QuestionnaireResponseDto; +import org.openecomp.sdcrests.vendorsoftwareproducts.types.ValidationResponseDto; +import org.openecomp.sdcrests.vendorsoftwareproducts.types.VersionSoftwareProductActionRequestDto; +import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspCreationDto; +import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspDescriptionDto; +import org.openecomp.sdcrests.vendorsoftwareproducts.types.VspDetailsDto; import org.openecomp.sdcrests.vsp.rest.VendorSoftwareProducts; -import org.openecomp.sdcrests.vsp.rest.mapping.*; +import org.openecomp.sdcrests.vsp.rest.mapping.MapPackageInfoToPackageInfoDto; +import org.openecomp.sdcrests.vsp.rest.mapping.MapQuestionnaireResponseToQuestionnaireResponseDto; +import org.openecomp.sdcrests.vsp.rest.mapping.MapValidationResponseToDto; +import org.openecomp.sdcrests.vsp.rest.mapping.MapVersionedVendorSoftwareProductInfoToVspDetailsDto; +import org.openecomp.sdcrests.vsp.rest.mapping.MapVspDescriptionDtoToVspDetails; +import org.openecomp.sdcrests.vsp.rest.mapping.MspVspDetailsToVspCreationDto; import org.openecomp.sdcrests.wrappers.GenericCollectionWrapper; import org.openecomp.sdcrests.wrappers.StringWrapperResponse; import org.slf4j.MDC; @@ -59,49 +70,49 @@ import java.util.List; @Scope(value = "prototype") public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { - private VendorSoftwareProductManager vendorSoftwareProductManager = - VspManagerFactory.getInstance().createInterface(); + private VendorSoftwareProductManager vendorSoftwareProductManager = + VspManagerFactory.getInstance().createInterface(); - private static final Logger logger = - LoggerFactory.getLogger(VendorSoftwareProductsImpl.class); + private static final Logger logger = + LoggerFactory.getLogger(VendorSoftwareProductsImpl.class); - private ActivityLogManager activityLogManager = - ActivityLogManagerFactory.getInstance().createInterface(); + private ActivityLogManager activityLogManager = + ActivityLogManagerFactory.getInstance().createInterface(); - @Override - public Response createVsp(VspDescriptionDto vspDescriptionDto, String user) { - MdcUtil.initMdc(LoggerServiceName.Create_VSP.toString()); - logger.audit(AuditMessages.AUDIT_MSG + AuditMessages.CREATE_VSP + vspDescriptionDto.getName()); - - VspDetails vspDetails = - new MapVspDescriptionDtoToVspDetails().applyMapping(vspDescriptionDto, VspDetails.class); + @Override + public Response createVsp(VspDescriptionDto vspDescriptionDto, String user) { + MdcUtil.initMdc(LoggerServiceName.Create_VSP.toString()); + logger.audit(AuditMessages.AUDIT_MSG + AuditMessages.CREATE_VSP + vspDescriptionDto.getName()); - vspDetails = vendorSoftwareProductManager.createVsp(vspDetails, user); + VspDetails vspDetails = + new MapVspDescriptionDtoToVspDetails().applyMapping(vspDescriptionDto, VspDetails.class); - MspVspDetailsToVspCreationDto mapping = new MspVspDetailsToVspCreationDto(); - VspCreationDto vspCreationDto = mapping.applyMapping(vspDetails, VspCreationDto.class); + vspDetails = vendorSoftwareProductManager.createVsp(vspDetails, user); - return Response.ok(vspCreationDto).build(); - } + MspVspDetailsToVspCreationDto mapping = new MspVspDetailsToVspCreationDto(); + VspCreationDto vspCreationDto = mapping.applyMapping(vspDetails, VspCreationDto.class); - @Override - public Response listVsps(String versionFilter, String user) { - MdcUtil.initMdc(LoggerServiceName.List_VSP.toString()); - List vspList = - vendorSoftwareProductManager.listVsps(versionFilter, user); - - GenericCollectionWrapper results = new GenericCollectionWrapper<>(); - if (!vspList.isEmpty()) { - MapVersionedVendorSoftwareProductInfoToVspDetailsDto mapper = - new MapVersionedVendorSoftwareProductInfoToVspDetailsDto(); - for (VersionedVendorSoftwareProductInfo versionedVsp : vspList) { - results.add(mapper.applyMapping(versionedVsp, VspDetailsDto.class)); - } - } + return Response.ok(vspCreationDto).build(); + } - return Response.ok(results).build(); + @Override + public Response listVsps(String versionFilter, String user) { + MdcUtil.initMdc(LoggerServiceName.List_VSP.toString()); + List vspList = + vendorSoftwareProductManager.listVsps(versionFilter, user); + + GenericCollectionWrapper results = new GenericCollectionWrapper<>(); + if (!vspList.isEmpty()) { + MapVersionedVendorSoftwareProductInfoToVspDetailsDto mapper = + new MapVersionedVendorSoftwareProductInfoToVspDetailsDto(); + for (VersionedVendorSoftwareProductInfo versionedVsp : vspList) { + results.add(mapper.applyMapping(versionedVsp, VspDetailsDto.class)); + } } + return Response.ok(results).build(); + } + @Override public Response getVsp(String vspId, String versionId, String user) { MdcUtil.initMdc(LoggerServiceName.Get_VSP.toString()); @@ -115,15 +126,15 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { VersionInfo versionInfo = getVersionInfo(vspId, VersionableEntityAction.Read, user); // - if(vspDetails.getOldVersion()!=null && !"".equals(vspDetails.getOldVersion())) { + if (vspDetails.getOldVersion() != null && !"".equals(vspDetails.getOldVersion())) { if (Version.valueOf(versionId).equals(versionInfo.getActiveVersion())) { try { Version healedVersion = vendorSoftwareProductManager.callAutoHeal(vspId, versionInfo, - vspDetails , user); + vspDetails, user); vspDetails = vendorSoftwareProductManager .getVsp(vspId, resolveVspVersion(vspId, healedVersion.toString(), user, - VersionableEntityAction.Read),user); + VersionableEntityAction.Read), user); versionInfo = getVersionInfo(vspId, VersionableEntityAction.Read, user); } catch (Exception e) { //to do @@ -137,8 +148,8 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { .applyMapping(new VersionedVendorSoftwareProductInfo(vspDetails, versionInfo), VspDetailsDto.class); - return Response.ok(vspDetailsDto).build(); - } + return Response.ok(vspDetailsDto).build(); + } @Override public Response updateVsp(String vspId, String versionId, VspDescriptionDto vspDescriptionDto, @@ -149,23 +160,23 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { vspDetails.setId(vspId); vspDetails.setVersion(resolveVspVersion(vspId, null, user, VersionableEntityAction.Write)); - vendorSoftwareProductManager.updateVsp(vspDetails, user); + vendorSoftwareProductManager.updateVsp(vspDetails, user); - return Response.ok().build(); - } + return Response.ok().build(); + } - @Override - public Response deleteVsp(String vspId, String user) { - MdcUtil.initMdc(LoggerServiceName.Delete_VSP.toString()); - vendorSoftwareProductManager.deleteVsp(vspId, user); + @Override + public Response deleteVsp(String vspId, String user) { + MdcUtil.initMdc(LoggerServiceName.Delete_VSP.toString()); + vendorSoftwareProductManager.deleteVsp(vspId, user); - return Response.ok().build(); - } + return Response.ok().build(); + } - @Override - public Response actOnVendorSoftwareProduct(String vspId, String versionId, - VersionSoftwareProductActionRequestDto request, - String user) throws IOException { + @Override + public Response actOnVendorSoftwareProduct(String vspId, String versionId, + VersionSoftwareProductActionRequestDto request, + String user) throws IOException { switch (request.getAction()) { case Checkout: @@ -207,89 +218,88 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { return Response.ok().build(); } - @Override - public Response getValidationVsp(String user) - throws Exception { - String validationVspId = vendorSoftwareProductManager.fetchValidationVsp(user); - StringWrapperResponse response = new StringWrapperResponse(validationVspId); - return Response.ok(response).build(); - } + @Override + public Response getValidationVsp(String user) + throws Exception { + String validationVspId = vendorSoftwareProductManager.fetchValidationVsp(user); + StringWrapperResponse response = new StringWrapperResponse(validationVspId); + return Response.ok(response).build(); + } - @Override - public Response getOrchestrationTemplate(String vspId, String versionId, String user) { - MdcUtil.initMdc(LoggerServiceName.Get_Uploaded_File.toString()); - byte[] orchestrationTemplateFile = - vendorSoftwareProductManager - .getOrchestrationTemplateFile(vspId, - resolveVspVersion(vspId, versionId, user, VersionableEntityAction.Read), user); + @Override + public Response getOrchestrationTemplate(String vspId, String versionId, String user) { + MdcUtil.initMdc(LoggerServiceName.Get_Uploaded_File.toString()); + byte[] orchestrationTemplateFile = + vendorSoftwareProductManager + .getOrchestrationTemplateFile(vspId, + resolveVspVersion(vspId, versionId, user, VersionableEntityAction.Read), user); - if (orchestrationTemplateFile == null) { - return Response.status(Response.Status.NOT_FOUND).build(); - } - Response.ResponseBuilder response = Response.ok(orchestrationTemplateFile); - response.header("Content-Disposition", "attachment; filename=LatestHeatPackage.zip"); - return response.build(); + if (orchestrationTemplateFile == null) { + return Response.status(Response.Status.NOT_FOUND).build(); } + Response.ResponseBuilder response = Response.ok(orchestrationTemplateFile); + response.header("Content-Disposition", "attachment; filename=LatestHeatPackage.zip"); + return response.build(); + } - @Override - public Response listPackages(String category, String subCategory, String user) { - MdcUtil.initMdc(LoggerServiceName.List_Packages.toString()); - List packageInfoList = - vendorSoftwareProductManager.listPackages(category, subCategory); + @Override + public Response listPackages(String category, String subCategory, String user) { + MdcUtil.initMdc(LoggerServiceName.List_Packages.toString()); + List packageInfoList = + vendorSoftwareProductManager.listPackages(category, subCategory); - GenericCollectionWrapper results = new GenericCollectionWrapper<>(); - MapPackageInfoToPackageInfoDto mapper = new MapPackageInfoToPackageInfoDto(); + GenericCollectionWrapper results = new GenericCollectionWrapper<>(); + MapPackageInfoToPackageInfoDto mapper = new MapPackageInfoToPackageInfoDto(); - if (packageInfoList != null) { - for (PackageInfo packageInfo : packageInfoList) { - results.add(mapper.applyMapping(packageInfo, PackageInfoDto.class)); - } - } - return Response.ok(results).build(); + if (packageInfoList != null) { + for (PackageInfo packageInfo : packageInfoList) { + results.add(mapper.applyMapping(packageInfo, PackageInfoDto.class)); + } } + return Response.ok(results).build(); + } @Override - public Response getTranslatedFile(String vspId, String version, String user) { + public Response getTranslatedFile(String vspId, String versionId, String user) { MdcUtil.initMdc(LoggerServiceName.Get_Translated_File.toString()); - File zipFile = - vendorSoftwareProductManager.getTranslatedFile(vspId,Version.valueOf(version), user); - Version versionObj = Version.valueOf(version); - Version resolvedVersion = versionObj == null + Version version = Version.valueOf(versionId); + Version resolvedVersion = version == null ? getVersionInfo(vspId, VersionableEntityAction.Read, user).getLatestFinalVersion() - : versionObj; - + : version; - Response.ResponseBuilder response = Response.ok(zipFile); - if (zipFile == null) { - logger.audit(AuditMessages.AUDIT_MSG + AuditMessages.IMPORT_FAIL + vspId); - return Response.status(Response.Status.NOT_FOUND).build(); - } - response.header("Content-Disposition", "attachment; filename=" + zipFile.getName()); + File zipFile = vendorSoftwareProductManager.getTranslatedFile(vspId, resolvedVersion, user); - logger.audit(AuditMessages.AUDIT_MSG + AuditMessages.IMPORT_SUCCESS + vspId); - return response.build(); + Response.ResponseBuilder response = Response.ok(zipFile); + if (zipFile == null) { + logger.audit(AuditMessages.AUDIT_MSG + AuditMessages.IMPORT_FAIL + vspId); + return Response.status(Response.Status.NOT_FOUND).build(); } + response.header("Content-Disposition", "attachment; filename=" + zipFile.getName()); - @Override - public Response getQuestionnaire(String vspId, String versionId, String user) { - MdcUtil.initMdc(LoggerServiceName.Get_Questionnaire_VSP.toString()); - QuestionnaireResponse questionnaireResponse = - vendorSoftwareProductManager.getVspQuestionnaire(vspId, - resolveVspVersion(vspId, versionId, user, VersionableEntityAction.Read), user); - - if (questionnaireResponse.getErrorMessage() != null) { - return Response.status(Response.Status.EXPECTATION_FAILED).entity( - new MapQuestionnaireResponseToQuestionnaireResponseDto() - .applyMapping(questionnaireResponse, QuestionnaireResponseDto.class)).build(); - } + logger.audit(AuditMessages.AUDIT_MSG + AuditMessages.IMPORT_SUCCESS + vspId); + return response.build(); + } - QuestionnaireResponseDto result = new MapQuestionnaireResponseToQuestionnaireResponseDto() - .applyMapping(questionnaireResponse, QuestionnaireResponseDto.class); - return Response.ok(result).build(); + @Override + public Response getQuestionnaire(String vspId, String versionId, String user) { + MdcUtil.initMdc(LoggerServiceName.Get_Questionnaire_VSP.toString()); + QuestionnaireResponse questionnaireResponse = + vendorSoftwareProductManager.getVspQuestionnaire(vspId, + resolveVspVersion(vspId, versionId, user, VersionableEntityAction.Read), user); + + if (questionnaireResponse.getErrorMessage() != null) { + return Response.status(Response.Status.EXPECTATION_FAILED).entity( + new MapQuestionnaireResponseToQuestionnaireResponseDto() + .applyMapping(questionnaireResponse, QuestionnaireResponseDto.class)).build(); } + QuestionnaireResponseDto result = new MapQuestionnaireResponseToQuestionnaireResponseDto() + .applyMapping(questionnaireResponse, QuestionnaireResponseDto.class); + return Response.ok(result).build(); + } + @Override public Response updateQuestionnaire(String questionnaireData, String vspId, String versionId, String user) { @@ -300,26 +310,26 @@ public class VendorSoftwareProductsImpl implements VendorSoftwareProducts { return Response.ok().build(); } - @Override - public Response heal(String vspId, String versionId, String user) { - vendorSoftwareProductManager.heal(vspId, Version.valueOf(versionId), user); - - return Response.ok().build(); - } + @Override + public Response heal(String vspId, String versionId, String user) { + vendorSoftwareProductManager.heal(vspId, Version.valueOf(versionId), user); - @Override - public Response getVspInformationArtifact(String vspId, String versionId, String user) { - MdcUtil.initMdc(LoggerServiceName.Get_Information_Artifact.toString()); - File textInformationArtifact = - vendorSoftwareProductManager.getInformationArtifact(vspId, - resolveVspVersion(vspId, versionId, user, VersionableEntityAction.Read), user); + return Response.ok().build(); + } - Response.ResponseBuilder response = Response.ok(textInformationArtifact); - if (textInformationArtifact == null) { - return Response.status(Response.Status.NOT_FOUND).build(); - } - response - .header("Content-Disposition", "attachment; filename=" + textInformationArtifact.getName()); - return response.build(); + @Override + public Response getVspInformationArtifact(String vspId, String versionId, String user) { + MdcUtil.initMdc(LoggerServiceName.Get_Information_Artifact.toString()); + File textInformationArtifact = + vendorSoftwareProductManager.getInformationArtifact(vspId, + resolveVspVersion(vspId, versionId, user, VersionableEntityAction.Read), user); + + Response.ResponseBuilder response = Response.ok(textInformationArtifact); + if (textInformationArtifact == null) { + return Response.status(Response.Status.NOT_FOUND).build(); } + response + .header("Content-Disposition", "attachment; filename=" + textInformationArtifact.getName()); + return response.build(); + } } diff --git a/openecomp-be/backend/openecomp-sdc-vendor-license-manager/src/main/java/org/openecomp/sdc/vendorlicense/impl/VendorLicenseManagerImpl.java b/openecomp-be/backend/openecomp-sdc-vendor-license-manager/src/main/java/org/openecomp/sdc/vendorlicense/impl/VendorLicenseManagerImpl.java index 451415c5ea..eb559f2e62 100644 --- a/openecomp-be/backend/openecomp-sdc-vendor-license-manager/src/main/java/org/openecomp/sdc/vendorlicense/impl/VendorLicenseManagerImpl.java +++ b/openecomp-be/backend/openecomp-sdc-vendor-license-manager/src/main/java/org/openecomp/sdc/vendorlicense/impl/VendorLicenseManagerImpl.java @@ -25,6 +25,8 @@ import org.openecomp.sdc.activityLog.ActivityLogManager; import org.openecomp.sdc.activityLog.ActivityLogManagerFactory; import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity; import org.openecomp.sdc.datatypes.error.ErrorLevel; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage; import org.openecomp.sdc.logging.context.impl.MdcDataErrorMessage; import org.openecomp.sdc.logging.types.LoggerConstants; @@ -87,6 +89,8 @@ public class VendorLicenseManagerImpl implements VendorLicenseManager { LicenseKeyGroupDaoFactory.getInstance().createInterface(); private ActivityLogManager activityLogManager = ActivityLogManagerFactory.getInstance().createInterface(); private static MdcDataDebugMessage mdcDataDebugMessage = new MdcDataDebugMessage(); + private static final Logger logger = + LoggerFactory.getLogger(VendorLicenseManagerImpl.class); private static void sortVlmListByModificationTimeDescOrder( List vendorLicenseModels) { @@ -178,14 +182,21 @@ public class VendorLicenseManagerImpl implements VendorLicenseManager { version.setStatus(VersionStatus.Locked); } - VendorLicenseModelEntity vlm = - vendorLicenseModelDao.get(new VendorLicenseModelEntity(entry.getKey(), version)); - if (vlm != null) { - VersionedVendorLicenseModel versionedVlm = new VersionedVendorLicenseModel(); - versionedVlm.setVendorLicenseModel(vlm); - versionedVlm.setVersionInfo(versionInfo); - vendorLicenseModels.add(versionedVlm); - } + try { + VendorLicenseModelEntity vlm = + vendorLicenseModelDao.get(new VendorLicenseModelEntity(entry.getKey(), version)); + if (vlm != null) { + VersionedVendorLicenseModel versionedVlm = new VersionedVendorLicenseModel(); + versionedVlm.setVendorLicenseModel(vlm); + versionedVlm.setVersionInfo(versionInfo); + vendorLicenseModels.add(versionedVlm); + } + }catch(RuntimeException rte){ + logger.error("Error trying to retrieve vlm["+entry.getKey()+"] version["+version.toString + ()+"] " + + "message:"+rte + .getMessage()); + } } sortVlmListByModificationTimeDescOrder(vendorLicenseModels); diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/VSPPackage.zip b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/VSPPackage.zip deleted file mode 100644 index ca55484a3c258f850fc480047fae8ae0257ab5a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33617 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%0A$fW&meY*t(;DS#NK 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 diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/OrchestrationTemplateCandidateManagerFactoryImpl.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/OrchestrationTemplateCandidateManagerFactoryImpl.java index 65aab2d9f4..77d496f0c8 100644 --- a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/OrchestrationTemplateCandidateManagerFactoryImpl.java +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/OrchestrationTemplateCandidateManagerFactoryImpl.java @@ -26,7 +26,11 @@ import org.openecomp.sdc.activitylog.dao.ActivityLogDaoFactory; import org.openecomp.sdc.healing.factory.HealingManagerFactory; import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager; import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManagerFactory; +import org.openecomp.sdc.vendorsoftwareproduct.dao.ComponentDaoFactory; +import org.openecomp.sdc.vendorsoftwareproduct.dao.MibDaoFactory; +import org.openecomp.sdc.vendorsoftwareproduct.dao.NicDaoFactory; import org.openecomp.sdc.vendorsoftwareproduct.dao.OrchestrationTemplateDaoFactory; +import org.openecomp.sdc.vendorsoftwareproduct.dao.ProcessDaoFactory; import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductDaoFactory; import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDaoFactory; import org.openecomp.sdc.vendorsoftwareproduct.factory.CandidateServiceFactory; @@ -45,6 +49,10 @@ public class OrchestrationTemplateCandidateManagerFactoryImpl extends CompositionDataExtractorFactory.getInstance().createInterface(), ServiceModelDaoFactory.getInstance().createInterface(), CompositionEntityDataManagerFactory.getInstance().createInterface(), + NicDaoFactory.getInstance().createInterface(), + ComponentDaoFactory.getInstance().createInterface(), + MibDaoFactory.getInstance().createInterface(), + ProcessDaoFactory.getInstance().createInterface(), ActivityLogManagerFactory.getInstance().createInterface()); diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/OrchestrationTemplateCandidateManagerImpl.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/OrchestrationTemplateCandidateManagerImpl.java index 9373bfb3a6..99a438f3a8 100644 --- a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/OrchestrationTemplateCandidateManagerImpl.java +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/OrchestrationTemplateCandidateManagerImpl.java @@ -19,11 +19,15 @@ */ package org.openecomp.sdc.vendorsoftwareproduct.impl; - +import static org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductConstants.GENERAL_COMPONENT_ID; +import static org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductConstants.UniqueValues + .PROCESS_NAME; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; +import org.apache.xalan.xslt.Process; import org.openecomp.core.model.dao.ServiceModelDao; import org.openecomp.core.model.types.ServiceElement; +import org.openecomp.core.util.UniqueValueUtil; import org.openecomp.core.utilities.file.FileContentHandler; import org.openecomp.core.utilities.file.FileUtils; import org.openecomp.core.utilities.json.JsonUtil; @@ -51,10 +55,16 @@ import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel; import org.openecomp.sdc.translator.services.heattotosca.HeatToToscaUtil; import org.openecomp.sdc.validation.util.ValidationManagerUtil; import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager; +import org.openecomp.sdc.vendorsoftwareproduct.dao.ComponentDao; +import org.openecomp.sdc.vendorsoftwareproduct.dao.MibDao; +import org.openecomp.sdc.vendorsoftwareproduct.dao.NicDao; import org.openecomp.sdc.vendorsoftwareproduct.dao.OrchestrationTemplateDao; +import org.openecomp.sdc.vendorsoftwareproduct.dao.ProcessDao; import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductDao; import org.openecomp.sdc.vendorsoftwareproduct.dao.VendorSoftwareProductInfoDao; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.MibEntity; import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateCandidateData; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ProcessEntity; import org.openecomp.sdc.vendorsoftwareproduct.dao.type.UploadData; import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails; import org.openecomp.sdc.vendorsoftwareproduct.errors.OrchestrationTemplateNotFoundErrorBuilder; @@ -69,7 +79,8 @@ import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStru import org.openecomp.sdc.vendorsoftwareproduct.utils.VendorSoftwareProductUtils; import org.openecomp.sdc.versioning.dao.types.Version; import org.openecomp.sdcrests.activitylog.types.ActivityType; - +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComponentEntity; +import org.openecomp.sdc.vendorsoftwareproduct.dao.type.NicEntity; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -78,6 +89,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Collection; public class OrchestrationTemplateCandidateManagerImpl implements OrchestrationTemplateCandidateManager { @@ -93,7 +105,11 @@ public class OrchestrationTemplateCandidateManagerImpl private CompositionDataExtractor compositionDataExtractor; private ServiceModelDao serviceModelDao; private CompositionEntityDataManager compositionEntityDataManager; + private NicDao nicDao; + private ComponentDao componentDao; + private MibDao mibDao; private ActivityLogManager activityLogManager; + private ProcessDao processDao; public OrchestrationTemplateCandidateManagerImpl( VendorSoftwareProductDao vendorSoftwareProductDao, VendorSoftwareProductInfoDao @@ -103,6 +119,10 @@ public class OrchestrationTemplateCandidateManagerImpl CompositionDataExtractor compositionDataExtractor, ServiceModelDao serviceModelDao, CompositionEntityDataManager compositionEntityDataManager, + NicDao nicDao, + ComponentDao componentDao, + MibDao mibDao, + ProcessDao processDao, ActivityLogManager activityLogManager) { this.vendorSoftwareProductDao = vendorSoftwareProductDao; this.vspInfoDao = vspInfoDao; @@ -112,6 +132,10 @@ public class OrchestrationTemplateCandidateManagerImpl this.compositionDataExtractor = compositionDataExtractor; this.serviceModelDao = serviceModelDao; this.compositionEntityDataManager = compositionEntityDataManager; + this.nicDao = nicDao; + this.componentDao = componentDao; + this.mibDao = mibDao; + this.processDao = processDao; this.activityLogManager = activityLogManager; } @@ -220,6 +244,15 @@ public class OrchestrationTemplateCandidateManagerImpl if (!zipByteArrayInputStream.isPresent()) { return response; } + Map componentsQustanniare = new HashMap<>(); + Map> componentNicsQustanniare = new HashMap<>(); + Map> componentMIBList = new HashMap<>(); + Map> processes = new HashMap<>(); + Map processArtifact = new HashMap<>(); + + backupComponentsQuestionnaireBeforeDelete(vspId, version, componentsQustanniare, + componentNicsQustanniare, componentMIBList, processes, processArtifact); + deleteUploadDataAndContent(vspId, version); saveHotData(vspId, version, zipByteArrayInputStream.get(), fileContentMap, tree); @@ -230,6 +263,8 @@ public class OrchestrationTemplateCandidateManagerImpl serviceModelDao.storeServiceModel(vspId, version, toscaServiceModel); compositionEntityDataManager.saveCompositionData(vspId, version, compositionDataExtractor.extractServiceCompositionData(toscaServiceModel)); + retainComponentQuestionnaireData(vspId, version, componentsQustanniare, + componentNicsQustanniare, componentMIBList, processes, processArtifact); } uploadFileResponse.addStructureErrors(uploadErrors); @@ -330,6 +365,133 @@ public class OrchestrationTemplateCandidateManagerImpl .ofNullable(candidateService.getOrchestrationTemplateCandidate(vspId, version)); } + private void retainComponentQuestionnaireData(String vspId, Version activeVersion, + Map componentsQustanniare, + Map> componentNicsQustanniare, + Map> componentMIBList, + Map> processes, + Map processArtifact) { + //VSP processes + restoreProcess(vspId, activeVersion, GENERAL_COMPONENT_ID, GENERAL_COMPONENT_ID, processes, + processArtifact); + Collection + components = vendorSoftwareProductDao.listComponents(vspId, activeVersion); + components.forEach(componentEntity -> { + String componentName = componentEntity.getComponentCompositionData().getName(); + if( componentsQustanniare.containsKey(componentName) ){ + componentDao.updateQuestionnaireData(vspId, activeVersion, + componentEntity.getId(),componentsQustanniare.get(componentEntity.getComponentCompositionData() + .getName())); + if( componentNicsQustanniare.containsKey(componentName) ){ + Map nicsQustanniare=componentNicsQustanniare.get(componentName); + Collection + nics=nicDao.list(new NicEntity(vspId, activeVersion, componentEntity.getId(), null)); + nics.forEach(nicEntity -> { + if(nicsQustanniare.containsKey(nicEntity.getNicCompositionData().getName())){ + nicDao.updateQuestionnaireData(vspId, activeVersion,componentEntity.getId + (),nicEntity.getId(),nicsQustanniare.get(nicEntity.getNicCompositionData().getName())); + } + }); + } + //MIB + if(componentMIBList.containsKey(componentName)) { + Collection mibList = componentMIBList.get(componentName); + mibList.forEach(mib -> { + mib.setComponentId(componentEntity.getId()); + mibDao.create(mib); + }); + } + //VFC processes + restoreProcess(vspId, activeVersion, componentEntity.getId(), componentName, processes, + processArtifact); + } + }); + } + + private void backupComponentsQuestionnaireBeforeDelete(String vspId, Version activeVersion, + Map componentsQustanniare, + Map> + componentNicsQustanniare, + Map> + componentMIBList, + Map> componentProcesses, + Map processArtifact) { + //backup VSP processes + backupProcess(vspId, activeVersion, GENERAL_COMPONENT_ID, GENERAL_COMPONENT_ID, + componentProcesses,processArtifact); + Collection componentsCompositionAndQuestionnaire= vendorSoftwareProductDao + .listComponentsCompositionAndQuestionnaire(vspId, + activeVersion); + componentsCompositionAndQuestionnaire.forEach(componentEntity ->{ + String componentName=componentEntity.getComponentCompositionData().getName(); + componentsQustanniare.put(componentName,componentEntity + .getQuestionnaireData()); + Collection + nics=nicDao.list(new NicEntity(vspId, activeVersion,componentEntity.getId(),null)); + //backup mib + Collection componentMIB = mibDao.listArtifacts(new + MibEntity(vspId, activeVersion, componentEntity.getId(), null)); + if(CollectionUtils.isNotEmpty(componentMIB)){ + componentMIBList.put(componentName,componentMIB); + } + + //backup component processes + backupProcess(vspId, activeVersion, componentEntity.getId(), componentName, + componentProcesses,processArtifact); + if(CollectionUtils.isNotEmpty(nics)) { + Map nicsQustanniare = new HashMap<>(); + nics.forEach(nicEntity -> { + NicEntity nic = nicDao.get(new NicEntity(vspId, activeVersion, componentEntity.getId(), + nicEntity.getId())); + NicEntity nicQuestionnaire = nicDao.getQuestionnaireData(vspId,activeVersion, + componentEntity.getId(),nicEntity.getId()); + + nicsQustanniare + .put(nicEntity.getNicCompositionData().getName(), nicQuestionnaire.getQuestionnaireData()); + }); + componentNicsQustanniare.put(componentName, nicsQustanniare); + } + }); + } + + private void backupProcess(String vspId, Version activeVersion, String componentId, + String componentName, Map> processes, + Map processArtifact){ + Collection processList = vendorSoftwareProductDao.listProcesses(vspId, + activeVersion, componentId); + if(!processList.isEmpty()){ + processes.put(componentName,processList); + processList.forEach(process -> { + //ProcessArtifactEntity artifact = vendorSoftwareProductDao.getProcessArtifact(vspId, + // activeVersion, componentId, process.getId()); + ProcessEntity artifact = processDao.get(new ProcessEntity(vspId,activeVersion,componentId,process.getId())); + if(artifact.getArtifact()!=null) { + processArtifact.put(process.getId(), artifact); + } + }); + } + } + + private void restoreProcess(String vspId, Version activeVersion, String componentId, + String componentName, Map> processes, + Map processArtifact){ + if(processes.containsKey(componentName)) { + Collection processList = processes.get(componentName); + processList.forEach(process -> { + //Reatin VFC process + if (!GENERAL_COMPONENT_ID.equals(componentId) && processArtifact.containsKey(process.getId + ())) { + ProcessEntity artifact = processArtifact.get(process.getId()); + artifact.setComponentId(componentId); + UniqueValueUtil.createUniqueValue(PROCESS_NAME, vspId, activeVersion.toString(), + componentId, process.getName()); + vendorSoftwareProductDao.createProcess(artifact); + } + }); + } + } + private HeatStructureTree createAndValidateHeatTree(OrchestrationTemplateActionResponse response, FileContentHandler fileContentMap) { VendorSoftwareProductUtils.addFileNamesToUploadFileResponse(fileContentMap, response); diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/VendorSoftwareProductManagerImpl.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/VendorSoftwareProductManagerImpl.java index 0d2023f387..2d1b62cd40 100644 --- a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/VendorSoftwareProductManagerImpl.java +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/VendorSoftwareProductManagerImpl.java @@ -472,10 +472,17 @@ public class VendorSoftwareProductManagerImpl implements VendorSoftwareProductMa if (user.equals(versionInfo.getLockingUser())) { version.setStatus(VersionStatus.Locked); } - VspDetails vsp = vspInfoDao.get(new VspDetails(entry.getKey(), version)); - if (vsp != null && !vsp.getId().equals(VALIDATION_VSP_ID)) { - vsp.setValidationDataStructure(null); - vsps.add(new VersionedVendorSoftwareProductInfo(vsp, versionInfo)); + try { + VspDetails vsp = vspInfoDao.get(new VspDetails(entry.getKey(), version)); + if (vsp != null && !vsp.getId().equals(VALIDATION_VSP_ID)) { + vsp.setValidationDataStructure(null); + vsps.add(new VersionedVendorSoftwareProductInfo(vsp, versionInfo)); + } + }catch(RuntimeException rte){ + logger.error("Error trying to retrieve vsp["+entry.getKey()+"] version["+version.toString + ()+"] " + + "message:"+rte + .getMessage()); } } diff --git a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java index 0be6a55df6..f850afbab8 100644 --- a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java +++ b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/errors/Messages.java @@ -35,7 +35,7 @@ public enum Messages { MANIFEST_NOT_EXIST("Manifest doesn't exist"), FILE_TYPE_NOT_LEGAL("File type not legal as data for other file"), MODULE_IN_MANIFEST_NO_YAML("Module '%s', has no yaml file reference"), - NO_MODULES_IN_MANIFEST("At least on Base/Module must be defined \n"), + NO_MODULES_IN_MANIFEST("At least one Base/Module must be defined \n"), MODULE_IN_MANIFEST_VOL_ENV_NO_VOL("Module '%s', has volume Env. reference with no Volume " + "reference"), ILLEGAL_MANIFEST("Illegal Manifest"), diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-api/pom.xml b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-api/pom.xml index bab8bc0e01..08a09273c6 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-api/pom.xml +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-api/pom.xml @@ -31,7 +31,7 @@ com.amdocs.zusammen zusammen-adaptor-inbound-api - 0.0.1-SNAPSHOT + 0.0.1 org.openecomp.sdc diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-core/pom.xml b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-core/pom.xml index 9bb1e1dbc0..c1870d8c64 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-core/pom.xml +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-core/pom.xml @@ -21,17 +21,17 @@ com.amdocs.zusammen zusammen-commons-utils - 0.0.1-SNAPSHOT + 0.0.1 com.amdocs.zusammen zusammen-adaptor-inbound-api - 0.0.1-SNAPSHOT + 0.0.1 com.amdocs.zusammen zusammen-adaptor-inbound-impl - 0.0.1-SNAPSHOT + 0.0.1 runtime @@ -53,7 +53,7 @@ com.amdocs.zusammen.plugin zusammen-search-index-empty-plugin - 0.0.1-SNAPSHOT + 0.0.1 runtime diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/pom.xml b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/pom.xml index ff45d1fa56..57f92f1b09 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/pom.xml +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-zusammen-lib/openecomp-zusammen-plugin/pom.xml @@ -15,23 +15,23 @@ com.amdocs.zusammen zusammen-sdk - 0.0.1-SNAPSHOT + 0.0.1 com.amdocs.zusammen zusammen-commons-db-api - 0.0.1-SNAPSHOT + 0.0.1 com.amdocs.zusammen zusammen-commons-db-impl - 0.0.1-SNAPSHOT + 0.0.1 runtime com.amdocs.zusammen.plugin zusammen-state-store-cassandra-plugin - 0.0.1-SNAPSHOT + 0.0.1 diff --git a/openecomp-be/lib/openecomp-healing-lib/openecomp-sdc-healing-impl/src/main/java/org/openecomp/sdc/healing/healers/CompositionDataHealer.java b/openecomp-be/lib/openecomp-healing-lib/openecomp-sdc-healing-impl/src/main/java/org/openecomp/sdc/healing/healers/CompositionDataHealer.java index 283f6c83b6..99e0a0ac6c 100644 --- a/openecomp-be/lib/openecomp-healing-lib/openecomp-sdc-healing-impl/src/main/java/org/openecomp/sdc/healing/healers/CompositionDataHealer.java +++ b/openecomp-be/lib/openecomp-healing-lib/openecomp-sdc-healing-impl/src/main/java/org/openecomp/sdc/healing/healers/CompositionDataHealer.java @@ -172,7 +172,9 @@ public class CompositionDataHealer implements Healer { JsonUtil.json2Object(component.getCompositionData(), ComponentData.class); componentData .setDisplayName(compositionDataExtractor.getComponentDisplayName(componentData.getName())); - componentData.setVfcCode(componentData.getDisplayName()); + String displayName = componentData.getDisplayName(); + componentData.setName(displayName); + componentData.setVfcCode(displayName); component.setCompositionData(JsonUtil.object2Json(componentData)); mdcDataDebugMessage.debugExitMessage("VSP id, component id", component.getVspId(), component diff --git a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/ExternalArtifactEnricher.java b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/ExternalArtifactEnricher.java index 3c27a0fac8..fb0622cd67 100644 --- a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/ExternalArtifactEnricher.java +++ b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/ExternalArtifactEnricher.java @@ -26,6 +26,8 @@ import org.openecomp.sdc.common.utils.CommonUtil; import org.openecomp.sdc.datatypes.error.ErrorMessage; import org.openecomp.sdc.enrichment.inter.Enricher; import org.openecomp.sdc.enrichment.inter.ExternalArtifactEnricherInterface; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; import org.openecomp.sdc.logging.context.impl.MdcDataDebugMessage; import java.io.InputStream; @@ -43,6 +45,7 @@ public class ExternalArtifactEnricher extends Enricher { "An Error has occured during enrichment of external artifacts "; private static Collection implementingClasses = getExternalArtifactEnrichedImplClassesList(); + private static Logger logger = LoggerFactory.getLogger(ExternalArtifactEnricher.class); private static Collection getExternalArtifactEnrichedImplClassesList() { InputStream externalArtifactEnrichConfigurationJson = @@ -68,7 +71,8 @@ public class ExternalArtifactEnricher extends Enricher { externalArtifactEnricherInstance.enrich(this.data); } } catch (Exception e) { - e.printStackTrace(); //// FIXME: 29-Nov-16 + e.printStackTrace(); + logger.error(e.getMessage()); } mdcDataDebugMessage.debugExitMessage(null, null); diff --git a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/ProcessArtifactEnricher.java b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/ProcessArtifactEnricher.java index b4a2815d69..a5f6529bbb 100644 --- a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/ProcessArtifactEnricher.java +++ b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/ProcessArtifactEnricher.java @@ -80,14 +80,15 @@ public class ProcessArtifactEnricher implements ExternalArtifactEnricherInterfac componentId, entity.getId());*/ processes.stream() - .filter(entity -> entity.getType().equals(ProcessType.Lifecycle_Operations)) .forEach(entity -> { ProcessEntity artifactEntity = new ProcessEntity(vspId, version, componentId, entity.getId()); ProcessEntity artifactProcessEntity = getProcessDao().get(artifactEntity); //ProcessArtifactEntity artifact = getProcessArtifactDao().get(artifactEntity); - if (artifactProcessEntity != null) { + if (artifactProcessEntity != null && ProcessType.Lifecycle_Operations.equals( + artifactProcessEntity.getType()) + && artifactProcessEntity.getArtifactName() != null ) { String componentName = componentEntity.getComponentCompositionData().getName(); String path = componentName + File.separator + ArtifactCategory.DEPLOYMENT.getDisplayName() + File.separator diff --git a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/tosca/AbstractSubstituteToscaEnricher.java b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/tosca/AbstractSubstituteToscaEnricher.java index d75c83f24c..93c4e67fc9 100644 --- a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/tosca/AbstractSubstituteToscaEnricher.java +++ b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/tosca/AbstractSubstituteToscaEnricher.java @@ -59,6 +59,7 @@ public class AbstractSubstituteToscaEnricher { final Map node_templates = serviceTemplate.getTopology_template().getNode_templates(); + if(node_templates == null) return errors; final Map> componentDisplayNameToNodeTempalteIds = populateAllNodeTemplateIdForComponent(node_templates, serviceTemplate, toscaModel); diff --git a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/test/java/org/openecomp/sdc/enrichment/impl/external/artifact/ProcessArtifactEnricherTest.java b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/test/java/org/openecomp/sdc/enrichment/impl/external/artifact/ProcessArtifactEnricherTest.java index cfb241483a..aeefc91aa3 100644 --- a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/test/java/org/openecomp/sdc/enrichment/impl/external/artifact/ProcessArtifactEnricherTest.java +++ b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/test/java/org/openecomp/sdc/enrichment/impl/external/artifact/ProcessArtifactEnricherTest.java @@ -28,6 +28,7 @@ import java.util.Collection; import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; public class ProcessArtifactEnricherTest { @@ -56,7 +57,6 @@ public class ProcessArtifactEnricherTest { version.setMinor(0); ComponentEntity componentEntity = getComponentEntity(vspId, version, componentId); - setMockToEnrichComponent(vspId, componentId, version); ProcessEntity entity = new ProcessEntity(vspId, version, componentId, null); ProcessEntity processEntity = new ProcessEntity(); @@ -64,6 +64,8 @@ public class ProcessArtifactEnricherTest { processEntity.setVspId(vspId); processEntity.setVersion(version); processEntity.setComponentId(componentId); + processEntity.setArtifactName("artifact_1kb.txt"); + processEntity.setArtifact(getMibByteBuffer("/mock/enrichProcess/artifact_1kb.txt")); Collection componentList = new ArrayList(); componentList.add(componentEntity); @@ -73,6 +75,8 @@ public class ProcessArtifactEnricherTest { list.add(processEntity); when(processDaoMock.list(entity)).thenReturn(list); + when(processDaoMock.get(anyObject())).thenReturn(processEntity); + EnrichmentInfo info = new EnrichmentInfo(); info.setVersion(version); info.setKey(vspId); @@ -92,19 +96,6 @@ public class ProcessArtifactEnricherTest { } - private void setMockToEnrichComponent(String vspId, String componentId, Version version) { - ProcessEntity returnedArtifact = new ProcessEntity(); - returnedArtifact.setVspId(vspId); - returnedArtifact.setVersion(version); - returnedArtifact.setComponentId(componentId); - returnedArtifact.setArtifactName("artifact_1kb.txt"); - returnedArtifact.setArtifact(getMibByteBuffer("/mock/enrichProcess/artifact_1kb.txt")); - - Mockito.when(processDaoMock.get(anyObject())) - .thenReturn(returnedArtifact); - Mockito.doNothing().when(enrichedServiceModelDaoMock).storeExternalArtifact(anyObject()); - } - private ComponentEntity getComponentEntity(String vspId, Version version, String componentId) { ComponentEntity componentEntity = new ComponentEntity(); componentEntity.setId(componentId); diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/datatypes/heattotosca/TranslationContext.java b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/datatypes/heattotosca/TranslationContext.java index 736318bcab..c036e39c21 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/datatypes/heattotosca/TranslationContext.java +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/datatypes/heattotosca/TranslationContext.java @@ -42,8 +42,11 @@ import org.openecomp.sdc.translator.services.heattotosca.NameExtractor; import org.openecomp.sdc.translator.services.heattotosca.globaltypes.GlobalTypesGenerator; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -58,6 +61,7 @@ public class TranslationContext { private static Map nameExtractorImplMap; private static Map supportedConsolidationComputeResources; private static Map supportedConsolidationPortResources; + private static List enrichPortResourceProperties; static { Configuration config = ConfigurationManager.lookup(); @@ -77,11 +81,19 @@ public class TranslationContext { supportedConsolidationPortResources = config.populateMap(ConfigConstants .MANDATORY_UNIFIED_MODEL_NAMESPACE, ConfigConstants .SUPPORTED_CONSOLIDATION_PORT_RESOURCES_KEY, ImplementationConfiguration.class); + enrichPortResourceProperties = config.getAsStringValues(ConfigConstants + .MANDATORY_UNIFIED_MODEL_NAMESPACE, ConfigConstants + .ENRICH_PORT_RESOURCE_PROP); } private Map unifiedSubstitutionData = new HashMap<>(); private ManifestFile manifest; + + public static List getEnrichPortResourceProperties() { + return enrichPortResourceProperties; + } + private FileContentHandler files = new FileContentHandler(); private Map manifestFiles = new HashMap<>(); //Key - file name, value - file type @@ -242,6 +254,19 @@ public class TranslationContext { return translatedIds; } + public Set getAllTranslatedResourceIdsFromDiffNestedFiles(String + nestedHeatFileNameToSkip){ + Set allTranslatedResourceIds = new HashSet<>(); + + this.translatedIds.entrySet().stream().filter( + heatFileNameToTranslatedIdsEntry -> !heatFileNameToTranslatedIdsEntry.getKey() + .equals(nestedHeatFileNameToSkip)).forEach(heatFileNameToTranslatedIdsEntry -> { + allTranslatedResourceIds.addAll(heatFileNameToTranslatedIdsEntry.getValue().keySet()); + }); + + return allTranslatedResourceIds; + } + // get tosca name from mapping configuration file //element type - parameter/attribute // element name - heat parameter/attribute name @@ -449,4 +474,6 @@ public class TranslationContext { return this.unifiedSubstitutionData.get(serviceTemplateName).getGlobalNodeTypeIndex (computeType); } + + } diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/ConfigConstants.java b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/ConfigConstants.java index f6918e382b..ca9f21b79a 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/ConfigConstants.java +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/ConfigConstants.java @@ -40,6 +40,9 @@ public class ConfigConstants { "supportedConsolidationComputeResources"; public static final String SUPPORTED_CONSOLIDATION_PORT_RESOURCES_KEY = "supportedConsolidationPortResources"; + public static final String ENRICH_PORT_RESOURCE_PROP = + "enrichPortResourceProperties"; + //others public static final String TRANS_MAPPING_DELIMITER_CHAR = "#"; diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/ConsolidationDataUtil.java b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/ConsolidationDataUtil.java index a89d08bcf6..148e754cfd 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/ConsolidationDataUtil.java +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/ConsolidationDataUtil.java @@ -2,6 +2,8 @@ package org.openecomp.sdc.translator.services.heattotosca; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.math.NumberUtils; +import org.openecomp.sdc.common.errors.CoreException; +import org.openecomp.sdc.common.errors.ErrorCode; import org.openecomp.sdc.datatypes.configuration.ImplementationConfiguration; import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate; import org.openecomp.sdc.heat.datatypes.model.HeatResourcesTypes; @@ -141,13 +143,21 @@ public class ConsolidationDataUtil { * * @param context the context * @param serviceTemplate the service template - * @param nestedNodeTemplateId the nested node template id - * @return the nested template consolidation data + * @param nestedHeatFileName + *@param nestedNodeTemplateId the nested node template id @return the nested template consolidation data */ public static NestedTemplateConsolidationData getNestedTemplateConsolidationData( TranslationContext context, ServiceTemplate serviceTemplate, - String nestedNodeTemplateId) { + String nestedHeatFileName, String nestedNodeTemplateId) { + + if(isNestedResourceIdOccuresInDifferentNestedFiles(context, nestedHeatFileName, + nestedNodeTemplateId)){ + throw new CoreException((new ErrorCode.ErrorCodeBuilder()) + .withMessage("Resource with id " + + nestedNodeTemplateId + " occures more than once in different addOn " + + "files").build()); + } ConsolidationData consolidationData = context.getConsolidationData(); String serviceTemplateFileName = ToscaUtil.getServiceTemplateFileName(serviceTemplate); @@ -176,6 +186,12 @@ public class ConsolidationDataUtil { return nestedTemplateConsolidationData; } + private static boolean isNestedResourceIdOccuresInDifferentNestedFiles(TranslationContext context, + String nestedHeatFileName, + String nestedNodeTemplateId) { + return context.getAllTranslatedResourceIdsFromDiffNestedFiles(nestedHeatFileName).contains(nestedNodeTemplateId); + } + /** * Update group id information in consolidation data. * @@ -372,7 +388,7 @@ public class ConsolidationDataUtil { } else if (consolidationEntityType == ConsolidationEntityType.NESTED || consolidationEntityType == ConsolidationEntityType.VFC_NESTED) { entityConsolidationData = getNestedTemplateConsolidationData(translationContext, - serviceTemplate, dependentNodeTemplateId); + serviceTemplate, translateTo.getHeatFileName(), dependentNodeTemplateId); } if (entityConsolidationData.getNodesConnectedIn() == null) { @@ -530,7 +546,8 @@ public class ConsolidationDataUtil { public static void updateNestedNodeTemplateId(TranslateTo translateTo) { TranslationContext context = translateTo.getContext(); ServiceTemplate serviceTemplate = translateTo.getServiceTemplate(); - getNestedTemplateConsolidationData(context, serviceTemplate, translateTo.getTranslatedId()); + getNestedTemplateConsolidationData( + context, serviceTemplate, translateTo.getHeatFileName(), translateTo.getTranslatedId()); } public static void removeSharedResource(ServiceTemplate serviceTemplate, diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/UnifiedCompositionService.java b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/UnifiedCompositionService.java index 471b1475d6..336d56a77f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/UnifiedCompositionService.java +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/UnifiedCompositionService.java @@ -46,6 +46,7 @@ import org.openecomp.sdc.tosca.datatypes.model.GroupDefinition; import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate; import org.openecomp.sdc.tosca.datatypes.model.NodeType; import org.openecomp.sdc.tosca.datatypes.model.ParameterDefinition; +import org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition; import org.openecomp.sdc.tosca.datatypes.model.PropertyType; import org.openecomp.sdc.tosca.datatypes.model.RelationshipTemplate; import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment; @@ -66,6 +67,7 @@ import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolida import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolidation.ConsolidationData; import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolidation.EntityConsolidationData; import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolidation.FileComputeConsolidationData; +import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolidation.FilePortConsolidationData; import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolidation.GetAttrFuncData; import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolidation.NestedTemplateConsolidationData; import org.openecomp.sdc.translator.datatypes.heattotosca.unifiedmodel.consolidation.PortTemplateConsolidationData; @@ -346,12 +348,13 @@ public class UnifiedCompositionService { List unifiedCompositionDataList, TranslationContext context) { handleUnifiedNestedNodeType(mainServiceTemplate, nestedServiceTemplate, context); - updateUnifiedNestedTemplates(mainServiceTemplate, nestedServiceTemplate, unifiedCompositionDataList, context); + updateUnifiedNestedTemplates(mainServiceTemplate, nestedServiceTemplate, + unifiedCompositionDataList, context); } private void handleGetAttrInConnectivity(ServiceTemplate serviceTemplate, - Set unifiedNodeIds, - TranslationContext context) { + Set unifiedNodeIds, + TranslationContext context) { Map nodeTemplates = serviceTemplate.getTopology_template().getNode_templates(); String serviceTemplateFileName = ToscaUtil.getServiceTemplateFileName(serviceTemplate); @@ -387,7 +390,7 @@ public class UnifiedCompositionService { context.getGlobalSubstitutionServiceTemplate(); newNestedNodeTypeId.ifPresent( - newNestedNodeTypeIdVal -> updateNestedNodeType(nodeTypeId, newNestedNodeTypeIdVal, + newNestedNodeTypeIdVal -> handleNestedNodeType(nodeTypeId, newNestedNodeTypeIdVal, nestedServiceTemplate, mainServiceTemplate, globalSubstitutionServiceTemplate, context)); @@ -403,26 +406,97 @@ public class UnifiedCompositionService { ToscaUtil.getServiceTemplateFileName(nestedServiceTemplate)); } + private void handleNestedNodeType(String nodeTypeId, String newNestedNodeTypeId, + ServiceTemplate nestedServiceTemplate, + ServiceTemplate mainServiceTemplate, + ServiceTemplate globalSubstitutionServiceTemplate, + TranslationContext context) { + updateNestedServiceTemplate(nestedServiceTemplate, context); + updateNestedNodeType(nodeTypeId, newNestedNodeTypeId, nestedServiceTemplate, + mainServiceTemplate, + globalSubstitutionServiceTemplate, context); + + + } + + private void updateNestedServiceTemplate(ServiceTemplate nestedServiceTemplate, + TranslationContext context) { + enrichPortProperties(nestedServiceTemplate, context); + } + + private void enrichPortProperties(ServiceTemplate nestedServiceTemplate, + TranslationContext context) { + String nestedServiceTemplateFileName = + ToscaUtil.getServiceTemplateFileName(nestedServiceTemplate); + FilePortConsolidationData filePortConsolidationData = + context.getConsolidationData().getPortConsolidationData().getFilePortConsolidationData + (nestedServiceTemplateFileName); + + if (Objects.nonNull(filePortConsolidationData)) { + Set portNodeTemplateIds = filePortConsolidationData.getAllPortNodeTemplateIds(); + if (Objects.nonNull(portNodeTemplateIds)) { + for (String portNodeTemplateId : portNodeTemplateIds) { + NodeTemplate portNodeTemplate = DataModelUtil.getNodeTemplate(nestedServiceTemplate, + portNodeTemplateId); + List portEntityConsolidationDataList = new ArrayList<>(); + portEntityConsolidationDataList.add(filePortConsolidationData + .getPortTemplateConsolidationData(portNodeTemplateId)); + + handleNodeTypeProperties(nestedServiceTemplate, + portEntityConsolidationDataList, portNodeTemplate, UnifiedCompositionEntity.Port, + null, context); + } + } + } + } + private void updateNestedNodeType(String nodeTypeId, String newNestedNodeTypeId, ServiceTemplate nestedServiceTemplate, ServiceTemplate mainServiceTemplate, ServiceTemplate globalSubstitutionServiceTemplate, TranslationContext context) { + String indexedNewNestedNodeTypeId = + updateNodeTypeId(nodeTypeId, newNestedNodeTypeId, nestedServiceTemplate, + mainServiceTemplate, + globalSubstitutionServiceTemplate, context); + + updateNodeTypeProperties(nestedServiceTemplate, globalSubstitutionServiceTemplate, + indexedNewNestedNodeTypeId); + } + + private void updateNodeTypeProperties(ServiceTemplate nestedServiceTemplate, + ServiceTemplate globalSubstitutionServiceTemplate, + String nodeTypeId) { + ToscaAnalyzerService toscaAnalyzerService = new ToscaAnalyzerServiceImpl(); + Map nodeTypePropertiesDefinition = + toscaAnalyzerService.manageSubstitutionNodeTypeProperties(nestedServiceTemplate); + NodeType nestedNodeType = + DataModelUtil.getNodeType(globalSubstitutionServiceTemplate, nodeTypeId); + nestedNodeType.setProperties(nodeTypePropertiesDefinition); + } + + private String updateNodeTypeId(String nodeTypeId, String newNestedNodeTypeId, + ServiceTemplate nestedServiceTemplate, + ServiceTemplate mainServiceTemplate, + ServiceTemplate globalSubstitutionServiceTemplate, + TranslationContext context) { context.addNestedFileToUsedNestedComputeType( - ToscaUtil.getServiceTemplateFileName(mainServiceTemplate), - ToscaUtil.getServiceTemplateFileName(nestedServiceTemplate), - newNestedNodeTypeId); - String indexedNodeType = + ToscaUtil.getServiceTemplateFileName(mainServiceTemplate), + ToscaUtil.getServiceTemplateFileName(nestedServiceTemplate), + newNestedNodeTypeId); + String indexedNewNestedNodeTypeId = handleNestedNodeTypeInGlobalSubstitutionTemplate(nodeTypeId, newNestedNodeTypeId, mainServiceTemplate, globalSubstitutionServiceTemplate, context); - handleSubstitutionMappingInNestedServiceTemplate(indexedNodeType, nestedServiceTemplate); + handleSubstitutionMappingInNestedServiceTemplate(indexedNewNestedNodeTypeId, + nestedServiceTemplate); context .updateHandledComputeType( ToscaUtil.getServiceTemplateFileName(mainServiceTemplate), ToscaUtil.getServiceTemplateFileName(nestedServiceTemplate), newNestedNodeTypeId); + return indexedNewNestedNodeTypeId; } private String handleNestedNodeTypeInGlobalSubstitutionTemplate(String nodeTypeId, @@ -458,7 +532,9 @@ public class UnifiedCompositionService { if (Objects.isNull(nestedTemplateConsolidationData)) { continue; } - handleNestedNodeTemplateInMainServiceTemplate(nestedTemplateConsolidationData.getNodeTemplateId(), mainServiceTemplate, nestedServiceTemplate, context); + handleNestedNodeTemplateInMainServiceTemplate( + nestedTemplateConsolidationData.getNodeTemplateId(), mainServiceTemplate, + nestedServiceTemplate, context); } } @@ -1566,9 +1642,29 @@ public class UnifiedCompositionService { ComputeTemplateConsolidationData computeTemplateConsolidationData, List unifiedCompositionDataList, TranslationContext context) { - List propertiesWithIdenticalVal = consolidationService.getPropertiesWithIdenticalVal(); + nodeTemplate.setProperties(new HashedMap()); + handleNodeTemplateProperties(serviceTemplate, nodeTemplate, substitutionServiceTemplate, + unifiedCompositionEntity, entityConsolidationDataList, computeTemplateConsolidationData, + unifiedCompositionDataList, context); + //Add enrich properties from openecomp node type as input to global and substitution ST + handleNodeTypeProperties(substitutionServiceTemplate, + entityConsolidationDataList, nodeTemplate, unifiedCompositionEntity, + computeTemplateConsolidationData, context); + + } + private void handleNodeTemplateProperties(ServiceTemplate serviceTemplate, + NodeTemplate nodeTemplate, + ServiceTemplate substitutionServiceTemplate, + UnifiedCompositionEntity unifiedCompositionEntity, + List + entityConsolidationDataList, + ComputeTemplateConsolidationData + computeTemplateConsolidationData, + List unifiedCompositionDataList, + TranslationContext context) { + List propertiesWithIdenticalVal = consolidationService.getPropertiesWithIdenticalVal(); for (EntityConsolidationData entityConsolidationData : entityConsolidationDataList) { String nodeTemplateId = entityConsolidationData.getNodeTemplateId(); Map properties = @@ -1588,7 +1684,6 @@ public class UnifiedCompositionService { unifiedCompositionEntity, computeTemplateConsolidationData, unifiedCompositionDataList, context); - //todo - define list of type which will match the node property type (instead of string) NodeType nodeTypeWithFlatHierarchy = HeatToToscaUtil.getNodeTypeWithFlatHierarchy(nodeTemplate.getType(), serviceTemplate, @@ -1596,30 +1691,82 @@ public class UnifiedCompositionService { String propertyType = nodeTypeWithFlatHierarchy.getProperties().get(propertyEntry.getKey()) .getType(); + addPropertyInputParameter(propertyType, substitutionServiceTemplate, parameterId); + } + } + } + } + + private void handleNodeTypeProperties(ServiceTemplate substitutionServiceTemplate, + List entityConsolidationDataList, + NodeTemplate nodeTemplate, + UnifiedCompositionEntity compositionEntity, + ComputeTemplateConsolidationData + computeTemplateConsolidationData, + TranslationContext context) { + ToscaAnalyzerService toscaAnalyzerService = new ToscaAnalyzerServiceImpl(); + Optional enrichNodeType = Optional.empty(); + List enrichProperties = new ArrayList<>(); + + if (compositionEntity.equals(UnifiedCompositionEntity.Port)) { + enrichNodeType = + toscaAnalyzerService.fetchNodeType(ToscaNodeType.NETWORK_PORT, + context.getGlobalServiceTemplates().values()); + enrichProperties = context.getEnrichPortResourceProperties(); + if (!enrichNodeType.isPresent() || Objects.isNull(enrichProperties)) { + return; + } + } else { + return; + } - if (propertyType.equalsIgnoreCase(PropertyType.STRING.getDisplayName()) - || propertyType.equalsIgnoreCase(PropertyType.INTEGER.getDisplayName()) - || propertyType.equalsIgnoreCase(PropertyType.FLOAT.getDisplayName()) - || propertyType.equalsIgnoreCase(PropertyType.BOOLEAN.getDisplayName())) { - parameterId - .ifPresent(parameterIdValue -> addInputParameter(parameterIdValue, - PropertyType.LIST.getDisplayName(), - DataModelUtil - .createEntrySchema(propertyType.toLowerCase(), null, null), - substitutionServiceTemplate)); - } else { - parameterId - .ifPresent(parameterIdValue -> addInputParameter(parameterIdValue, - PropertyType.LIST.getDisplayName(), - DataModelUtil - .createEntrySchema(PropertyTypeExt.JSON.getDisplayName(), null, null), - substitutionServiceTemplate)); + Map nodeTemplateProperties = nodeTemplate.getProperties(); + Map enrichNodeTypeProperties = enrichNodeType.get().getProperties(); + if (Objects.nonNull(enrichNodeTypeProperties)) { + for (String enrichPropertyName : enrichProperties) { + if (!nodeTemplateProperties.containsKey(enrichPropertyName)) { + for (EntityConsolidationData entityConsolidationData : entityConsolidationDataList) { + String nodeTemplateId = entityConsolidationData.getNodeTemplateId(); + String inputParamId = + getParameterId(nodeTemplateId, nodeTemplate, enrichPropertyName, + compositionEntity, computeTemplateConsolidationData); + Map> propertyVal = getPropertyValueInputParam(nodeTemplateId, + nodeTemplate, inputParamId); + nodeTemplate.getProperties().put(enrichPropertyName, propertyVal); + String propertyType = + enrichNodeType.get().getProperties().get(enrichPropertyName).getType(); + addPropertyInputParameter(propertyType, substitutionServiceTemplate, + Optional.of(inputParamId)); } } } } } + + private void addPropertyInputParameter(String propertyType, + ServiceTemplate substitutionServiceTemplate, + Optional parameterId) { + if (propertyType.equalsIgnoreCase(PropertyType.STRING.getDisplayName()) + || propertyType.equalsIgnoreCase(PropertyType.INTEGER.getDisplayName()) + || propertyType.equalsIgnoreCase(PropertyType.FLOAT.getDisplayName()) + || propertyType.equalsIgnoreCase(PropertyType.BOOLEAN.getDisplayName())) { + parameterId + .ifPresent(parameterIdValue -> addInputParameter(parameterIdValue, + PropertyType.LIST.getDisplayName(), + DataModelUtil + .createEntrySchema(propertyType.toLowerCase(), null, null), + substitutionServiceTemplate)); + } else { + parameterId + .ifPresent(parameterIdValue -> addInputParameter(parameterIdValue, + PropertyType.LIST.getDisplayName(), + DataModelUtil + .createEntrySchema(PropertyTypeExt.JSON.getDisplayName(), null, null), + substitutionServiceTemplate)); + } + } + private void handleConsolidationEntitiesRequirementConnectivity(String nodeTemplateId, NodeTemplate nodeTemplate, ServiceTemplate @@ -1716,17 +1863,24 @@ public class UnifiedCompositionService { unifiedCompositionDataList, context)) { return Optional.empty(); } - - Map> propertyVal = new HashMap<>(); - List getInputFuncParams = new ArrayList<>(); String inputParamId = getParameterId(nodeTemplateId, nodeTemplate, propertyEntry.getKey(), compositionEntity, computeTemplateConsolidationData); + Map> propertyVal = getPropertyValueInputParam(nodeTemplateId, + nodeTemplate, inputParamId); + nodeTemplate.getProperties().put(propertyEntry.getKey(), propertyVal); + return Optional.of(inputParamId); + } + + private Map> getPropertyValueInputParam(String nodeTemplateId, + NodeTemplate nodeTemplate, + String inputParamId) { + Map> propertyVal = new HashMap<>(); + List getInputFuncParams = new ArrayList<>(); getInputFuncParams.add(inputParamId); getInputFuncParams.add(ToscaConstants.INDEX_VALUE_PROPERTY_NAME); propertyVal.put(ToscaFunctions.GET_INPUT.getDisplayName(), getInputFuncParams); - nodeTemplate.getProperties().put(propertyEntry.getKey(), propertyVal); - return Optional.of(inputParamId); + return propertyVal; } private boolean handleGetAttrFromConsolidationNodes( @@ -1863,7 +2017,8 @@ public class UnifiedCompositionService { + getComputeTypeSuffix(nodeTemplate.getType()) + "_" + propertyId; case Port: String portType = ConsolidationDataUtil.getPortType(nodeTemplateId); - if (computeTemplateConsolidationData.getPorts().get(portType).size() > 1) { + if (Objects.isNull(computeTemplateConsolidationData) + || computeTemplateConsolidationData.getPorts().get(portType).size() > 1) { return UnifiedCompositionEntity.Port.name().toLowerCase() + "_" + nodeTemplateId + "_" + propertyId; } @@ -2015,7 +2170,13 @@ public class UnifiedCompositionService { default: break; } - abstractSubstituteProperties.put(substitutionTemplateInputName, abstractPropertyValue); + //Add the property only if it has at least one non-null value + for (Object val : abstractPropertyValue) { + if (Objects.nonNull(val)) { + abstractSubstituteProperties.put(substitutionTemplateInputName, abstractPropertyValue); + break; + } + } } return Optional.ofNullable(abstractSubstituteProperties); } @@ -2184,7 +2345,8 @@ public class UnifiedCompositionService { context.getHandledNestedComputeNodeTemplateIndex(mainServiceTemplateName, newNestedNodeTypeId); String newNodeTemplateId = - Constants.ABSTRACT_NODE_TEMPLATE_ID_PREFIX + getComputeTypeSuffix(newNestedNodeTypeId) + "_" + index; + Constants.ABSTRACT_NODE_TEMPLATE_ID_PREFIX + getComputeTypeSuffix(newNestedNodeTypeId) + + "_" + index; nestedNodeTemplate.setType(newNestedNodeTypeId); mainServiceTemplate.getTopology_template().getNode_templates().remove(nestedNodeTemplateId); @@ -2388,7 +2550,9 @@ public class UnifiedCompositionService { if (propertyName.isPresent()) { NodeTemplate portNodeTemplate = DataModelUtil.getNodeTemplate(serviceTemplate, portNodeTemplateId); - return getPropertyValueFromNodeTemplate(propertyName.get(), portNodeTemplate); + if (Objects.nonNull(portNodeTemplate)) { + return getPropertyValueFromNodeTemplate(propertyName.get(), portNodeTemplate); + } } return Optional.empty(); } diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/impl/functiontranslation/FunctionTranslationGetAttrImpl.java b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/impl/functiontranslation/FunctionTranslationGetAttrImpl.java index cc188d71a6..823daa53c8 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/impl/functiontranslation/FunctionTranslationGetAttrImpl.java +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/java/org/openecomp/sdc/translator/services/heattotosca/impl/functiontranslation/FunctionTranslationGetAttrImpl.java @@ -276,7 +276,7 @@ public class FunctionTranslationGetAttrImpl implements FunctionTranslation { .getPortTemplateConsolidationData(context, serviceTemplate, resourceId)); } else if (HeatToToscaUtil.isNestedResource(resource)) { return Optional.of(ConsolidationDataUtil - .getNestedTemplateConsolidationData(context, serviceTemplate, resourceId)); + .getNestedTemplateConsolidationData(context, serviceTemplate, heatFileName, resourceId)); } return Optional.empty(); } diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/resources/config-heatToToscaMapping.json b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/resources/config-heatToToscaMapping.json index 384847351e..d329b92b9f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/resources/config-heatToToscaMapping.json +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/resources/config-heatToToscaMapping.json @@ -74,7 +74,7 @@ }, "attributes": { "name": "name", - "virtual_machine_intefrace_mac_addresses": "virtual_machine_intefrace_mac_addresses", + "virtual_machine_interface_mac_addresses": "virtual_machine_interface_mac_addresses", "virtual_machine_interface_mac_addresses#virtual_machine_interface_mac_addresses_mac_address": "mac_address", "virtual_network_refs": "virtual_network_refs", "port_tuple_refs": "port_tuple_refs", diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/resources/config-mandatory-unifiedModel.json b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/resources/config-mandatory-unifiedModel.json index d4df0699f5..2b8f484705 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/resources/config-mandatory-unifiedModel.json +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/main/resources/config-mandatory-unifiedModel.json @@ -26,6 +26,17 @@ "enable": true } }, + "enrichPortResourceProperties": [ + "network_role_tag", + "mac_requirements", + "vlan_requirements", + "ip_requirements", + "network_role", + "order", + "exCP_naming", + "subnetpoolid" + ] + , "_config": { "namespace": "mandatoryUnifiedModel" } diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/java/org/openecomp/sdc/translator/services/heattotosca/impl/fulltest/UnifiedCompositionNestedSingleComputeFullTest.java b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/java/org/openecomp/sdc/translator/services/heattotosca/impl/fulltest/UnifiedCompositionNestedSingleComputeFullTest.java index 0001ec8d54..9f3232eaca 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/java/org/openecomp/sdc/translator/services/heattotosca/impl/fulltest/UnifiedCompositionNestedSingleComputeFullTest.java +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/java/org/openecomp/sdc/translator/services/heattotosca/impl/fulltest/UnifiedCompositionNestedSingleComputeFullTest.java @@ -24,8 +24,19 @@ public class UnifiedCompositionNestedSingleComputeFullTest extends BaseFullTrans testTranslationWithInit(); } + @Test + public void testNestedWithOneComputeSamePortType() throws IOException { + inputFilesPath = + "/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in"; + outputFilesPath = + "/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out"; + + testTranslationWithInit(); + } + @Test public void testOneNestedWithTwoComputesOfSameType() throws IOException { + //Not pattern 4 (Complex VFC) inputFilesPath = "/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoComputesOfSameType/in"; outputFilesPath = @@ -36,6 +47,7 @@ public class UnifiedCompositionNestedSingleComputeFullTest extends BaseFullTrans @Test public void testOneNestedWithTwoDiffComputeTypes() throws IOException { + //Not pattern 4 (Complex VFC) inputFilesPath = "/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/in"; outputFilesPath = @@ -124,6 +136,7 @@ public class UnifiedCompositionNestedSingleComputeFullTest extends BaseFullTrans @Test public void testMultiLevelNestedComposition() throws IOException { + //Not pattern 4 (Multi level Complex VFC) inputFilesPath = "/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedMultiLevels/in"; outputFilesPath = diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw2_service_instance1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw2_service_instance1ServiceTemplate.yaml index c47881c827..19e88a77fb 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw2_service_instance1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw2_service_instance1ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance1: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw2_service_instance3ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw2_service_instance3ServiceTemplate.yaml index b3fd08ad7f..0f74dfe252 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw2_service_instance3ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw2_service_instance3ServiceTemplate.yaml @@ -250,32 +250,22 @@ topology_template: service_instance3: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list groups: service_instance3_group: type: org.openecomp.groups.heat.HeatStack diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw3_service_instance4ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw3_service_instance4ServiceTemplate.yaml index 031d40e78f..bb8a6c0324 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw3_service_instance4ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw3_service_instance4ServiceTemplate.yaml @@ -250,32 +250,22 @@ topology_template: service_instance4: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list groups: service_instance4_group: type: org.openecomp.groups.heat.HeatStack diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw_service_instance1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw_service_instance1ServiceTemplate.yaml index a80565137c..72b97b69a9 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw_service_instance1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw_service_instance1ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance1: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw_service_instance2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw_service_instance2ServiceTemplate.yaml index 1ba7cd1567..1798f33fde 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw_service_instance2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkMultiNested/expectedoutputfiles/OCS-fw_service_instance2ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance2: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/MainServiceTemplate.yaml index 3fc99fd2e7..f4dda7cefd 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/MainServiceTemplate.yaml @@ -51,7 +51,77 @@ topology_template: get_input: Internal1_forwarding_mode network_name: get_input: Internal1_net_name - test_nested: + test_nested0: + type: org.openecomp.resource.abstract.nodes.heat.OCS-fw + directives: + - substitutable + properties: + network_param2: Internal2-net + service_template_filter: + substitute_service_template: OCS-fwServiceTemplate.yaml + network_param1: Internal1-net + requirements: + - link_port_0_service_instance2: + capability: tosca.capabilities.network.Linkable + node: Internal2-net + relationship: tosca.relationships.network.LinksTo + - link_port_1_service_instance2: + capability: tosca.capabilities.network.Linkable + node: Internal1-net + relationship: tosca.relationships.network.LinksTo + - link_port_2_service_instance2: + capability: tosca.capabilities.network.Linkable + node: Internal2-net + relationship: tosca.relationships.network.LinksTo + - link_port_0_service_instance1: + capability: tosca.capabilities.network.Linkable + node: Internal1-net + relationship: tosca.relationships.network.LinksTo + - link_port_1_service_instance1: + capability: tosca.capabilities.network.Linkable + node: Internal1-net + relationship: tosca.relationships.network.LinksTo + - link_port_2_service_instance1: + capability: tosca.capabilities.network.Linkable + node: Internal2-net + relationship: tosca.relationships.network.LinksTo + - link_port_0_service_instance1_test_nested2: + capability: tosca.capabilities.network.Linkable + node: Internal2-net + relationship: tosca.relationships.network.LinksTo + - link_port_1_service_instance1_test_nested2: + capability: tosca.capabilities.network.Linkable + node: Internal1-net + relationship: tosca.relationships.network.LinksTo + - link_port_2_service_instance1_test_nested2: + capability: tosca.capabilities.network.Linkable + node: Internal2-net + relationship: tosca.relationships.network.LinksTo + - link_port_0_service_instance4_test_nested3_test_nested2: + capability: tosca.capabilities.network.Linkable + node: Internal1-net + relationship: tosca.relationships.network.LinksTo + - link_port_1_service_instance4_test_nested3_test_nested2: + capability: tosca.capabilities.network.Linkable + node: Internal1-net + relationship: tosca.relationships.network.LinksTo + - link_port_2_service_instance4_test_nested3_test_nested2: + capability: tosca.capabilities.network.Linkable + node: Internal1-net + relationship: tosca.relationships.network.LinksTo + - link_port_0_service_instance3_test_nested2: + capability: tosca.capabilities.network.Linkable + node: Internal1-net + relationship: tosca.relationships.network.LinksTo + - link_port_1_service_instance3_test_nested2: + capability: tosca.capabilities.network.Linkable + node: Internal1-net + relationship: tosca.relationships.network.LinksTo + - link_port_2_service_instance3_test_nested2: + capability: tosca.capabilities.network.Linkable + node: Internal2-net + relationship: tosca.relationships.network.LinksTo + test_nested1: type: org.openecomp.resource.abstract.nodes.heat.OCS-fw directives: - substitutable @@ -130,7 +200,7 @@ topology_template: members: - Internal2-net - Internal1-net - - test_nested + - test_nested0 addOn_group: type: org.openecomp.groups.heat.HeatStack properties: @@ -139,4 +209,4 @@ topology_template: members: - Internal2-net - Internal1-net - - test_nested \ No newline at end of file + - test_nested1 \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw2_service_instance1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw2_service_instance1ServiceTemplate.yaml index c47881c827..19e88a77fb 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw2_service_instance1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw2_service_instance1ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance1: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw2_service_instance3ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw2_service_instance3ServiceTemplate.yaml index b3fd08ad7f..0f74dfe252 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw2_service_instance3ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw2_service_instance3ServiceTemplate.yaml @@ -250,32 +250,22 @@ topology_template: service_instance3: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list groups: service_instance3_group: type: org.openecomp.groups.heat.HeatStack diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw3_service_instance4ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw3_service_instance4ServiceTemplate.yaml index 031d40e78f..bb8a6c0324 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw3_service_instance4ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw3_service_instance4ServiceTemplate.yaml @@ -250,32 +250,22 @@ topology_template: service_instance4: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list groups: service_instance4_group: type: org.openecomp.groups.heat.HeatStack diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw_service_instance1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw_service_instance1ServiceTemplate.yaml index a80565137c..72b97b69a9 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw_service_instance1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw_service_instance1ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance1: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw_service_instance2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw_service_instance2ServiceTemplate.yaml index 1ba7cd1567..1798f33fde 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw_service_instance2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/expectedoutputfiles/OCS-fw_service_instance2ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance2: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/inputfiles/addOn.yml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/inputfiles/addOn.yml index 2785688607..7747ff6719 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/inputfiles/addOn.yml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/inputfiles/addOn.yml @@ -30,7 +30,7 @@ resources: forwarding_mode: { get_param: Internal1_forwarding_mode } shared: { get_param: Internal1_shared } - test_nested: + test_nested1: type: OCS-fw.yml properties: network_param1: { get_resource: Internal1-net} diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/inputfiles/base.yml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/inputfiles/base.yml index 2785688607..235cf5e4cf 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/inputfiles/base.yml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/connectToNetworkSharedMultiNested/inputfiles/base.yml @@ -30,7 +30,7 @@ resources: forwarding_mode: { get_param: Internal1_forwarding_mode } shared: { get_param: Internal1_shared } - test_nested: + test_nested0: type: OCS-fw.yml properties: network_param1: { get_resource: Internal1-net} diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/diffServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/diffServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_1ServiceTemplate.yaml index 69d73f9034..9c7de5309f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/diffServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/diffServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_1ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance_1: type: org.openecomp.resource.vfc.nodes.heat.compute_service_template_1 properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/diffServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/diffServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_2ServiceTemplate.yaml index 1a0f590d58..6ccd3c4a0e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/diffServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/diffServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_2ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance_2: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/oneServiceInstance/expectedoutputfiles/lcp1_mss.oam-fw_si_service_instanceServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/oneServiceInstance/expectedoutputfiles/lcp1_mss.oam-fw_si_service_instanceServiceTemplate.yaml index 53cb41cc75..c7685c951b 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/oneServiceInstance/expectedoutputfiles/lcp1_mss.oam-fw_si_service_instanceServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/oneServiceInstance/expectedoutputfiles/lcp1_mss.oam-fw_si_service_instanceServiceTemplate.yaml @@ -294,32 +294,22 @@ topology_template: service_instance: type: org.openecomp.resource.vfc.nodes.heat.st properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list groups: service_instance_group: type: org.openecomp.groups.heat.HeatStack diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sameServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sameServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_1ServiceTemplate.yaml index de34c8fba8..413aa7b724 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sameServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sameServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_1ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance_1: type: org.openecomp.resource.vfc.nodes.heat.compute_service_template properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sameServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sameServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_2ServiceTemplate.yaml index 818e411705..a20cb55608 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sameServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sameServiceTemplate/expectedoutputfiles/OCS-fw_service_instance_2ServiceTemplate.yaml @@ -130,32 +130,22 @@ topology_template: service_instance_2: type: org.openecomp.resource.vfc.nodes.heat.compute_service_template properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list port_0: type: org.openecomp.resource.cp.nodes.heat.network.contrail.Port properties: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sharedNetworkMulti/expectedoutputfiles/OCS-fw_service_instanceServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sharedNetworkMulti/expectedoutputfiles/OCS-fw_service_instanceServiceTemplate.yaml index 1980b18393..e99b179375 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sharedNetworkMulti/expectedoutputfiles/OCS-fw_service_instanceServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/contrail2serviceinstance/sharedNetworkMulti/expectedoutputfiles/OCS-fw_service_instanceServiceTemplate.yaml @@ -330,32 +330,22 @@ topology_template: service_instance: type: org.openecomp.resource.vfc.nodes.heat.compute_service_template properties: - availability_zone: - get_input: availability_zone - static_routes_list: - get_input: static_routes_list - availability_zone_enable: - get_input: availability_zone_enable - service_template_name: - get_input: service_template_name - ordered_interfaces: - get_input: ordered_interfaces flavor: get_input: flavor image_name: get_input: image_name + availability_zone: + get_input: availability_zone service_type: get_input: service_type - service_interface_type_list: - get_input: service_interface_type_list + availability_zone_enable: + get_input: availability_zone_enable + service_template_name: + get_input: service_template_name service_instance_name: get_input: service_instance_name - interface_list: - get_input: interface_list service_mode: get_input: service_mode - shared_ip_list: - get_input: shared_ip_list groups: service_instance_group: type: org.openecomp.groups.heat.HeatStack diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/GlobalSubstitutionTypesServiceTemplate.yaml index 549e488839..3f0bbea5ee 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,30 +60,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -399,6 +435,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -421,30 +487,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -790,6 +862,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -812,30 +914,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list required: true status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/MainServiceTemplate.yaml index 700ca62ca3..b3be41a76f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/MainServiceTemplate.yaml @@ -77,6 +77,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 2 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -90,14 +98,6 @@ topology_template: is_required: false port_pd01_port_network: - packet_internal_network - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 2 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW service_template_filter: @@ -118,6 +118,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -131,14 +139,6 @@ topology_template: is_required: false port_pd01_port_network: - packet_internal_network - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 0 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW service_template_filter: @@ -159,6 +159,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -172,14 +180,6 @@ topology_template: is_required: false port_pd01_port_network: - packet_internal_network - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW service_template_filter: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_0ServiceTemplate.yaml index 5ef1764a63..6a96d70747 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_0ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,26 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -77,14 +107,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_1ServiceTemplate.yaml index a0da89fcd1..1efd8dcca0 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_1ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,26 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -77,14 +107,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_2ServiceTemplate.yaml index 8e6fc1636e..08e5895c0e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeDiffImageName/out/Nested_pd_server_2ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,26 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -77,14 +107,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/GlobalSubstitutionTypesServiceTemplate.yaml index 89cc273c46..b85ce67d05 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +60,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -411,6 +441,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -433,36 +493,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -808,6 +868,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -830,36 +920,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/MainServiceTemplate.yaml index e320ad820d..89aa2d4fbf 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/MainServiceTemplate.yaml @@ -171,6 +171,18 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_attribute: + - abstract_pd_server_0 + - pd_server_show + compute_pd_server_name: + - get_input: + - pd_server_names + - 2 + vm_flavor_name: + get_attribute: + - network_policy_server + - name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -184,18 +196,6 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - compute_pd_server_availability_zone: - - get_attribute: - - abstract_pd_server_0 - - pd_server_show - compute_pd_server_name: - - get_input: - - pd_server_names - - 2 - vm_flavor_name: - get_attribute: - - network_policy_server - - name port_pd01_port_network_role_tag: - oam compute_pd_server_user_data_format: @@ -218,6 +218,16 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 0 + vm_flavor_name: + get_attribute: + - network_policy_server + - name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -231,16 +241,6 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 0 - vm_flavor_name: - get_attribute: - - network_policy_server - - name port_pd01_port_network_role_tag: - oam compute_pd_server_user_data_format: @@ -258,6 +258,16 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + vm_flavor_name: + get_attribute: + - network_policy_server + - name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -271,16 +281,6 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - vm_flavor_name: - get_attribute: - - network_policy_server - - name port_pd01_port_network_role_tag: - oam compute_pd_server_user_data_format: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_0ServiceTemplate.yaml index afa6a85603..3d11cad564 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_0ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,6 +107,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_1ServiceTemplate.yaml index 5b0eb7e992..1efd8dcca0 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_1ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,6 +107,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_2ServiceTemplate.yaml index 1b487934d1..08e5895c0e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypeGetAttrBetweenThem/out/Nested_pd_server_2ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,6 +107,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/GlobalSubstitutionTypesServiceTemplate.yaml index 549e488839..3f0bbea5ee 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,30 +60,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -399,6 +435,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -421,30 +487,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -790,6 +862,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -812,30 +914,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list required: true status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/MainServiceTemplate.yaml index db618f7af0..4187b3bb39 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/MainServiceTemplate.yaml @@ -76,6 +76,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 2 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -89,14 +97,6 @@ topology_template: is_required: false port_pd01_port_network: - packet_external_network - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 2 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW service_template_filter: @@ -122,6 +122,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -135,14 +143,6 @@ topology_template: is_required: false port_pd01_port_network: - packet_internal_network - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 0 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW service_template_filter: @@ -163,6 +163,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -176,14 +184,6 @@ topology_template: is_required: false port_pd01_port_network: - packet_internal_network - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW service_template_filter: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_0ServiceTemplate.yaml index 5ef1764a63..6a96d70747 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_0ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,26 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -77,14 +107,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_1ServiceTemplate.yaml index a0da89fcd1..1efd8dcca0 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_1ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,26 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -77,14 +107,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_2ServiceTemplate.yaml index 8e6fc1636e..08e5895c0e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/catalogInstances/threeComputesSameTypePortsConnectedToDiffNetworks/out/Nested_pd_server_2ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,26 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -77,14 +107,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/GlobalSubstitutionTypesServiceTemplate.yaml index da7b5979f9..a921a8e328 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -926,29 +926,92 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - server_group: - type: string - required: true - status: SUPPORTED - connectivityChk: - type: json + port_pcm_port_0_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name required: true status: SUPPORTED - oam_net_gw: - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + pcm_server_name: + type: string + description: PCRF CM server name + required: true + status: SUPPORTED + cps_net_mask: + type: string + description: CPS network mask + required: true + status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + oam_net_name: + type: string + description: OAM network name + required: true + status: SUPPORTED + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + server_group: + type: string + required: true + status: SUPPORTED + connectivityChk: + type: json + required: true + status: SUPPORTED + oam_net_gw: + type: string + description: CPS network gateway + required: true + status: SUPPORTED security_group_name: type: string description: the name of security group @@ -959,6 +1022,12 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance @@ -969,21 +1038,11 @@ node_types: description: CPS Cluman Cinder Volume required: true status: SUPPORTED - pcm_server_name: - type: string - description: PCRF CM server name - required: true - status: SUPPORTED cps_net_name: type: string description: CPS network name required: true status: SUPPORTED - cps_net_mask: - type: string - description: CPS network mask - required: true - status: SUPPORTED oam_net_ip: type: string description: OAM network ip @@ -994,11 +1053,12 @@ node_types: description: CPS network mask required: true status: SUPPORTED - oam_net_name: - type: string - description: OAM network name + port_pcm_port_1_order: + type: list required: true status: SUPPORTED + entry_schema: + type: integer attributes: server_pcm_id: type: string @@ -1421,7 +1481,13 @@ node_types: org.openecomp.resource.abstract.nodes.1c1_scalling_instance: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_1c1_t1_port_fixed_ips: + port_1c1_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -1433,24 +1499,80 @@ node_types: status: SUPPORTED entry_schema: type: string - port_1c1_t2_port_ip_requirements: + port_1c1_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c1_t1_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_1c1_t1_port_mac_requirements: + vm_image_name: + type: string + required: true + status: SUPPORTED + compute_1c1_scalling_instance_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t1_port_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t1_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t2_port_fixed_ips: type: list required: true status: SUPPORTED entry_schema: type: json - port_1c1_t2_port_network_role_tag: + port_1c1_t2_port_network: type: list required: true status: SUPPORTED entry_schema: type: string + port_1c1_t1_port_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t1_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -1459,80 +1581,84 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_1c1_t2_port_mac_requirements: + port_1c1_t2_port_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_flavor_name: - type: string + type: string + port_1c1_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c1_t2_port_mac_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_1c1_scalling_instance_availability_zone: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t2_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string port_1c1_t2_port_name: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string - required: true - status: SUPPORTED compute_1c1_scalling_instance_scheduler_hints: type: list required: true status: SUPPORTED entry_schema: type: json - compute_1c1_scalling_instance_metadata: + port_1c1_t2_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: type: json - compute_1c1_scalling_instance_name: + compute_1c1_scalling_instance_metadata: type: list required: true status: SUPPORTED entry_schema: - type: string - port_1c1_t1_port_name: + type: json + port_1c1_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_network: + port_1c1_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t2_port_fixed_ips: + port_1c1_t1_port_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1c1_t2_port_network: + type: string + port_1c1_t1_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string + type: integer attributes: 1c1_scalling_instance_1c1_t1_port_tenant_id: type: list @@ -1972,6 +2098,74 @@ node_types: status: SUPPORTED entry_schema: type: json + port_1a_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1a_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t2_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t1_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1a_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_a_single_1a_availability_zone: type: list required: true @@ -1992,50 +2186,48 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_1a_t1_port_ip_requirements: + port_1a_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1a_t2_port_network_role_tag: + type: string + port_1a_t1_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_1a_t1_port_order: + type: list required: true status: SUPPORTED - port_1a_t2_port_network: + entry_schema: + type: integer + port_1a_t2_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - port_1a_t1_port_mac_requirements: + type: json + port_1a_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_1a_t1_port_network: + port_1a_t2_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1a_t2_port_ip_requirements: + port_1a_t2_port_order: type: list required: true status: SUPPORTED entry_schema: - type: json + type: integer compute_a_single_1a_user_data_format: type: list required: true @@ -2482,6 +2674,74 @@ node_types: org.openecomp.resource.abstract.nodes.b_single_1b_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -2508,16 +2768,18 @@ node_types: status: SUPPORTED entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_flavor_name: - type: string + port_1b_t2_port_ip_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_1b_t1_port_value_specs: type: list required: true @@ -2530,16 +2792,12 @@ node_types: status: SUPPORTED entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -2552,12 +2810,12 @@ node_types: status: SUPPORTED entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true @@ -2998,12 +3256,86 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c2_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -3018,12 +3350,6 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: - type: list - required: true - status: SUPPORTED - entry_schema: - type: string compute_1c2_catalog_instance_metadata: type: list required: true @@ -3036,10 +3362,12 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_1c2_t1_port_exCP_naming: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_network: type: list required: true @@ -3052,11 +3380,7 @@ node_types: status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -3514,12 +3838,86 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c2_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -3534,22 +3932,18 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED + type: json port_1c2_t1_port_network: type: list required: true @@ -3562,11 +3956,7 @@ node_types: status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -4024,6 +4414,74 @@ node_types: org.openecomp.resource.abstract.nodes.b_single_1b_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -4050,32 +4508,36 @@ node_types: status: SUPPORTED entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_flavor_name: - type: string - required: true - status: SUPPORTED - port_1b_t1_port_ip_requirements: + port_1b_t2_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string + port_1b_t1_port_network_role_tag: + type: list required: true status: SUPPORTED + entry_schema: + type: string compute_b_single_1b_metadata: type: list required: true status: SUPPORTED entry_schema: type: json + port_1b_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -4088,12 +4550,12 @@ node_types: status: SUPPORTED entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json compute_b_single_1b_name: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/MainServiceTemplate.yaml index 7a12426fa6..700c94ba91 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/MainServiceTemplate.yaml @@ -143,6 +143,52 @@ topology_template: directives: - substitutable properties: + compute_1c1_scalling_instance_user_data_format: + - RAW2 + - RAW1 + port_1c1_t2_port_network_role_tag: + - ppds + - ppds + vm_flavor_name: + get_input: pd_flavor_name + port_1c1_t1_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false + - - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name + compute_1c1_scalling_instance_name: + - get_input: + - 1c1_scalling_instance_names + - 2 + - get_input: + - 1c1_scalling_instance_names + - 1 + port_1c1_t1_port_name: + - 1c1_t1_port_1 + - 1c1_t1_port_0 + port_1c1_t1_port_network: + - 1c1_scalling_instance_network + - 1c1_scalling_instance_network + port_1c1_t2_port_fixed_ips: + - - ip_address: + get_input: + - myIPs + - 4 + - - ip_address: + get_input: + - myIPs + - 2 + port_1c1_t2_port_network: + - get_input: ppds_net_name + - get_input: ppds_net_name port_1c1_t1_port_fixed_ips: - - ip_address: get_input: @@ -152,9 +198,6 @@ topology_template: get_input: - myIPs - 1 - compute_1c1_scalling_instance_user_data_format: - - RAW2 - - RAW1 port_1c1_t2_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -171,35 +214,17 @@ topology_template: is_required: false - mac_count_required: is_required: false - port_1c1_t2_port_network_role_tag: - - ppds - - ppds port_1c1_t2_port_mac_requirements: - mac_count_required: is_required: false - mac_count_required: is_required: false - vm_flavor_name: - get_input: pd_flavor_name compute_1c1_scalling_instance_availability_zone: - get_input: availabilityzone_name - get_input: availabilityzone_name - port_1c1_t1_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: true - floating_ip_count_required: - is_required: false - - - ip_version: 4 - ip_count_required: - is_required: true - floating_ip_count_required: - is_required: false port_1c1_t2_port_name: - 1c1_t2_port_1 - 1c1_t2_port_0 - vm_image_name: - get_input: pd_image_name compute_1c1_scalling_instance_scheduler_hints: - group: BE_Affinity_group - group: BE_Affinity_group @@ -233,31 +258,6 @@ topology_template: get_attribute: - abstract_b_single_1b_0 - b_single_1b_instance_name - compute_1c1_scalling_instance_name: - - get_input: - - 1c1_scalling_instance_names - - 2 - - get_input: - - 1c1_scalling_instance_names - - 1 - port_1c1_t1_port_name: - - 1c1_t1_port_1 - - 1c1_t1_port_0 - port_1c1_t1_port_network: - - 1c1_scalling_instance_network - - 1c1_scalling_instance_network - port_1c1_t2_port_fixed_ips: - - - ip_address: - get_input: - - myIPs - - 4 - - - ip_address: - get_input: - - myIPs - - 2 - port_1c1_t2_port_network: - - get_input: ppds_net_name - - get_input: ppds_net_name service_template_filter: substitute_service_template: Nested_1c1_scalling_instanceServiceTemplate.yaml count: 2 @@ -276,6 +276,18 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_input: pd_flavor_name + port_1b_t1_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name + compute_b_single_1b_user_data_format: + - RAW port_1b_t2_port_mac_requirements: - mac_count_required: is_required: false @@ -289,16 +301,6 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - vm_flavor_name: - get_input: pd_flavor_name - port_1b_t1_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - vm_image_name: - get_input: pd_image_name compute_b_single_1b_metadata: - connectivityTo4PNested: get_attribute: @@ -329,8 +331,6 @@ topology_template: is_required: false port_1b_t2_port_network: - b_single_1b_network - compute_b_single_1b_user_data_format: - - RAW compute_b_single_1b_name: - get_input: - b_single_1b_names @@ -358,13 +358,23 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_metadata: - connectivityTo4PNested: get_attribute: @@ -398,21 +408,11 @@ topology_template: - get_input: - 1c2_catalog_instance_names - 1 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - RAW1 port_1c2_t1_port_network_role_tag: @@ -443,32 +443,32 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_name: - get_input: - 1c2_catalog_instance_names - 2 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - get_attribute: - abstract_1c2_catalog_instance_0 @@ -661,10 +661,6 @@ topology_template: get_attribute: - abstract_1c1_scalling_instance - 1c1_scalling_instance_1c1_t2_port_tenant_id - compute_a_single_1a_availability_zone: - - get_input: availabilityzone_name - compute_a_single_1a_scheduler_hints: - - group: BE_Affinity_group port_1a_t1_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -690,6 +686,10 @@ topology_template: is_required: false floating_ip_count_required: is_required: false + compute_a_single_1a_availability_zone: + - get_input: availabilityzone_name + compute_a_single_1a_scheduler_hints: + - group: BE_Affinity_group compute_a_single_1a_user_data_format: - RAW compute_a_single_1a_name: @@ -877,6 +877,18 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_input: pd_flavor_name + port_1b_t1_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name + compute_b_single_1b_user_data_format: + - RAW port_1b_t2_port_mac_requirements: - mac_count_required: is_required: false @@ -890,29 +902,17 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - vm_flavor_name: - get_input: pd_flavor_name port_1b_t1_port_value_specs: - get_attribute: - abstract_a_single_1a - a_single_1a_1a_t1_port_tenant_id port_1b_t1_port_network_role_tag: - oam - port_1b_t1_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - vm_image_name: - get_input: pd_image_name port_1b_t1_port_mac_requirements: - mac_count_required: is_required: false port_1b_t2_port_network: - b_single_1b_network - compute_b_single_1b_user_data_format: - - RAW port_1b_t1_port_network: - get_input: oam_net_name compute_b_single_1b_name: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c1_scalling_instanceServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c1_scalling_instanceServiceTemplate.yaml index aa6bcaf443..f6b0a50917 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c1_scalling_instanceServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c1_scalling_instanceServiceTemplate.yaml @@ -11,7 +11,12 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_1c1_t1_port_fixed_ips: + port_1c1_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c1_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -21,21 +26,67 @@ topology_template: required: true entry_schema: type: string - port_1c1_t2_port_ip_requirements: + port_1c1_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c1_t1_port_ip_requirements: type: list required: true entry_schema: type: json - port_1c1_t1_port_mac_requirements: + vm_image_name: + type: string + required: true + compute_1c1_scalling_instance_name: + type: list + required: true + entry_schema: + type: string + port_1c1_t1_port_name: + type: list + required: true + entry_schema: + type: string + port_1c1_t1_port_network: + type: list + required: true + entry_schema: + type: string + port_1c1_t2_port_fixed_ips: type: list required: true entry_schema: type: json - port_1c1_t2_port_network_role_tag: + port_1c1_t2_port_network: type: list required: true entry_schema: type: string + port_1c1_t1_port_fixed_ips: + type: list + required: true + entry_schema: + type: json + port_1c1_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_1c1_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1c1_t1_port_mac_requirements: + type: list + required: true + entry_schema: + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -43,79 +94,107 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_1c1_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1c1_t2_port_order: + type: list + required: true + entry_schema: + type: integer port_1c1_t2_port_mac_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string - required: true compute_1c1_scalling_instance_availability_zone: type: list required: true entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t2_port_subnetpoolid: type: list required: true entry_schema: - type: json + type: string port_1c1_t2_port_name: type: list required: true entry_schema: type: string - vm_image_name: - type: string - required: true compute_1c1_scalling_instance_scheduler_hints: type: list required: true entry_schema: type: json - compute_1c1_scalling_instance_metadata: + port_1c1_t2_port_exCP_naming: type: list required: true entry_schema: type: json - compute_1c1_scalling_instance_name: + compute_1c1_scalling_instance_metadata: type: list required: true entry_schema: - type: string - port_1c1_t1_port_name: + type: json + port_1c1_t1_port_subnetpoolid: type: list required: true entry_schema: type: string - port_1c1_t1_port_network: + port_1c1_t1_port_network_role_tag: type: list required: true entry_schema: type: string - port_1c1_t2_port_fixed_ips: + port_1c1_t1_port_network_role: type: list required: true entry_schema: - type: json - port_1c1_t2_port_network: + type: string + port_1c1_t1_port_order: type: list required: true entry_schema: - type: string + type: integer node_templates: 1c1_scalling_instance_1c1_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c1_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c1_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c1_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c1_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c1_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c1_t1_port_order + - index_value + network_role: + get_input: + - port_1c1_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c1_t1_port_subnetpoolid + - index_value fixed_ips: get_input: - port_1c1_t1_port_fixed_ips @@ -163,6 +242,14 @@ topology_template: 1c1_scalling_instance_1c1_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c1_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c1_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c1_t2_port_ip_requirements @@ -175,6 +262,18 @@ topology_template: get_input: - port_1c1_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c1_t2_port_order + - index_value + network_role: + get_input: + - port_1c1_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c1_t2_port_subnetpoolid + - index_value fixed_ips: get_input: - port_1c1_t2_port_fixed_ips diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml index 67305b71ce..7a439484d6 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,11 +89,6 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: - type: list - required: true - entry_schema: - type: string compute_1c2_catalog_instance_metadata: type: list required: true @@ -43,9 +99,11 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string + port_1c2_t1_port_exCP_naming: + type: list required: true + entry_schema: + type: json port_1c2_t1_port_network: type: list required: true @@ -56,10 +114,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -115,14 +170,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -135,6 +214,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -147,6 +234,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml index 213939c88e..ab88e26fa7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,19 +89,16 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true + type: json port_1c2_t1_port_network: type: list required: true @@ -51,10 +109,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -106,14 +161,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -126,6 +205,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_a_single_1aServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_a_single_1aServiceTemplate.yaml index 409bf1d35f..c0ea9ef793 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_a_single_1aServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_a_single_1aServiceTemplate.yaml @@ -16,6 +16,62 @@ topology_template: required: true entry_schema: type: json + port_1a_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1a_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1a_t2_port_network: + type: list + required: true + entry_schema: + type: string + port_1a_t1_port_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_network: + type: list + required: true + entry_schema: + type: string + port_1a_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + vm_image_name: + type: string + required: true + port_1a_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json compute_a_single_1a_availability_zone: type: list required: true @@ -33,42 +89,41 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_1a_t1_port_ip_requirements: + port_1a_t1_port_network_role_tag: type: list required: true entry_schema: - type: json - port_1a_t2_port_network_role_tag: + type: string + port_1a_t1_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_1a_t1_port_order: + type: list required: true - port_1a_t2_port_network: + entry_schema: + type: integer + port_1a_t2_port_exCP_naming: type: list required: true entry_schema: - type: string - port_1a_t1_port_mac_requirements: + type: json + port_1a_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - port_1a_t1_port_network: + port_1a_t2_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_image_name: - type: string - required: true - port_1a_t2_port_ip_requirements: + port_1a_t2_port_order: type: list required: true entry_schema: - type: json + type: integer compute_a_single_1a_user_data_format: type: list required: true @@ -88,14 +143,38 @@ topology_template: a_single_1a_1a_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1a_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1a_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1a_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1a_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1a_t1_port_mac_requirements - index_value + order: + get_input: + - port_1a_t1_port_order + - index_value + network_role: + get_input: + - port_1a_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1a_t1_port_subnetpoolid + - index_value network: get_input: - port_1a_t1_port_network @@ -135,6 +214,14 @@ topology_template: a_single_1a_1a_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1a_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1a_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1a_t2_port_ip_requirements @@ -147,6 +234,18 @@ topology_template: get_input: - port_1a_t2_port_mac_requirements - index_value + order: + get_input: + - port_1a_t2_port_order + - index_value + network_role: + get_input: + - port_1a_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1a_t2_port_subnetpoolid + - index_value network: get_input: - port_1a_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_b_single_1b_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_b_single_1b_0ServiceTemplate.yaml index 97428c699a..1b859d537f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_b_single_1b_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_b_single_1b_0ServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -33,27 +89,31 @@ topology_template: required: true entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string - required: true - port_1b_t1_port_ip_requirements: + port_1b_t2_port_ip_requirements: type: list required: true entry_schema: type: json - vm_image_name: - type: string + port_1b_t1_port_network_role_tag: + type: list required: true + entry_schema: + type: string compute_b_single_1b_metadata: type: list required: true entry_schema: type: json + port_1b_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -64,11 +124,11 @@ topology_template: required: true entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: - type: string + type: json compute_b_single_1b_name: type: list required: true @@ -105,14 +165,38 @@ topology_template: b_single_1b_1b_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_attribute: - b_single_1b @@ -125,14 +209,38 @@ topology_template: b_single_1b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_b_single_1b_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_b_single_1b_1ServiceTemplate.yaml index 78243244fa..1feba0fca7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_b_single_1b_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/Nested_b_single_1b_1ServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -33,14 +89,16 @@ topology_template: required: true entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string + port_1b_t2_port_ip_requirements: + type: list required: true + entry_schema: + type: json port_1b_t1_port_value_specs: type: list required: true @@ -51,14 +109,11 @@ topology_template: required: true entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true entry_schema: - type: json - vm_image_name: - type: string - required: true + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -69,11 +124,11 @@ topology_template: required: true entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true @@ -115,6 +170,14 @@ topology_template: get_input: - port_1b_t1_port_value_specs - index_value + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements @@ -127,6 +190,18 @@ topology_template: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_input: - port_1b_t1_port_network @@ -139,14 +214,38 @@ topology_template: b_single_1b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/nested-pcm_v0.1ServiceTemplate.yaml index d6dd992034..a8e64880b2 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/connectivityBetweenPatterns/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,32 +11,90 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - server_group: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string + availabilityzone_name: + label: availabilityzone name hidden: false immutable: false type: string - connectivityChk: + description: availabilityzone name + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json + pcm_image_name: + label: image name hidden: false immutable: false - type: json - availabilityzone_name: - label: availabilityzone name + type: string + description: PCRF CM image name + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + pcm_server_name: + label: PCRF CM server name hidden: false immutable: false type: string - description: availabilityzone name - oam_net_gw: - label: CPS network gateway + description: PCRF CM server name + cps_net_mask: + label: CPS network mask hidden: false immutable: false type: string - description: CPS network gateway - pcm_image_name: - label: image name + description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + oam_net_name: + label: OAM network name hidden: false immutable: false type: string - description: PCRF CM image name + description: OAM network name + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string + server_group: + hidden: false + immutable: false + type: string + connectivityChk: + hidden: false + immutable: false + type: json + oam_net_gw: + label: CPS network gateway + hidden: false + immutable: false + type: string + description: CPS network gateway security_group_name: label: security group name hidden: false @@ -49,6 +107,11 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false @@ -61,24 +124,12 @@ topology_template: immutable: false type: string description: CPS Cluman Cinder Volume - pcm_server_name: - label: PCRF CM server name - hidden: false - immutable: false - type: string - description: PCRF CM server name cps_net_name: label: CPS network name hidden: false immutable: false type: string description: CPS network name - cps_net_mask: - label: CPS network mask - hidden: false - immutable: false - type: string - description: CPS network mask oam_net_ip: label: OAM network ip hidden: false @@ -91,12 +142,11 @@ topology_template: immutable: false type: string description: CPS network mask - oam_net_name: - label: OAM network name - hidden: false - immutable: false - type: string - description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -109,15 +159,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -150,15 +220,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/GlobalSubstitutionTypesServiceTemplate.yaml index 3213f601da..536511a641 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -922,6 +922,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string server_group: type: string required: true @@ -936,6 +942,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -951,11 +963,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -986,11 +1022,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string @@ -1413,7 +1473,13 @@ node_types: org.openecomp.resource.abstract.nodes.1c1_scalling_instance: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_1c1_t1_port_fixed_ips: + port_1c1_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -1425,24 +1491,80 @@ node_types: status: SUPPORTED entry_schema: type: string - port_1c1_t2_port_ip_requirements: + port_1c1_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c1_t1_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_1c1_t1_port_mac_requirements: + vm_image_name: + type: string + required: true + status: SUPPORTED + compute_1c1_scalling_instance_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t1_port_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t1_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t2_port_fixed_ips: type: list required: true status: SUPPORTED entry_schema: type: json - port_1c1_t2_port_network_role_tag: + port_1c1_t2_port_network: type: list required: true status: SUPPORTED entry_schema: type: string + port_1c1_t1_port_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t1_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -1451,74 +1573,78 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_1c1_t2_port_mac_requirements: + port_1c1_t2_port_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_flavor_name: - type: string + type: string + port_1c1_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c1_t2_port_mac_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_1c1_scalling_instance_availability_zone: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t2_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string port_1c1_t2_port_name: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string - required: true - status: SUPPORTED compute_1c1_scalling_instance_scheduler_hints: type: list required: true status: SUPPORTED entry_schema: type: json - compute_1c1_scalling_instance_name: + port_1c1_t2_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - port_1c1_t1_port_name: + type: json + port_1c1_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_network: + port_1c1_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t2_port_fixed_ips: + port_1c1_t1_port_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1c1_t2_port_network: + type: string + port_1c1_t1_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string + type: integer attributes: 1c1_scalling_instance_instance_name: type: list @@ -1947,6 +2073,74 @@ node_types: org.openecomp.resource.abstract.nodes.a_single_1a: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1a_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1a_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t2_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t1_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1a_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_a_single_1a_availability_zone: type: list required: true @@ -1967,50 +2161,48 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_1a_t1_port_ip_requirements: + port_1a_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1a_t2_port_network_role_tag: + type: string + port_1a_t1_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_1a_t1_port_order: + type: list required: true status: SUPPORTED - port_1a_t2_port_network: + entry_schema: + type: integer + port_1a_t2_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - port_1a_t1_port_mac_requirements: + type: json + port_1a_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_1a_t1_port_network: + port_1a_t2_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1a_t2_port_ip_requirements: + port_1a_t2_port_order: type: list required: true status: SUPPORTED entry_schema: - type: json + type: integer compute_a_single_1a_user_data_format: type: list required: true @@ -2457,6 +2649,74 @@ node_types: org.openecomp.resource.abstract.nodes.b_single_1b_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -2483,32 +2743,30 @@ node_types: status: SUPPORTED entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_flavor_name: - type: string + port_1b_t2_port_ip_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_1b_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -2521,12 +2779,12 @@ node_types: status: SUPPORTED entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true @@ -2967,12 +3225,86 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c2_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -2987,22 +3319,18 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED + type: json port_1c2_t1_port_network: type: list required: true @@ -3015,11 +3343,7 @@ node_types: status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -3477,12 +3801,86 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c2_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -3497,22 +3895,18 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED + type: json port_1c2_t1_port_network: type: list required: true @@ -3525,11 +3919,7 @@ node_types: status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -4056,16 +4446,6 @@ node_types: status: SUPPORTED entry_schema: type: json - port_1b_t1_port_ip_requirements: - type: list - required: true - status: SUPPORTED - entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED compute_b_single_1b_availability_zone: type: list required: true @@ -4086,6 +4466,62 @@ node_types: status: SUPPORTED entry_schema: type: json + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t2_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -4098,7 +4534,19 @@ node_types: status: SUPPORTED entry_schema: type: string - port_1b_t2_port_ip_requirements: + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -4110,16 +4558,30 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_1b_t2_port_exCP_naming: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_b_single_1b_name: type: list required: true status: SUPPORTED entry_schema: type: string + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: b_single_1b_instance_name: type: list diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/MainServiceTemplate.yaml index 5108b6f4f0..68f812e15d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/MainServiceTemplate.yaml @@ -115,47 +115,14 @@ topology_template: directives: - substitutable properties: - port_1c1_t1_port_fixed_ips: - - - ip_address: - get_input: - - myIPs - - 3 - - - ip_address: - get_input: - - myIPs - - 1 compute_1c1_scalling_instance_user_data_format: - RAW2 - RAW1 - port_1c1_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: true - floating_ip_count_required: - is_required: false - - - ip_version: 4 - ip_count_required: - is_required: true - floating_ip_count_required: - is_required: false - port_1c1_t1_port_mac_requirements: - - mac_count_required: - is_required: false - - mac_count_required: - is_required: false port_1c1_t2_port_network_role_tag: - ppds - ppds - port_1c1_t2_port_mac_requirements: - - mac_count_required: - is_required: false - - mac_count_required: - is_required: false vm_flavor_name: get_input: pd_flavor_name - compute_1c1_scalling_instance_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name port_1c1_t1_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -167,14 +134,8 @@ topology_template: is_required: true floating_ip_count_required: is_required: false - port_1c1_t2_port_name: - - 1c1_t2_port_1 - - 1c1_t2_port_0 vm_image_name: get_input: pd_image_name - compute_1c1_scalling_instance_scheduler_hints: - - group: BE_Affinity_group - - group: BE_Affinity_group compute_1c1_scalling_instance_name: - get_input: - 1c1_scalling_instance_names @@ -200,6 +161,45 @@ topology_template: port_1c1_t2_port_network: - get_input: ppds_net_name - get_input: ppds_net_name + port_1c1_t1_port_fixed_ips: + - - ip_address: + get_input: + - myIPs + - 3 + - - ip_address: + get_input: + - myIPs + - 1 + port_1c1_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false + - - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false + port_1c1_t1_port_mac_requirements: + - mac_count_required: + is_required: false + - mac_count_required: + is_required: false + port_1c1_t2_port_mac_requirements: + - mac_count_required: + is_required: false + - mac_count_required: + is_required: false + compute_1c1_scalling_instance_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + port_1c1_t2_port_name: + - 1c1_t2_port_1 + - 1c1_t2_port_0 + compute_1c1_scalling_instance_scheduler_hints: + - group: BE_Affinity_group + - group: BE_Affinity_group service_template_filter: substitute_service_template: Nested_1c1_scalling_instanceServiceTemplate.yaml count: 2 @@ -225,6 +225,18 @@ topology_template: port_1b_t2_port_mac_requirements: - mac_count_required: is_required: false + compute_b_single_1b_availability_zone: + - get_input: availabilityzone_name + compute_b_single_1b_scheduler_hints: + - group: BE_Affinity_group + port_1b_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_flavor_name: + get_input: pd_flavor_name port_1b_t1_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -233,25 +245,13 @@ topology_template: is_required: false vm_image_name: get_input: pd_image_name - compute_b_single_1b_availability_zone: - - get_input: availabilityzone_name - compute_b_single_1b_scheduler_hints: - - group: BE_Affinity_group port_1b_t1_port_mac_requirements: - mac_count_required: is_required: false port_1b_t2_port_network: - b_single_1b_network - port_1b_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_b_single_1b_user_data_format: - RAW - vm_flavor_name: - get_input: pd_flavor_name compute_b_single_1b_name: - get_input: - b_single_1b_names @@ -292,32 +292,32 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_name: - get_input: - 1c2_catalog_instance_names - 1 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - RAW1 port_1c2_t1_port_network_role_tag: @@ -352,32 +352,32 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_name: - get_input: - 1c2_catalog_instance_names - 2 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - get_attribute: - abstract_1c2_catalog_instance_0 @@ -588,10 +588,6 @@ topology_template: directives: - substitutable properties: - compute_a_single_1a_availability_zone: - - get_input: availabilityzone_name - compute_a_single_1a_scheduler_hints: - - group: BE_Affinity_group port_1a_t1_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -617,6 +613,10 @@ topology_template: is_required: false floating_ip_count_required: is_required: false + compute_a_single_1a_availability_zone: + - get_input: availabilityzone_name + compute_a_single_1a_scheduler_hints: + - group: BE_Affinity_group compute_a_single_1a_user_data_format: - RAW compute_a_single_1a_name: @@ -780,6 +780,18 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_input: pd_flavor_name + port_1b_t1_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name + compute_b_single_1b_user_data_format: + - RAW port_1b_t2_port_mac_requirements: - mac_count_required: is_required: false @@ -793,25 +805,13 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - vm_flavor_name: - get_input: pd_flavor_name port_1b_t1_port_network_role_tag: - oam - port_1b_t1_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - vm_image_name: - get_input: pd_image_name port_1b_t1_port_mac_requirements: - mac_count_required: is_required: false port_1b_t2_port_network: - b_single_1b_network - compute_b_single_1b_user_data_format: - - RAW port_1b_t1_port_network: - get_input: oam_net_name compute_b_single_1b_name: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c1_scalling_instanceServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c1_scalling_instanceServiceTemplate.yaml index 2c43ee2c01..3a93e4c8b9 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c1_scalling_instanceServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c1_scalling_instanceServiceTemplate.yaml @@ -11,7 +11,12 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_1c1_t1_port_fixed_ips: + port_1c1_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c1_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -21,21 +26,67 @@ topology_template: required: true entry_schema: type: string - port_1c1_t2_port_ip_requirements: + port_1c1_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c1_t1_port_ip_requirements: type: list required: true entry_schema: type: json - port_1c1_t1_port_mac_requirements: + vm_image_name: + type: string + required: true + compute_1c1_scalling_instance_name: + type: list + required: true + entry_schema: + type: string + port_1c1_t1_port_name: + type: list + required: true + entry_schema: + type: string + port_1c1_t1_port_network: + type: list + required: true + entry_schema: + type: string + port_1c1_t2_port_fixed_ips: type: list required: true entry_schema: type: json - port_1c1_t2_port_network_role_tag: + port_1c1_t2_port_network: type: list required: true entry_schema: type: string + port_1c1_t1_port_fixed_ips: + type: list + required: true + entry_schema: + type: json + port_1c1_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_1c1_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1c1_t1_port_mac_requirements: + type: list + required: true + entry_schema: + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -43,74 +94,102 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_1c1_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1c1_t2_port_order: + type: list + required: true + entry_schema: + type: integer port_1c1_t2_port_mac_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string - required: true compute_1c1_scalling_instance_availability_zone: type: list required: true entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t2_port_subnetpoolid: type: list required: true entry_schema: - type: json + type: string port_1c1_t2_port_name: type: list required: true entry_schema: type: string - vm_image_name: - type: string - required: true compute_1c1_scalling_instance_scheduler_hints: type: list required: true entry_schema: type: json - compute_1c1_scalling_instance_name: + port_1c1_t2_port_exCP_naming: type: list required: true entry_schema: - type: string - port_1c1_t1_port_name: + type: json + port_1c1_t1_port_subnetpoolid: type: list required: true entry_schema: type: string - port_1c1_t1_port_network: + port_1c1_t1_port_network_role_tag: type: list required: true entry_schema: type: string - port_1c1_t2_port_fixed_ips: + port_1c1_t1_port_network_role: type: list required: true entry_schema: - type: json - port_1c1_t2_port_network: + type: string + port_1c1_t1_port_order: type: list required: true entry_schema: - type: string + type: integer node_templates: 1c1_scalling_instance_1c1_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c1_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c1_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c1_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c1_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c1_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c1_t1_port_order + - index_value + network_role: + get_input: + - port_1c1_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c1_t1_port_subnetpoolid + - index_value fixed_ips: get_input: - port_1c1_t1_port_fixed_ips @@ -154,6 +233,14 @@ topology_template: 1c1_scalling_instance_1c1_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c1_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c1_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c1_t2_port_ip_requirements @@ -166,6 +253,18 @@ topology_template: get_input: - port_1c1_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c1_t2_port_order + - index_value + network_role: + get_input: + - port_1c1_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c1_t2_port_subnetpoolid + - index_value fixed_ips: get_input: - port_1c1_t2_port_fixed_ips diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml index dd75d5837c..80b876b5ce 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,19 +89,16 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true + type: json port_1c2_t1_port_network: type: list required: true @@ -51,10 +109,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -106,14 +161,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -126,6 +205,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml index 213939c88e..ab88e26fa7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,19 +89,16 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true + type: json port_1c2_t1_port_network: type: list required: true @@ -51,10 +109,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -106,14 +161,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -126,6 +205,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_a_single_1aServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_a_single_1aServiceTemplate.yaml index dcfab01851..33152e6824 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_a_single_1aServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_a_single_1aServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1a_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1a_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1a_t2_port_network: + type: list + required: true + entry_schema: + type: string + port_1a_t1_port_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_network: + type: list + required: true + entry_schema: + type: string + port_1a_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + vm_image_name: + type: string + required: true + port_1a_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json compute_a_single_1a_availability_zone: type: list required: true @@ -28,42 +84,41 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_1a_t1_port_ip_requirements: + port_1a_t1_port_network_role_tag: type: list required: true entry_schema: - type: json - port_1a_t2_port_network_role_tag: + type: string + port_1a_t1_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_1a_t1_port_order: + type: list required: true - port_1a_t2_port_network: + entry_schema: + type: integer + port_1a_t2_port_exCP_naming: type: list required: true entry_schema: - type: string - port_1a_t1_port_mac_requirements: + type: json + port_1a_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - port_1a_t1_port_network: + port_1a_t2_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_image_name: - type: string - required: true - port_1a_t2_port_ip_requirements: + port_1a_t2_port_order: type: list required: true entry_schema: - type: json + type: integer compute_a_single_1a_user_data_format: type: list required: true @@ -83,14 +138,38 @@ topology_template: a_single_1a_1a_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1a_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1a_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1a_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1a_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1a_t1_port_mac_requirements - index_value + order: + get_input: + - port_1a_t1_port_order + - index_value + network_role: + get_input: + - port_1a_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1a_t1_port_subnetpoolid + - index_value network: get_input: - port_1a_t1_port_network @@ -126,6 +205,14 @@ topology_template: a_single_1a_1a_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1a_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1a_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1a_t2_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1a_t2_port_mac_requirements - index_value + order: + get_input: + - port_1a_t2_port_order + - index_value + network_role: + get_input: + - port_1a_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1a_t2_port_subnetpoolid + - index_value network: get_input: - port_1a_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_b_single_1b_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_b_single_1b_0ServiceTemplate.yaml index cefe2d2db0..cbfebea739 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_b_single_1b_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_b_single_1b_0ServiceTemplate.yaml @@ -16,14 +16,6 @@ topology_template: required: true entry_schema: type: json - port_1b_t1_port_ip_requirements: - type: list - required: true - entry_schema: - type: json - vm_image_name: - type: string - required: true compute_b_single_1b_availability_zone: type: list required: true @@ -41,6 +33,52 @@ topology_template: required: true entry_schema: type: json + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t2_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_1b_t1_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1b_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -51,7 +89,17 @@ topology_template: required: true entry_schema: type: string - port_1b_t2_port_ip_requirements: + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: @@ -61,14 +109,26 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string + port_1b_t2_port_exCP_naming: + type: list required: true + entry_schema: + type: json compute_b_single_1b_name: type: list required: true entry_schema: type: string + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string node_templates: b_single_1b: type: org.openecomp.resource.vfc.nodes.heat.b_single_1b @@ -96,14 +156,38 @@ topology_template: b_single_1b_1b_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_attribute: - b_single_1b @@ -116,14 +200,38 @@ topology_template: b_single_1b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_b_single_1b_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_b_single_1b_1ServiceTemplate.yaml index 158df6fc9f..23f23830ac 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_b_single_1b_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/Nested_b_single_1b_1ServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -33,27 +89,26 @@ topology_template: required: true entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string + port_1b_t2_port_ip_requirements: + type: list required: true + entry_schema: + type: json port_1b_t1_port_network_role_tag: type: list required: true entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true entry_schema: - type: json - vm_image_name: - type: string - required: true + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -64,11 +119,11 @@ topology_template: required: true entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true @@ -106,6 +161,14 @@ topology_template: b_single_1b_1b_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements @@ -118,6 +181,18 @@ topology_template: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_input: - port_1b_t1_port_network @@ -130,14 +205,38 @@ topology_template: b_single_1b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/nested-pcm_v0.1ServiceTemplate.yaml index 10064c8155..caa366f570 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/dependencyConnectivity/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string server_group: hidden: false immutable: false @@ -27,6 +32,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -45,12 +55,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -87,12 +117,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -105,15 +155,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -146,15 +216,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/GlobalSubstitutionTypesServiceTemplate.yaml index 5b8093e870..f0a9da57b6 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -922,6 +922,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string server_group: type: string required: true @@ -936,6 +942,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -951,11 +963,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -986,11 +1022,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string @@ -1413,7 +1473,13 @@ node_types: org.openecomp.resource.abstract.nodes.1c1_scalling_instance: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_1c1_t1_port_fixed_ips: + port_1c1_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -1425,24 +1491,80 @@ node_types: status: SUPPORTED entry_schema: type: string - port_1c1_t2_port_ip_requirements: + port_1c1_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c1_t1_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_1c1_t1_port_mac_requirements: + vm_image_name: + type: string + required: true + status: SUPPORTED + compute_1c1_scalling_instance_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t1_port_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t1_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t2_port_fixed_ips: type: list required: true status: SUPPORTED entry_schema: type: json - port_1c1_t2_port_network_role_tag: + port_1c1_t2_port_network: type: list required: true status: SUPPORTED entry_schema: type: string + port_1c1_t1_port_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t1_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -1451,74 +1573,78 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_1c1_t2_port_mac_requirements: + port_1c1_t2_port_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_flavor_name: - type: string + type: string + port_1c1_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c1_t2_port_mac_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_1c1_scalling_instance_availability_zone: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t2_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string port_1c1_t2_port_name: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string - required: true - status: SUPPORTED compute_1c1_scalling_instance_scheduler_hints: type: list required: true status: SUPPORTED entry_schema: type: json - compute_1c1_scalling_instance_name: + port_1c1_t2_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - port_1c1_t1_port_name: + type: json + port_1c1_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_network: + port_1c1_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t2_port_fixed_ips: + port_1c1_t1_port_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1c1_t2_port_network: + type: string + port_1c1_t1_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string + type: integer attributes: 1c1_scalling_instance_instance_name: type: list @@ -1947,6 +2073,74 @@ node_types: org.openecomp.resource.abstract.nodes.a_single_1a: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1a_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1a_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t2_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t1_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1a_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_a_single_1a_availability_zone: type: list required: true @@ -1967,50 +2161,48 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_1a_t1_port_ip_requirements: + port_1a_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1a_t2_port_network_role_tag: + type: string + port_1a_t1_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_1a_t1_port_order: + type: list required: true status: SUPPORTED - port_1a_t2_port_network: + entry_schema: + type: integer + port_1a_t2_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - port_1a_t1_port_mac_requirements: + type: json + port_1a_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_1a_t1_port_network: + port_1a_t2_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1a_t2_port_ip_requirements: + port_1a_t2_port_order: type: list required: true status: SUPPORTED entry_schema: - type: json + type: integer compute_a_single_1a_user_data_format: type: list required: true @@ -2457,6 +2649,74 @@ node_types: org.openecomp.resource.abstract.nodes.b_single_1b_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -2483,32 +2743,30 @@ node_types: status: SUPPORTED entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_flavor_name: - type: string + port_1b_t2_port_ip_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_1b_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -2521,12 +2779,12 @@ node_types: status: SUPPORTED entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true @@ -2967,12 +3225,86 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c2_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -2987,22 +3319,18 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED + type: json port_1c2_t1_port_network: type: list required: true @@ -3015,11 +3343,7 @@ node_types: status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -3477,12 +3801,86 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c2_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -3497,22 +3895,18 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED + type: json port_1c2_t1_port_network: type: list required: true @@ -3525,11 +3919,7 @@ node_types: status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -3993,16 +4383,6 @@ node_types: status: SUPPORTED entry_schema: type: json - port_1b_t1_port_ip_requirements: - type: list - required: true - status: SUPPORTED - entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED compute_b_single_1b_availability_zone: type: list required: true @@ -4023,6 +4403,62 @@ node_types: status: SUPPORTED entry_schema: type: json + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t2_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -4035,7 +4471,19 @@ node_types: status: SUPPORTED entry_schema: type: string - port_1b_t2_port_ip_requirements: + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -4047,16 +4495,30 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_1b_t2_port_exCP_naming: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_b_single_1b_name: type: list required: true status: SUPPORTED entry_schema: type: string + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: b_single_1b_instance_name: type: list diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/MainServiceTemplate.yaml index 9322fa81fc..26ab893506 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/MainServiceTemplate.yaml @@ -111,47 +111,14 @@ topology_template: directives: - substitutable properties: - port_1c1_t1_port_fixed_ips: - - - ip_address: - get_input: - - myIPs - - 3 - - - ip_address: - get_input: - - myIPs - - 1 compute_1c1_scalling_instance_user_data_format: - RAW2 - RAW1 - port_1c1_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: true - floating_ip_count_required: - is_required: false - - - ip_version: 4 - ip_count_required: - is_required: true - floating_ip_count_required: - is_required: false - port_1c1_t1_port_mac_requirements: - - mac_count_required: - is_required: false - - mac_count_required: - is_required: false port_1c1_t2_port_network_role_tag: - ppds - ppds - port_1c1_t2_port_mac_requirements: - - mac_count_required: - is_required: false - - mac_count_required: - is_required: false vm_flavor_name: get_input: pd_flavor_name - compute_1c1_scalling_instance_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name port_1c1_t1_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -163,14 +130,8 @@ topology_template: is_required: true floating_ip_count_required: is_required: false - port_1c1_t2_port_name: - - 1c1_t2_port_1 - - 1c1_t2_port_0 vm_image_name: get_input: pd_image_name - compute_1c1_scalling_instance_scheduler_hints: - - group: BE_Affinity_group - - group: BE_Affinity_group compute_1c1_scalling_instance_name: - get_input: - 1c1_scalling_instance_names @@ -196,6 +157,45 @@ topology_template: port_1c1_t2_port_network: - get_input: ppds_net_name - get_input: ppds_net_name + port_1c1_t1_port_fixed_ips: + - - ip_address: + get_input: + - myIPs + - 3 + - - ip_address: + get_input: + - myIPs + - 1 + port_1c1_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false + - - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false + port_1c1_t1_port_mac_requirements: + - mac_count_required: + is_required: false + - mac_count_required: + is_required: false + port_1c1_t2_port_mac_requirements: + - mac_count_required: + is_required: false + - mac_count_required: + is_required: false + compute_1c1_scalling_instance_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + port_1c1_t2_port_name: + - 1c1_t2_port_1 + - 1c1_t2_port_0 + compute_1c1_scalling_instance_scheduler_hints: + - group: BE_Affinity_group + - group: BE_Affinity_group service_template_filter: substitute_service_template: Nested_1c1_scalling_instanceServiceTemplate.yaml count: 2 @@ -217,6 +217,18 @@ topology_template: port_1b_t2_port_mac_requirements: - mac_count_required: is_required: false + compute_b_single_1b_availability_zone: + - get_input: availabilityzone_name + compute_b_single_1b_scheduler_hints: + - group: BE_Affinity_group + port_1b_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_flavor_name: + get_input: pd_flavor_name port_1b_t1_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -225,25 +237,13 @@ topology_template: is_required: false vm_image_name: get_input: pd_image_name - compute_b_single_1b_availability_zone: - - get_input: availabilityzone_name - compute_b_single_1b_scheduler_hints: - - group: BE_Affinity_group port_1b_t1_port_mac_requirements: - mac_count_required: is_required: false port_1b_t2_port_network: - b_single_1b_network - port_1b_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_b_single_1b_user_data_format: - RAW - vm_flavor_name: - get_input: pd_flavor_name compute_b_single_1b_name: - get_input: - b_single_1b_names @@ -271,32 +271,32 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_name: - get_input: - 1c2_catalog_instance_names - 1 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - RAW1 port_1c2_t1_port_network_role_tag: @@ -327,32 +327,32 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_name: - get_input: - 1c2_catalog_instance_names - 2 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - get_attribute: - abstract_1c2_catalog_instance_0 @@ -509,10 +509,6 @@ topology_template: directives: - substitutable properties: - compute_a_single_1a_availability_zone: - - get_input: availabilityzone_name - compute_a_single_1a_scheduler_hints: - - group: BE_Affinity_group port_1a_t1_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -538,6 +534,10 @@ topology_template: is_required: false floating_ip_count_required: is_required: false + compute_a_single_1a_availability_zone: + - get_input: availabilityzone_name + compute_a_single_1a_scheduler_hints: + - group: BE_Affinity_group compute_a_single_1a_user_data_format: - RAW compute_a_single_1a_name: @@ -693,6 +693,18 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_input: pd_flavor_name + port_1b_t1_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name + compute_b_single_1b_user_data_format: + - RAW port_1b_t2_port_mac_requirements: - mac_count_required: is_required: false @@ -706,25 +718,13 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - vm_flavor_name: - get_input: pd_flavor_name port_1b_t1_port_network_role_tag: - oam - port_1b_t1_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - vm_image_name: - get_input: pd_image_name port_1b_t1_port_mac_requirements: - mac_count_required: is_required: false port_1b_t2_port_network: - b_single_1b_network - compute_b_single_1b_user_data_format: - - RAW port_1b_t1_port_network: - get_input: oam_net_name compute_b_single_1b_name: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c1_scalling_instanceServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c1_scalling_instanceServiceTemplate.yaml index 2c43ee2c01..3a93e4c8b9 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c1_scalling_instanceServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c1_scalling_instanceServiceTemplate.yaml @@ -11,7 +11,12 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_1c1_t1_port_fixed_ips: + port_1c1_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c1_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -21,21 +26,67 @@ topology_template: required: true entry_schema: type: string - port_1c1_t2_port_ip_requirements: + port_1c1_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c1_t1_port_ip_requirements: type: list required: true entry_schema: type: json - port_1c1_t1_port_mac_requirements: + vm_image_name: + type: string + required: true + compute_1c1_scalling_instance_name: + type: list + required: true + entry_schema: + type: string + port_1c1_t1_port_name: + type: list + required: true + entry_schema: + type: string + port_1c1_t1_port_network: + type: list + required: true + entry_schema: + type: string + port_1c1_t2_port_fixed_ips: type: list required: true entry_schema: type: json - port_1c1_t2_port_network_role_tag: + port_1c1_t2_port_network: type: list required: true entry_schema: type: string + port_1c1_t1_port_fixed_ips: + type: list + required: true + entry_schema: + type: json + port_1c1_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_1c1_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1c1_t1_port_mac_requirements: + type: list + required: true + entry_schema: + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -43,74 +94,102 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_1c1_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1c1_t2_port_order: + type: list + required: true + entry_schema: + type: integer port_1c1_t2_port_mac_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string - required: true compute_1c1_scalling_instance_availability_zone: type: list required: true entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t2_port_subnetpoolid: type: list required: true entry_schema: - type: json + type: string port_1c1_t2_port_name: type: list required: true entry_schema: type: string - vm_image_name: - type: string - required: true compute_1c1_scalling_instance_scheduler_hints: type: list required: true entry_schema: type: json - compute_1c1_scalling_instance_name: + port_1c1_t2_port_exCP_naming: type: list required: true entry_schema: - type: string - port_1c1_t1_port_name: + type: json + port_1c1_t1_port_subnetpoolid: type: list required: true entry_schema: type: string - port_1c1_t1_port_network: + port_1c1_t1_port_network_role_tag: type: list required: true entry_schema: type: string - port_1c1_t2_port_fixed_ips: + port_1c1_t1_port_network_role: type: list required: true entry_schema: - type: json - port_1c1_t2_port_network: + type: string + port_1c1_t1_port_order: type: list required: true entry_schema: - type: string + type: integer node_templates: 1c1_scalling_instance_1c1_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c1_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c1_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c1_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c1_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c1_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c1_t1_port_order + - index_value + network_role: + get_input: + - port_1c1_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c1_t1_port_subnetpoolid + - index_value fixed_ips: get_input: - port_1c1_t1_port_fixed_ips @@ -154,6 +233,14 @@ topology_template: 1c1_scalling_instance_1c1_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c1_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c1_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c1_t2_port_ip_requirements @@ -166,6 +253,18 @@ topology_template: get_input: - port_1c1_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c1_t2_port_order + - index_value + network_role: + get_input: + - port_1c1_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c1_t2_port_subnetpoolid + - index_value fixed_ips: get_input: - port_1c1_t2_port_fixed_ips diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml index dd75d5837c..80b876b5ce 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,19 +89,16 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true + type: json port_1c2_t1_port_network: type: list required: true @@ -51,10 +109,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -106,14 +161,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -126,6 +205,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml index 213939c88e..ab88e26fa7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,19 +89,16 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true + type: json port_1c2_t1_port_network: type: list required: true @@ -51,10 +109,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -106,14 +161,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -126,6 +205,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_a_single_1aServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_a_single_1aServiceTemplate.yaml index dcfab01851..33152e6824 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_a_single_1aServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_a_single_1aServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1a_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1a_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1a_t2_port_network: + type: list + required: true + entry_schema: + type: string + port_1a_t1_port_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_network: + type: list + required: true + entry_schema: + type: string + port_1a_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + vm_image_name: + type: string + required: true + port_1a_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json compute_a_single_1a_availability_zone: type: list required: true @@ -28,42 +84,41 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_1a_t1_port_ip_requirements: + port_1a_t1_port_network_role_tag: type: list required: true entry_schema: - type: json - port_1a_t2_port_network_role_tag: + type: string + port_1a_t1_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_1a_t1_port_order: + type: list required: true - port_1a_t2_port_network: + entry_schema: + type: integer + port_1a_t2_port_exCP_naming: type: list required: true entry_schema: - type: string - port_1a_t1_port_mac_requirements: + type: json + port_1a_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - port_1a_t1_port_network: + port_1a_t2_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_image_name: - type: string - required: true - port_1a_t2_port_ip_requirements: + port_1a_t2_port_order: type: list required: true entry_schema: - type: json + type: integer compute_a_single_1a_user_data_format: type: list required: true @@ -83,14 +138,38 @@ topology_template: a_single_1a_1a_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1a_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1a_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1a_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1a_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1a_t1_port_mac_requirements - index_value + order: + get_input: + - port_1a_t1_port_order + - index_value + network_role: + get_input: + - port_1a_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1a_t1_port_subnetpoolid + - index_value network: get_input: - port_1a_t1_port_network @@ -126,6 +205,14 @@ topology_template: a_single_1a_1a_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1a_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1a_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1a_t2_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1a_t2_port_mac_requirements - index_value + order: + get_input: + - port_1a_t2_port_order + - index_value + network_role: + get_input: + - port_1a_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1a_t2_port_subnetpoolid + - index_value network: get_input: - port_1a_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_b_single_1b_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_b_single_1b_0ServiceTemplate.yaml index cefe2d2db0..cbfebea739 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_b_single_1b_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_b_single_1b_0ServiceTemplate.yaml @@ -16,14 +16,6 @@ topology_template: required: true entry_schema: type: json - port_1b_t1_port_ip_requirements: - type: list - required: true - entry_schema: - type: json - vm_image_name: - type: string - required: true compute_b_single_1b_availability_zone: type: list required: true @@ -41,6 +33,52 @@ topology_template: required: true entry_schema: type: json + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t2_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_1b_t1_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1b_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -51,7 +89,17 @@ topology_template: required: true entry_schema: type: string - port_1b_t2_port_ip_requirements: + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: @@ -61,14 +109,26 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string + port_1b_t2_port_exCP_naming: + type: list required: true + entry_schema: + type: json compute_b_single_1b_name: type: list required: true entry_schema: type: string + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string node_templates: b_single_1b: type: org.openecomp.resource.vfc.nodes.heat.b_single_1b @@ -96,14 +156,38 @@ topology_template: b_single_1b_1b_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_attribute: - b_single_1b @@ -116,14 +200,38 @@ topology_template: b_single_1b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_b_single_1b_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_b_single_1b_1ServiceTemplate.yaml index 158df6fc9f..23f23830ac 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_b_single_1b_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/Nested_b_single_1b_1ServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -33,27 +89,26 @@ topology_template: required: true entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string + port_1b_t2_port_ip_requirements: + type: list required: true + entry_schema: + type: json port_1b_t1_port_network_role_tag: type: list required: true entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true entry_schema: - type: json - vm_image_name: - type: string - required: true + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -64,11 +119,11 @@ topology_template: required: true entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true @@ -106,6 +161,14 @@ topology_template: b_single_1b_1b_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements @@ -118,6 +181,18 @@ topology_template: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_input: - port_1b_t1_port_network @@ -130,14 +205,38 @@ topology_template: b_single_1b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/nested-pcm_v0.1ServiceTemplate.yaml index 10064c8155..caa366f570 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/oneAppearancePerPattern/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string server_group: hidden: false immutable: false @@ -27,6 +32,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -45,12 +55,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -87,12 +117,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -105,15 +155,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -146,15 +216,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/GlobalSubstitutionTypesServiceTemplate.yaml index 5f4738ca50..19dc9b133d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -926,6 +926,12 @@ node_types: org.openecomp.resource.abstract.nodes.1c12_scalling_instance: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c1_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_1c12_scalling_instance_scheduler_hints: type: list required: true @@ -944,10 +950,12 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string + port_1c1_t1_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_1c1_t1_port_mac_requirements: type: list required: true @@ -962,40 +970,68 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_1c1_t1_port_name: + vm_flavor_name: + type: string + required: true + status: SUPPORTED + compute_1c12_scalling_instance_user_data_format: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: + port_1c1_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: type: string required: true status: SUPPORTED - compute_1c12_scalling_instance_availability_zone: + port_1c1_t1_port_name: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_network: + port_1c1_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c12_scalling_instance_user_data_format: + port_1c1_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t1_port_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string + compute_1c12_scalling_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t1_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer attributes: 1c12_scalling_instance_1c1_t1_port_tenant_id: type: list @@ -1346,16 +1382,24 @@ node_types: org.openecomp.resource.abstract.nodes.1c11_scalling_instance: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c1_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c1_t1_port_fixed_ips: type: list required: true status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string + port_1c1_t1_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_1c1_t1_port_mac_requirements: type: list required: true @@ -1370,52 +1414,80 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_1c1_t1_port_name: + vm_flavor_name: + type: string + required: true + status: SUPPORTED + compute_1c11_scalling_instance_name: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c11_scalling_instance_scheduler_hints: + compute_1c11_scalling_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_1c11_scalling_instance_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c1_t1_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_flavor_name: + vm_image_name: type: string required: true status: SUPPORTED - compute_1c11_scalling_instance_name: + port_1c1_t1_port_name: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_network: + compute_1c11_scalling_instance_scheduler_hints: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c1_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c11_scalling_instance_availability_zone: + port_1c1_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c11_scalling_instance_user_data_format: + port_1c1_t1_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t1_port_network: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string + port_1c1_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer attributes: 1c11_scalling_instance_instance_name: type: list @@ -1766,29 +1838,92 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - server_group: - type: string - required: true - status: SUPPORTED - connectivityChk: - type: json + port_pcm_port_0_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name required: true status: SUPPORTED - oam_net_gw: - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + pcm_server_name: + type: string + description: PCRF CM server name + required: true + status: SUPPORTED + cps_net_mask: + type: string + description: CPS network mask + required: true + status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + oam_net_name: + type: string + description: OAM network name + required: true + status: SUPPORTED + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + server_group: + type: string + required: true + status: SUPPORTED + connectivityChk: + type: json + required: true + status: SUPPORTED + oam_net_gw: + type: string + description: CPS network gateway + required: true + status: SUPPORTED security_group_name: type: string description: the name of security group @@ -1799,6 +1934,12 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance @@ -1809,21 +1950,11 @@ node_types: description: CPS Cluman Cinder Volume required: true status: SUPPORTED - pcm_server_name: - type: string - description: PCRF CM server name - required: true - status: SUPPORTED cps_net_name: type: string description: CPS network name required: true status: SUPPORTED - cps_net_mask: - type: string - description: CPS network mask - required: true - status: SUPPORTED oam_net_ip: type: string description: OAM network ip @@ -1834,11 +1965,12 @@ node_types: description: CPS network mask required: true status: SUPPORTED - oam_net_name: - type: string - description: OAM network name + port_pcm_port_1_order: + type: list required: true status: SUPPORTED + entry_schema: + type: integer attributes: server_pcm_id: type: string @@ -2261,22 +2393,18 @@ node_types: org.openecomp.resource.abstract.nodes.a_single_2a: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - compute_a_single_2a_name: + compute_a_single_2a_user_data_format: type: list required: true status: SUPPORTED entry_schema: type: string - compute_a_single_2a_user_data_format: + port_1a_t1_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_image_name: - type: string - required: true - status: SUPPORTED + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -2291,12 +2419,30 @@ node_types: status: SUPPORTED entry_schema: type: json + port_1a_t1_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string compute_a_single_2a_scheduler_hints: type: list required: true status: SUPPORTED entry_schema: type: json + port_1a_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer compute_a_single_2a_availability_zone: type: list required: true @@ -2307,24 +2453,46 @@ node_types: type: string required: true status: SUPPORTED - compute_a_single_2a_metadata: + port_1a_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_1a_t1_port_mac_requirements: + port_1a_t1_port_network: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1a_t1_port_network: + type: string + port_1a_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_a_single_2a_name: type: list required: true status: SUPPORTED entry_schema: type: string + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1a_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + compute_a_single_2a_metadata: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json attributes: a_single_2a_instance_name: type: list @@ -2670,33 +2838,25 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_1c2_t1_port_mac_requirements: + port_1c2_t2_port_order: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1c2_t2_port_network: + type: integer + compute_1c2_catalog_instance_availability_zone: type: list required: true status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + port_1c2_t2_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t2_port_network_role: type: list required: true status: SUPPORTED @@ -2706,13 +2866,13 @@ node_types: type: string required: true status: SUPPORTED - port_1c2_t1_port_network: + port_1c2_t2_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - port_1c2_t2_port_mac_requirements: + port_1c2_t1_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -2722,12 +2882,86 @@ node_types: type: string required: true status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_1c2_catalog_instance_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t2_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_1c2_catalog_instance_user_data_format: type: list required: true @@ -3181,6 +3415,74 @@ node_types: status: SUPPORTED entry_schema: type: json + port_1a_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1a_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t2_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t1_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1a_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1a_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1a_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_a_single_1a_availability_zone: type: list required: true @@ -3201,50 +3503,48 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_1a_t1_port_ip_requirements: + port_1a_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1a_t2_port_network_role_tag: + type: string + port_1a_t1_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_1a_t1_port_order: + type: list required: true status: SUPPORTED - port_1a_t2_port_network: + entry_schema: + type: integer + port_1a_t2_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - port_1a_t1_port_mac_requirements: + type: json + port_1a_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_1a_t1_port_network: + port_1a_t2_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1a_t2_port_ip_requirements: + port_1a_t2_port_order: type: list required: true status: SUPPORTED entry_schema: - type: json + type: integer compute_a_single_1a_user_data_format: type: list required: true @@ -3691,12 +3991,86 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_3: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c2_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -3711,22 +4085,18 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true status: SUPPORTED entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED + type: json port_1c2_t1_port_network: type: list required: true @@ -3739,11 +4109,7 @@ node_types: status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -4201,6 +4567,74 @@ node_types: org.openecomp.resource.abstract.nodes.b_single_1b_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -4227,32 +4661,36 @@ node_types: status: SUPPORTED entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_flavor_name: - type: string - required: true - status: SUPPORTED - port_1b_t1_port_ip_requirements: + port_1b_t2_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string + port_1b_t1_port_network_role_tag: + type: list required: true status: SUPPORTED + entry_schema: + type: string compute_b_single_1b_metadata: type: list required: true status: SUPPORTED entry_schema: type: json + port_1b_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -4265,12 +4703,12 @@ node_types: status: SUPPORTED entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json compute_b_single_1b_name: type: list required: true @@ -4705,12 +5143,86 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c2_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -4725,12 +5237,6 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: - type: list - required: true - status: SUPPORTED - entry_schema: - type: string compute_1c2_catalog_instance_metadata: type: list required: true @@ -4743,10 +5249,12 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_1c2_t1_port_exCP_naming: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_network: type: list required: true @@ -4759,11 +5267,7 @@ node_types: status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -5221,12 +5725,86 @@ node_types: org.openecomp.resource.abstract.nodes.1c2_catalog_instance_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1c2_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1c2_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -5241,22 +5819,18 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: - type: list - required: true - status: SUPPORTED - entry_schema: - type: string compute_1c2_catalog_instance_name: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string + type: string + port_1c2_t1_port_exCP_naming: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_1c2_t1_port_network: type: list required: true @@ -5269,11 +5843,7 @@ node_types: status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true status: SUPPORTED @@ -5726,6 +6296,80 @@ node_types: org.openecomp.resource.abstract.nodes.b_single_2b_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + compute_b_single_2b_metadata: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + compute_b_single_2b_scheduler_hints: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string compute_b_single_2b_availability_zone: type: list required: true @@ -5746,6 +6390,12 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 + port_1b_t2_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1b_t2_port_ip_requirements: type: list required: true @@ -5758,50 +6408,42 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED compute_b_single_2b_user_data_format: type: list required: true status: SUPPORTED entry_schema: type: string - compute_b_single_2b_metadata: + port_1b_t1_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1b_t1_port_ip_requirements: + type: string + port_1b_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED + type: string port_1b_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - compute_b_single_2b_scheduler_hints: + port_1b_t2_port_network: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1b_t2_port_network: + type: string + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json attributes: b_single_2b_instance_name: type: list @@ -6225,6 +6867,74 @@ node_types: org.openecomp.resource.abstract.nodes.b_single_1b_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -6251,16 +6961,18 @@ node_types: status: SUPPORTED entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_flavor_name: - type: string + port_1b_t2_port_ip_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_1b_t1_port_value_specs: type: list required: true @@ -6273,16 +6985,12 @@ node_types: status: SUPPORTED entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -6295,12 +7003,12 @@ node_types: status: SUPPORTED entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true @@ -6741,6 +7449,74 @@ node_types: org.openecomp.resource.abstract.nodes.b_single_2b_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_1b_t1_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_1b_t1_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + compute_b_single_2b_scheduler_hints: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_1b_t2_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string compute_b_single_2b_availability_zone: type: list required: true @@ -6761,6 +7537,12 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 + port_1b_t2_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_1b_t2_port_ip_requirements: type: list required: true @@ -6773,10 +7555,6 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED port_1b_t1_port_value_specs: type: list required: true @@ -6795,34 +7573,30 @@ node_types: status: SUPPORTED entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED + type: string port_1b_t1_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - compute_b_single_2b_scheduler_hints: + port_1b_t2_port_network: type: list required: true status: SUPPORTED entry_schema: - type: json - port_1b_t2_port_network: + type: string + port_1b_t1_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/MainServiceTemplate.yaml index 4c81d27afc..d61ea01cc8 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/MainServiceTemplate.yaml @@ -284,32 +284,32 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_name: - get_input: - 1c2_catalog_instance_names - 3 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - get_attribute: - abstract_1c2_catalog_instance_1 @@ -342,32 +342,32 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_name: - get_input: - 1c2_catalog_instance_names - 2 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - get_attribute: - abstract_1c2_catalog_instance_0 @@ -400,13 +400,23 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_metadata: - connectivityTo4PNested_2: get_attribute: @@ -480,21 +490,11 @@ topology_template: - get_input: - 1c2_catalog_instance_names - 1 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - RAW1 port_1c2_t1_port_network_role_tag: @@ -525,32 +525,32 @@ topology_template: directives: - substitutable properties: + compute_1c2_catalog_instance_availability_zone: + - get_input: availabilityzone_name + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name + port_1c2_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_1c2_t1_port_mac_requirements: - mac_count_required: is_required: false port_1c2_t2_port_network: - 1c2_catalog_instance_network - compute_1c2_catalog_instance_availability_zone: - - get_input: availabilityzone_name compute_1c2_catalog_instance_name: - get_input: - 1c2_catalog_instance_names - 2 - vm_flavor_name: - get_input: pd_flavor_name port_1c2_t1_port_network: - get_input: oam_net_name port_1c2_t2_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: pd_image_name - port_1c2_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_1c2_catalog_instance_user_data_format: - RAW1 port_1c2_t1_port_network_role_tag: @@ -708,10 +708,6 @@ topology_template: get_attribute: - abstract_1c2_catalog_instance_1 - 1c2_catalog_instance_instance_name - compute_a_single_1a_availability_zone: - - get_input: availabilityzone_name - compute_a_single_1a_scheduler_hints: - - group: BE_Affinity_group port_1a_t1_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -737,6 +733,10 @@ topology_template: is_required: false floating_ip_count_required: is_required: false + compute_a_single_1a_availability_zone: + - get_input: availabilityzone_name + compute_a_single_1a_scheduler_hints: + - group: BE_Affinity_group compute_a_single_1a_user_data_format: - RAW compute_a_single_1a_name: @@ -860,6 +860,18 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_input: pd_flavor_name + port_1b_t1_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name + compute_b_single_2b_scheduler_hints: + - group: BE_Affinity_group compute_b_single_2b_availability_zone: - get_input: availabilityzone_name port_1b_t2_port_mac_requirements: @@ -875,8 +887,6 @@ topology_template: - get_input: - b_single_2b_names - 1 - vm_flavor_name: - get_input: pd_flavor_name port_1b_t1_port_value_specs: - get_attribute: - abstract_a_single_1a @@ -885,19 +895,9 @@ topology_template: - RAW port_1b_t1_port_network_role_tag: - oam - port_1b_t1_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - vm_image_name: - get_input: pd_image_name port_1b_t1_port_mac_requirements: - mac_count_required: is_required: false - compute_b_single_2b_scheduler_hints: - - group: BE_Affinity_group port_1b_t2_port_network: - b_single_1b_network_2 port_1b_t1_port_network: @@ -1025,19 +1025,11 @@ topology_template: get_input: - myIPs - 1 - vm_image_name: - get_input: pd_image_name port_1c1_t1_port_mac_requirements: - mac_count_required: is_required: false - mac_count_required: is_required: false - port_1c1_t1_port_name: - - 1c1_t1_port_01 - - 1c1_t1_port_02 - compute_1c11_scalling_instance_scheduler_hints: - - group: BE_Affinity_group - - group: BE_Affinity_group vm_flavor_name: get_input: pd_flavor_name compute_1c11_scalling_instance_name: @@ -1047,9 +1039,6 @@ topology_template: - get_input: - 1c11_scalling_instance_names - 2 - port_1c1_t1_port_network: - - 1c1_scalling_instance_network - - 1c1_scalling_instance_network compute_1c11_scalling_instance_availability_zone: - get_input: availabilityzone_name - get_input: availabilityzone_name @@ -1067,6 +1056,17 @@ topology_template: is_required: true floating_ip_count_required: is_required: false + vm_image_name: + get_input: pd_image_name + port_1c1_t1_port_name: + - 1c1_t1_port_01 + - 1c1_t1_port_02 + compute_1c11_scalling_instance_scheduler_hints: + - group: BE_Affinity_group + - group: BE_Affinity_group + port_1c1_t1_port_network: + - 1c1_scalling_instance_network + - 1c1_scalling_instance_network service_template_filter: substitute_service_template: Nested_1c11_scalling_instanceServiceTemplate.yaml count: 2 @@ -1085,25 +1085,8 @@ topology_template: directives: - substitutable properties: - compute_b_single_2b_availability_zone: - - get_input: availabilityzone_name - port_1b_t2_port_mac_requirements: - - mac_count_required: - is_required: false - port_1b_t2_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - compute_b_single_2b_name: - - get_input: - - b_single_2b_names - - 0 vm_flavor_name: get_input: pd_flavor_name - compute_b_single_2b_user_data_format: - - RAW compute_b_single_2b_metadata: - connectivityTo4PNested_2: get_attribute: @@ -1177,11 +1160,28 @@ topology_template: is_required: false vm_image_name: get_input: pd_image_name + compute_b_single_2b_scheduler_hints: + - group: BE_Affinity_group + compute_b_single_2b_availability_zone: + - get_input: availabilityzone_name + port_1b_t2_port_mac_requirements: + - mac_count_required: + is_required: false + port_1b_t2_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + compute_b_single_2b_name: + - get_input: + - b_single_2b_names + - 0 + compute_b_single_2b_user_data_format: + - RAW port_1b_t1_port_mac_requirements: - mac_count_required: is_required: false - compute_b_single_2b_scheduler_hints: - - group: BE_Affinity_group port_1b_t2_port_network: - b_single_1b_network_2 service_template_filter: @@ -1231,24 +1231,13 @@ topology_template: - get_input: - 1c12_scalling_instance_names - 2 - vm_image_name: - get_input: pd_image_name port_1c1_t1_port_mac_requirements: - mac_count_required: is_required: false - mac_count_required: is_required: false - port_1c1_t1_port_name: - - 1c1_t1_port_11 - - 1c1_t1_port_12 vm_flavor_name: get_input: pd_flavor_name - compute_1c12_scalling_instance_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - port_1c1_t1_port_network: - - 1c1_scalling_instance_network - - 1c1_scalling_instance_network compute_1c12_scalling_instance_user_data_format: - RAW1 - RAW1 @@ -1263,6 +1252,17 @@ topology_template: is_required: true floating_ip_count_required: is_required: false + vm_image_name: + get_input: pd_image_name + port_1c1_t1_port_name: + - 1c1_t1_port_11 + - 1c1_t1_port_12 + compute_1c12_scalling_instance_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + port_1c1_t1_port_network: + - 1c1_scalling_instance_network + - 1c1_scalling_instance_network service_template_filter: substitute_service_template: Nested_1c12_scalling_instanceServiceTemplate.yaml count: 2 @@ -1411,14 +1411,8 @@ topology_template: directives: - substitutable properties: - compute_a_single_2a_name: - - get_input: - - a_single_2a_names - - 0 compute_a_single_2a_user_data_format: - RAW - vm_image_name: - get_input: pd_image_name port_1a_t1_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -1431,6 +1425,17 @@ topology_template: - get_input: availabilityzone_name vm_flavor_name: get_input: pd_flavor_name + port_1a_t1_port_mac_requirements: + - mac_count_required: + is_required: false + port_1a_t1_port_network: + - a_single_1a_network + compute_a_single_2a_name: + - get_input: + - a_single_2a_names + - 0 + vm_image_name: + get_input: pd_image_name compute_a_single_2a_metadata: - connectivityTo4PNested_2: get_attribute: @@ -1495,11 +1500,6 @@ topology_template: get_attribute: - abstract_1c2_catalog_instance_1 - 1c2_catalog_instance_instance_name - port_1a_t1_port_mac_requirements: - - mac_count_required: - is_required: false - port_1a_t1_port_network: - - a_single_1a_network service_template_filter: substitute_service_template: Nested_a_single_2aServiceTemplate.yaml count: 1 @@ -1518,6 +1518,18 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_input: pd_flavor_name + port_1b_t1_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name + compute_b_single_1b_user_data_format: + - RAW port_1b_t2_port_mac_requirements: - mac_count_required: is_required: false @@ -1531,29 +1543,17 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - vm_flavor_name: - get_input: pd_flavor_name port_1b_t1_port_value_specs: - get_attribute: - abstract_a_single_1a - a_single_1a_1a_t1_port_tenant_id port_1b_t1_port_network_role_tag: - oam - port_1b_t1_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - vm_image_name: - get_input: pd_image_name port_1b_t1_port_mac_requirements: - mac_count_required: is_required: false port_1b_t2_port_network: - b_single_1b_network_1 - compute_b_single_1b_user_data_format: - - RAW port_1b_t1_port_network: - get_input: oam_net_name compute_b_single_1b_name: @@ -1762,6 +1762,18 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_input: pd_flavor_name + port_1b_t1_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name + compute_b_single_1b_user_data_format: + - RAW port_1b_t2_port_mac_requirements: - mac_count_required: is_required: false @@ -1775,16 +1787,6 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - vm_flavor_name: - get_input: pd_flavor_name - port_1b_t1_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - vm_image_name: - get_input: pd_image_name compute_b_single_1b_metadata: - connectivityTo4PNested_2: get_attribute: @@ -1855,8 +1857,6 @@ topology_template: is_required: false port_1b_t2_port_network: - b_single_1b_network_1 - compute_b_single_1b_user_data_format: - - RAW compute_b_single_1b_name: - get_input: - b_single_1b_names diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c11_scalling_instanceServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c11_scalling_instanceServiceTemplate.yaml index 610b8d7a56..a249ecf5cc 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c11_scalling_instanceServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c11_scalling_instanceServiceTemplate.yaml @@ -11,14 +11,21 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c1_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json port_1c1_t1_port_fixed_ips: type: list required: true entry_schema: type: json - vm_image_name: - type: string + port_1c1_t1_port_vlan_requirements: + type: list required: true + entry_schema: + type: json port_1c1_t1_port_mac_requirements: type: list required: true @@ -31,44 +38,67 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_1c1_t1_port_name: + vm_flavor_name: + type: string + required: true + compute_1c11_scalling_instance_name: type: list required: true entry_schema: type: string - compute_1c11_scalling_instance_scheduler_hints: + compute_1c11_scalling_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_1c11_scalling_instance_user_data_format: + type: list + required: true + entry_schema: + type: string + port_1c1_t1_port_ip_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: + vm_image_name: type: string required: true - compute_1c11_scalling_instance_name: + port_1c1_t1_port_name: type: list required: true entry_schema: type: string - port_1c1_t1_port_network: + compute_1c11_scalling_instance_scheduler_hints: + type: list + required: true + entry_schema: + type: json + port_1c1_t1_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_1c11_scalling_instance_availability_zone: + port_1c1_t1_port_network_role_tag: type: list required: true entry_schema: type: string - compute_1c11_scalling_instance_user_data_format: + port_1c1_t1_port_network_role: type: list required: true entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t1_port_network: type: list required: true entry_schema: - type: json + type: string + port_1c1_t1_port_order: + type: list + required: true + entry_schema: + type: integer node_templates: 1c11_scalling_instance: type: org.openecomp.resource.vfc.nodes.heat.1c11_scalling_instance @@ -96,14 +126,38 @@ topology_template: 1c11_scalling_instance_1c1_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c1_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c1_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c1_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c1_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c1_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c1_t1_port_order + - index_value + network_role: + get_input: + - port_1c1_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c1_t1_port_subnetpoolid + - index_value fixed_ips: get_input: - port_1c1_t1_port_fixed_ips diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c12_scalling_instanceServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c12_scalling_instanceServiceTemplate.yaml index 09698482d3..90c0f22132 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c12_scalling_instanceServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c12_scalling_instanceServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c1_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json compute_1c12_scalling_instance_scheduler_hints: type: list required: true @@ -26,9 +31,11 @@ topology_template: required: true entry_schema: type: string - vm_image_name: - type: string + port_1c1_t1_port_vlan_requirements: + type: list required: true + entry_schema: + type: json port_1c1_t1_port_mac_requirements: type: list required: true @@ -41,46 +48,93 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_1c1_t1_port_name: + vm_flavor_name: + type: string + required: true + compute_1c12_scalling_instance_user_data_format: type: list required: true entry_schema: type: string - vm_flavor_name: + port_1c1_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: type: string required: true - compute_1c12_scalling_instance_availability_zone: + port_1c1_t1_port_name: type: list required: true entry_schema: type: string - port_1c1_t1_port_network: + port_1c1_t1_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_1c12_scalling_instance_user_data_format: + port_1c1_t1_port_network_role_tag: type: list required: true entry_schema: type: string - port_1c1_t1_port_ip_requirements: + port_1c1_t1_port_network_role: type: list required: true entry_schema: - type: json + type: string + compute_1c12_scalling_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c1_t1_port_network: + type: list + required: true + entry_schema: + type: string + port_1c1_t1_port_order: + type: list + required: true + entry_schema: + type: integer node_templates: 1c12_scalling_instance_1c1_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c1_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c1_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c1_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c1_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c1_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c1_t1_port_order + - index_value + network_role: + get_input: + - port_1c1_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c1_t1_port_subnetpoolid + - index_value fixed_ips: get_input: - port_1c1_t1_port_fixed_ips diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml index 67305b71ce..7a439484d6 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_0ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,11 +89,6 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: - type: list - required: true - entry_schema: - type: string compute_1c2_catalog_instance_metadata: type: list required: true @@ -43,9 +99,11 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string + port_1c2_t1_port_exCP_naming: + type: list required: true + entry_schema: + type: json port_1c2_t1_port_network: type: list required: true @@ -56,10 +114,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -115,14 +170,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -135,6 +214,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -147,6 +234,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml index 278dffc4ff..e384bc3dc4 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_1ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,19 +89,16 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true + type: json port_1c2_t1_port_network: type: list required: true @@ -51,10 +109,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -106,14 +161,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -126,6 +205,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_2ServiceTemplate.yaml index edff50ac2e..1ff0c9b441 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_2ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,19 +89,16 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true + type: json port_1c2_t1_port_network: type: list required: true @@ -51,10 +109,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -106,14 +161,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -126,6 +205,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_3ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_3ServiceTemplate.yaml index 5d93924142..ea49f9743e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_3ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_1c2_catalog_instance_3ServiceTemplate.yaml @@ -11,11 +11,72 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1c2_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_1c2_catalog_instance_availability_zone: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1c2_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1c2_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1c2_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1c2_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1c2_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_1c2_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json port_1c2_t1_port_mac_requirements: type: list required: true entry_schema: type: json + port_1c2_t1_port_network_role: + type: list + required: true + entry_schema: + type: string port_1c2_t2_port_network: type: list required: true @@ -28,19 +89,16 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - compute_1c2_catalog_instance_availability_zone: + compute_1c2_catalog_instance_name: type: list required: true entry_schema: type: string - compute_1c2_catalog_instance_name: + port_1c2_t1_port_exCP_naming: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true + type: json port_1c2_t1_port_network: type: list required: true @@ -51,10 +109,7 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string - required: true - port_1c2_t2_port_ip_requirements: + port_1c2_t2_port_vlan_requirements: type: list required: true entry_schema: @@ -106,14 +161,38 @@ topology_template: 1c2_catalog_instance_1c2_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1c2_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1c2_t2_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t2_port_order + - index_value + network_role: + get_input: + - port_1c2_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t2_port_subnetpoolid + - index_value network: get_input: - port_1c2_t2_port_network @@ -126,6 +205,14 @@ topology_template: 1c2_catalog_instance_1c2_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1c2_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1c2_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1c2_t1_port_ip_requirements @@ -138,6 +225,18 @@ topology_template: get_input: - port_1c2_t1_port_mac_requirements - index_value + order: + get_input: + - port_1c2_t1_port_order + - index_value + network_role: + get_input: + - port_1c2_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1c2_t1_port_subnetpoolid + - index_value network: get_input: - port_1c2_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_a_single_1aServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_a_single_1aServiceTemplate.yaml index 409bf1d35f..c0ea9ef793 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_a_single_1aServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_a_single_1aServiceTemplate.yaml @@ -16,6 +16,62 @@ topology_template: required: true entry_schema: type: json + port_1a_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_1a_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1a_t2_port_network: + type: list + required: true + entry_schema: + type: string + port_1a_t1_port_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_network: + type: list + required: true + entry_schema: + type: string + port_1a_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + vm_image_name: + type: string + required: true + port_1a_t2_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_1a_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json compute_a_single_1a_availability_zone: type: list required: true @@ -33,42 +89,41 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_1a_t1_port_ip_requirements: + port_1a_t1_port_network_role_tag: type: list required: true entry_schema: - type: json - port_1a_t2_port_network_role_tag: + type: string + port_1a_t1_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_1a_t1_port_order: + type: list required: true - port_1a_t2_port_network: + entry_schema: + type: integer + port_1a_t2_port_exCP_naming: type: list required: true entry_schema: - type: string - port_1a_t1_port_mac_requirements: + type: json + port_1a_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - port_1a_t1_port_network: + port_1a_t2_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_image_name: - type: string - required: true - port_1a_t2_port_ip_requirements: + port_1a_t2_port_order: type: list required: true entry_schema: - type: json + type: integer compute_a_single_1a_user_data_format: type: list required: true @@ -88,14 +143,38 @@ topology_template: a_single_1a_1a_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1a_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1a_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1a_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1a_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1a_t1_port_mac_requirements - index_value + order: + get_input: + - port_1a_t1_port_order + - index_value + network_role: + get_input: + - port_1a_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1a_t1_port_subnetpoolid + - index_value network: get_input: - port_1a_t1_port_network @@ -135,6 +214,14 @@ topology_template: a_single_1a_1a_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1a_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1a_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1a_t2_port_ip_requirements @@ -147,6 +234,18 @@ topology_template: get_input: - port_1a_t2_port_mac_requirements - index_value + order: + get_input: + - port_1a_t2_port_order + - index_value + network_role: + get_input: + - port_1a_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1a_t2_port_subnetpoolid + - index_value network: get_input: - port_1a_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_a_single_2aServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_a_single_2aServiceTemplate.yaml index cfd54f1688..800932c2ed 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_a_single_2aServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_a_single_2aServiceTemplate.yaml @@ -11,19 +11,16 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - compute_a_single_2a_name: + compute_a_single_2a_user_data_format: type: list required: true entry_schema: type: string - compute_a_single_2a_user_data_format: + port_1a_t1_port_exCP_naming: type: list required: true entry_schema: - type: string - vm_image_name: - type: string - required: true + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -36,11 +33,26 @@ topology_template: required: true entry_schema: type: json + port_1a_t1_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1a_t1_port_network_role: + type: list + required: true + entry_schema: + type: string compute_a_single_2a_scheduler_hints: type: list required: true entry_schema: type: json + port_1a_t1_port_order: + type: list + required: true + entry_schema: + type: integer compute_a_single_2a_availability_zone: type: list required: true @@ -49,21 +61,39 @@ topology_template: vm_flavor_name: type: string required: true - compute_a_single_2a_metadata: + port_1a_t1_port_mac_requirements: type: list required: true entry_schema: type: json - port_1a_t1_port_mac_requirements: + port_1a_t1_port_network: type: list required: true entry_schema: - type: json - port_1a_t1_port_network: + type: string + port_1a_t1_port_subnetpoolid: type: list required: true entry_schema: type: string + compute_a_single_2a_name: + type: list + required: true + entry_schema: + type: string + vm_image_name: + type: string + required: true + port_1a_t1_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + compute_a_single_2a_metadata: + type: list + required: true + entry_schema: + type: json node_templates: a_single_2a: type: org.openecomp.resource.vfc.nodes.heat.a_single_2a @@ -95,14 +125,38 @@ topology_template: a_single_2a_1a_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1a_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1a_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1a_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1a_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1a_t1_port_mac_requirements - index_value + order: + get_input: + - port_1a_t1_port_order + - index_value + network_role: + get_input: + - port_1a_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1a_t1_port_subnetpoolid + - index_value network: get_input: - port_1a_t1_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_1b_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_1b_0ServiceTemplate.yaml index b274d6c05d..d7831802db 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_1b_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_1b_0ServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -33,14 +89,16 @@ topology_template: required: true entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string + port_1b_t2_port_ip_requirements: + type: list required: true + entry_schema: + type: json port_1b_t1_port_value_specs: type: list required: true @@ -51,14 +109,11 @@ topology_template: required: true entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true entry_schema: - type: json - vm_image_name: - type: string - required: true + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -69,11 +124,11 @@ topology_template: required: true entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true @@ -115,6 +170,14 @@ topology_template: get_input: - port_1b_t1_port_value_specs - index_value + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements @@ -127,6 +190,18 @@ topology_template: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_input: - port_1b_t1_port_network @@ -139,14 +214,38 @@ topology_template: b_single_1b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_1b_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_1b_1ServiceTemplate.yaml index 36ead5cbaf..b80c2db770 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_1b_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_1b_1ServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + compute_b_single_1b_user_data_format: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t2_port_mac_requirements: type: list required: true @@ -33,27 +89,31 @@ topology_template: required: true entry_schema: type: json - port_1b_t2_port_ip_requirements: + port_1b_t2_port_vlan_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string - required: true - port_1b_t1_port_ip_requirements: + port_1b_t2_port_ip_requirements: type: list required: true entry_schema: type: json - vm_image_name: - type: string + port_1b_t1_port_network_role_tag: + type: list required: true + entry_schema: + type: string compute_b_single_1b_metadata: type: list required: true entry_schema: type: json + port_1b_t1_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_1b_t1_port_mac_requirements: type: list required: true @@ -64,11 +124,11 @@ topology_template: required: true entry_schema: type: string - compute_b_single_1b_user_data_format: + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: - type: string + type: json compute_b_single_1b_name: type: list required: true @@ -105,14 +165,38 @@ topology_template: b_single_1b_1b_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_attribute: - b_single_1b @@ -125,14 +209,38 @@ topology_template: b_single_1b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_2b_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_2b_0ServiceTemplate.yaml index 8fb57944db..5ce31a4d71 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_2b_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_2b_0ServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + compute_b_single_2b_scheduler_hints: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string compute_b_single_2b_availability_zone: type: list required: true @@ -28,6 +84,11 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_1b_t2_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_1b_t2_port_ip_requirements: type: list required: true @@ -38,9 +99,6 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string - required: true port_1b_t1_port_value_specs: type: list required: true @@ -56,29 +114,26 @@ topology_template: required: true entry_schema: type: string - port_1b_t1_port_ip_requirements: + port_1b_t1_port_subnetpoolid: type: list required: true entry_schema: - type: json - vm_image_name: - type: string - required: true + type: string port_1b_t1_port_mac_requirements: type: list required: true entry_schema: type: json - compute_b_single_2b_scheduler_hints: + port_1b_t2_port_network: type: list required: true entry_schema: - type: json - port_1b_t2_port_network: + type: string + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: - type: string + type: json port_1b_t1_port_network: type: list required: true @@ -115,6 +170,14 @@ topology_template: get_input: - port_1b_t1_port_value_specs - index_value + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements @@ -127,6 +190,18 @@ topology_template: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_input: - port_1b_t1_port_network @@ -139,14 +214,38 @@ topology_template: b_single_2b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_2b_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_2b_1ServiceTemplate.yaml index f867345250..a8680d8869 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_2b_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/Nested_b_single_2b_1ServiceTemplate.yaml @@ -11,6 +11,67 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_1b_t1_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t1_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t1_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + compute_b_single_2b_metadata: + type: list + required: true + entry_schema: + type: json + port_1b_t1_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + compute_b_single_2b_scheduler_hints: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_order: + type: list + required: true + entry_schema: + type: integer + port_1b_t2_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_1b_t2_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_1b_t2_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string compute_b_single_2b_availability_zone: type: list required: true @@ -28,6 +89,11 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_1b_t2_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_1b_t2_port_ip_requirements: type: list required: true @@ -38,42 +104,36 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string - required: true compute_b_single_2b_user_data_format: type: list required: true entry_schema: type: string - compute_b_single_2b_metadata: + port_1b_t1_port_network_role_tag: type: list required: true entry_schema: - type: json - port_1b_t1_port_ip_requirements: + type: string + port_1b_t1_port_subnetpoolid: type: list required: true entry_schema: - type: json - vm_image_name: - type: string - required: true + type: string port_1b_t1_port_mac_requirements: type: list required: true entry_schema: type: json - compute_b_single_2b_scheduler_hints: + port_1b_t2_port_network: type: list required: true entry_schema: - type: json - port_1b_t2_port_network: + type: string + port_1b_t1_port_vlan_requirements: type: list required: true entry_schema: - type: string + type: json node_templates: b_single_2b: type: org.openecomp.resource.vfc.nodes.heat.b_single_2b @@ -105,14 +165,38 @@ topology_template: b_single_2b_1b_t1_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t1_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t1_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t1_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t1_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t1_port_mac_requirements - index_value + order: + get_input: + - port_1b_t1_port_order + - index_value + network_role: + get_input: + - port_1b_t1_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t1_port_subnetpoolid + - index_value network: get_attribute: - b_single_2b @@ -125,14 +209,38 @@ topology_template: b_single_2b_1b_t2_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_1b_t2_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_1b_t2_port_vlan_requirements + - index_value ip_requirements: get_input: - port_1b_t2_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_1b_t2_port_network_role_tag + - index_value mac_requirements: get_input: - port_1b_t2_port_mac_requirements - index_value + order: + get_input: + - port_1b_t2_port_order + - index_value + network_role: + get_input: + - port_1b_t2_port_network_role + - index_value + subnetpoolid: + get_input: + - port_1b_t2_port_subnetpoolid + - index_value network: get_input: - port_1b_t2_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/nested-pcm_v0.1ServiceTemplate.yaml index d6dd992034..a8e64880b2 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/mixPatterns/twoAppearancePerPatternWithConnectivities/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,32 +11,90 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - server_group: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string + availabilityzone_name: + label: availabilityzone name hidden: false immutable: false type: string - connectivityChk: + description: availabilityzone name + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json + pcm_image_name: + label: image name hidden: false immutable: false - type: json - availabilityzone_name: - label: availabilityzone name + type: string + description: PCRF CM image name + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + pcm_server_name: + label: PCRF CM server name hidden: false immutable: false type: string - description: availabilityzone name - oam_net_gw: - label: CPS network gateway + description: PCRF CM server name + cps_net_mask: + label: CPS network mask hidden: false immutable: false type: string - description: CPS network gateway - pcm_image_name: - label: image name + description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + oam_net_name: + label: OAM network name hidden: false immutable: false type: string - description: PCRF CM image name + description: OAM network name + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string + server_group: + hidden: false + immutable: false + type: string + connectivityChk: + hidden: false + immutable: false + type: json + oam_net_gw: + label: CPS network gateway + hidden: false + immutable: false + type: string + description: CPS network gateway security_group_name: label: security group name hidden: false @@ -49,6 +107,11 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false @@ -61,24 +124,12 @@ topology_template: immutable: false type: string description: CPS Cluman Cinder Volume - pcm_server_name: - label: PCRF CM server name - hidden: false - immutable: false - type: string - description: PCRF CM server name cps_net_name: label: CPS network name hidden: false immutable: false type: string description: CPS network name - cps_net_mask: - label: CPS network mask - hidden: false - immutable: false - type: string - description: CPS network mask oam_net_ip: label: OAM network ip hidden: false @@ -91,12 +142,11 @@ topology_template: immutable: false type: string description: CPS network mask - oam_net_name: - label: OAM network name - hidden: false - immutable: false - type: string - description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -109,15 +159,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -150,15 +220,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml index 0138bf7b61..1155109ae9 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -18,6 +24,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -33,11 +45,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -68,11 +104,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string @@ -495,6 +555,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -505,6 +571,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -520,11 +592,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -555,11 +651,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml index 1ab6da631d..1a50030cb0 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -41,12 +51,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -101,15 +151,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -139,15 +209,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/nested-pcm_v0.2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/nested-pcm_v0.2ServiceTemplate.yaml index a5e41ea4fa..e75b827856 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/nested-pcm_v0.2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/diffNestedFilesWithSameComputeType/out/nested-pcm_v0.2ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -41,12 +51,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -101,15 +151,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -139,15 +209,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedMultiLevels/out/Nested_jsaServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedMultiLevels/out/Nested_jsaServiceTemplate.yaml new file mode 100644 index 0000000000..80fe6dec9c --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedMultiLevels/out/Nested_jsaServiceTemplate.yaml @@ -0,0 +1,171 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +metadata: + template_name: Nested_jsa +imports: +- openecomp_heat_index: + file: openecomp-heat/_index.yml +- GlobalSubstitutionTypes: + file: GlobalSubstitutionTypesServiceTemplate.yaml +node_types: + org.openecomp.resource.vfc.nodes.heat.jsa: + derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server +topology_template: + inputs: + compute_jsa_name: + type: list + required: true + entry_schema: + type: string + vm_image_name: + type: string + required: true + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + node_templates: + jsa: + type: org.openecomp.resource.vfc.nodes.heat.jsa + properties: + image: + get_input: vm_image_name + name: + get_input: + - compute_jsa_name + - index_value + substitution_mappings: + node_type: org.openecomp.resource.abstract.nodes.jsa + capabilities: + instance_jsa: + - jsa + - instance + disk.latency_jsa: + - jsa + - disk.latency + disk.device.usage_jsa: + - jsa + - disk.device.usage + disk.iops_jsa: + - jsa + - disk.iops + disk.read.bytes.rate_jsa: + - jsa + - disk.read.bytes.rate + disk.device.allocation_jsa: + - jsa + - disk.device.allocation + disk.write.bytes.rate_jsa: + - jsa + - disk.write.bytes.rate + disk.ephemeral.size_jsa: + - jsa + - disk.ephemeral.size + cpu_util_jsa: + - jsa + - cpu_util + disk.device.write.bytes.rate_jsa: + - jsa + - disk.device.write.bytes.rate + disk.read.bytes_jsa: + - jsa + - disk.read.bytes + disk.capacity_jsa: + - jsa + - disk.capacity + disk.write.bytes_jsa: + - jsa + - disk.write.bytes + memory.usage_jsa: + - jsa + - memory.usage + disk.device.read.bytes.rate_jsa: + - jsa + - disk.device.read.bytes.rate + disk.device.capacity_jsa: + - jsa + - disk.device.capacity + disk.device.read.requests_jsa: + - jsa + - disk.device.read.requests + endpoint_jsa: + - jsa + - endpoint + disk.read.requests_jsa: + - jsa + - disk.read.requests + memory.resident_jsa: + - jsa + - memory.resident + disk.device.write.requests.rate_jsa: + - jsa + - disk.device.write.requests.rate + scalable_jsa: + - jsa + - scalable + feature_jsa: + - jsa + - feature + cpu_jsa: + - jsa + - cpu + disk.usage_jsa: + - jsa + - disk.usage + disk.write.requests_jsa: + - jsa + - disk.write.requests + memory_jsa: + - jsa + - memory + disk.device.write.bytes_jsa: + - jsa + - disk.device.write.bytes + disk.root.size_jsa: + - jsa + - disk.root.size + cpu.delta_jsa: + - jsa + - cpu.delta + disk.device.write.requests_jsa: + - jsa + - disk.device.write.requests + disk.device.read.requests.rate_jsa: + - jsa + - disk.device.read.requests.rate + os_jsa: + - jsa + - os + disk.allocation_jsa: + - jsa + - disk.allocation + binding_jsa: + - jsa + - binding + disk.device.read.bytes_jsa: + - jsa + - disk.device.read.bytes + host_jsa: + - jsa + - host + disk.device.latency_jsa: + - jsa + - disk.device.latency + vcpus_jsa: + - jsa + - vcpus + disk.device.iops_jsa: + - jsa + - disk.device.iops + disk.write.requests.rate_jsa: + - jsa + - disk.write.requests.rate + requirements: + local_storage_jsa: + - jsa + - local_storage + dependency_jsa: + - jsa + - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index 45251124c8..a0430c354b 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string p1: type: string description: UID of OAM network @@ -23,16 +29,73 @@ node_types: description: availabilityzone name required: true status: SUPPORTED - oam_net_gw: - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + pcm_server_name: + type: string + description: PCRF CM server name + required: true + status: SUPPORTED + cps_net_mask: + type: string + description: CPS network mask + required: true + status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + oam_net_name: + type: string + description: OAM network name + required: true + status: SUPPORTED + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + oam_net_gw: + type: string + description: CPS network gateway + required: true + status: SUPPORTED security_group_name: type: string description: the name of security group @@ -43,6 +106,12 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance @@ -53,21 +122,11 @@ node_types: description: CPS Cluman Cinder Volume required: true status: SUPPORTED - pcm_server_name: - type: string - description: PCRF CM server name - required: true - status: SUPPORTED cps_net_name: type: string description: CPS network name required: true status: SUPPORTED - cps_net_mask: - type: string - description: CPS network mask - required: true - status: SUPPORTED oam_net_ip: type: string description: OAM network ip @@ -78,11 +137,12 @@ node_types: description: CPS network mask required: true status: SUPPORTED - oam_net_name: - type: string - description: OAM network name + port_pcm_port_1_order: + type: list required: true status: SUPPORTED + entry_schema: + type: integer attributes: server_pcm_id: type: string @@ -510,11 +570,67 @@ node_types: description: UID of OAM network required: true status: SUPPORTED + port_oam_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name required: true status: SUPPORTED + port_oam_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + oam_server_name: + type: string + description: oam server name + required: true + status: SUPPORTED + port_oam_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_oam_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_oam_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_oam_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + oam_image_name: + type: string + description: oam image name + required: true + status: SUPPORTED + cps_net_mask: + type: string + description: CPS network mask + required: true + status: SUPPORTED + oam_net_name: + type: string + description: OAM network name + required: true + status: SUPPORTED oam_net_gw: type: string description: CPS network gateway @@ -535,29 +651,38 @@ node_types: description: CPS network ip required: true status: SUPPORTED - oam_server_name: - type: string - description: oam server name + port_oam_port_0_order: + type: list required: true status: SUPPORTED - pcm_vol: - type: string - description: CPS Cluman Cinder Volume + entry_schema: + type: integer + port_oam_port_0_vlan_requirements: + type: list required: true status: SUPPORTED - oam_image_name: - type: string - description: oam image name + entry_schema: + type: json + port_oam_port_1_exCP_naming: + type: list required: true status: SUPPORTED - cps_net_name: + entry_schema: + type: json + port_oam_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + pcm_vol: type: string - description: CPS network name + description: CPS Cluman Cinder Volume required: true status: SUPPORTED - cps_net_mask: + cps_net_name: type: string - description: CPS network mask + description: CPS network name required: true status: SUPPORTED oam_net_ip: @@ -575,11 +700,6 @@ node_types: description: UID of OAM network required: true status: SUPPORTED - oam_net_name: - type: string - description: OAM network name - required: true - status: SUPPORTED attributes: server_oam_id: type: string diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/nested-oam_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/nested-oam_v0.1ServiceTemplate.yaml index 007006b550..2decadf3c7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/nested-oam_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/nested-oam_v0.1ServiceTemplate.yaml @@ -16,12 +16,66 @@ topology_template: immutable: false type: string description: UID of OAM network + port_oam_port_1_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false immutable: false type: string description: availabilityzone name + port_oam_port_0_network_role: + type: list + required: true + entry_schema: + type: string + oam_server_name: + label: oam server name + hidden: false + immutable: false + type: string + description: oam server name + port_oam_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_oam_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_oam_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_oam_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + oam_image_name: + label: image name + hidden: false + immutable: false + type: string + description: oam image name + cps_net_mask: + label: CPS network mask + hidden: false + immutable: false + type: string + description: CPS network mask + oam_net_name: + label: OAM network name + hidden: false + immutable: false + type: string + description: OAM network name oam_net_gw: label: CPS network gateway hidden: false @@ -46,36 +100,38 @@ topology_template: immutable: false type: string description: CPS network ip - oam_server_name: - label: oam server name - hidden: false - immutable: false - type: string - description: oam server name + port_oam_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_oam_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_oam_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_oam_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json pcm_vol: label: CPS Cluman Cinder Volume hidden: false immutable: false type: string description: CPS Cluman Cinder Volume - oam_image_name: - label: image name - hidden: false - immutable: false - type: string - description: oam image name cps_net_name: label: CPS network name hidden: false immutable: false type: string description: CPS network name - cps_net_mask: - label: CPS network mask - hidden: false - immutable: false - type: string - description: CPS network mask oam_net_ip: label: OAM network ip hidden: false @@ -93,12 +149,6 @@ topology_template: immutable: false type: string description: UID of OAM network - oam_net_name: - label: OAM network name - hidden: false - immutable: false - type: string - description: OAM network name node_templates: oam_port_0: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -111,15 +161,35 @@ topology_template: is_required: false security_groups: - get_input: shared_security_group_id1 + network_role: + get_input: + - port_oam_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_oam_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_oam_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_oam_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_oam_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -149,15 +219,35 @@ topology_template: security_groups: - get_input: shared_security_group_id1 - get_input: security_group_name + network_role: + get_input: + - port_oam_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_oam_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_oam_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_oam_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_oam_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/nested-pcm_v0.1ServiceTemplate.yaml index 458a0e54bb..b07c726b57 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesConnectedIn/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string p1: hidden: false immutable: false @@ -27,18 +32,71 @@ topology_template: immutable: false type: string description: availabilityzone name - oam_net_gw: - label: CPS network gateway - hidden: false - immutable: false - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false immutable: false type: string description: PCRF CM image name + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + pcm_server_name: + label: PCRF CM server name + hidden: false + immutable: false + type: string + description: PCRF CM server name + cps_net_mask: + label: CPS network mask + hidden: false + immutable: false + type: string + description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + oam_net_name: + label: OAM network name + hidden: false + immutable: false + type: string + description: OAM network name + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string + oam_net_gw: + label: CPS network gateway + hidden: false + immutable: false + type: string + description: CPS network gateway security_group_name: label: security group name hidden: false @@ -51,6 +109,11 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false @@ -63,24 +126,12 @@ topology_template: immutable: false type: string description: CPS Cluman Cinder Volume - pcm_server_name: - label: PCRF CM server name - hidden: false - immutable: false - type: string - description: PCRF CM server name cps_net_name: label: CPS network name hidden: false immutable: false type: string description: CPS network name - cps_net_mask: - label: CPS network mask - hidden: false - immutable: false - type: string - description: CPS network mask oam_net_ip: label: OAM network ip hidden: false @@ -93,12 +144,11 @@ topology_template: immutable: false type: string description: CPS network mask - oam_net_name: - label: OAM network name - hidden: false - immutable: false - type: string - description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -111,15 +161,35 @@ topology_template: is_required: false security_groups: - get_input: p1 + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -150,15 +220,35 @@ topology_template: security_groups: - get_input: p1 - get_input: p2 + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index 0e171ac23c..7fe923c53b 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string metadata: type: string description: metadata @@ -18,16 +24,73 @@ node_types: description: availabilityzone name required: true status: SUPPORTED - oam_net_gw: - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + pcm_server_name: + type: string + description: PCRF CM server name + required: true + status: SUPPORTED + cps_net_mask: + type: string + description: CPS network mask + required: true + status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + oam_net_name: + type: string + description: OAM network name + required: true + status: SUPPORTED + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + oam_net_gw: + type: string + description: CPS network gateway + required: true + status: SUPPORTED security_group_name: type: string description: the name of security group @@ -38,6 +101,12 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance @@ -58,21 +127,11 @@ node_types: description: CPS Cluman Cinder Volume required: true status: SUPPORTED - pcm_server_name: - type: string - description: PCRF CM server name - required: true - status: SUPPORTED cps_net_name: type: string description: CPS network name required: true status: SUPPORTED - cps_net_mask: - type: string - description: CPS network mask - required: true - status: SUPPORTED oam_net_ip: type: string description: OAM network ip @@ -83,11 +142,12 @@ node_types: description: CPS network mask required: true status: SUPPORTED - oam_net_name: - type: string - description: OAM network name + port_pcm_port_1_order: + type: list required: true status: SUPPORTED + entry_schema: + type: integer attributes: server_pcm_id: type: string @@ -510,6 +570,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.oam_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -520,6 +586,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_flavor_name: type: string description: flavor name of PCRF CM instance @@ -540,6 +612,30 @@ node_types: description: oam server name required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -570,11 +666,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_oam_id: type: string diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/nested-oam_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/nested-oam_v0.1ServiceTemplate.yaml index 0a5403054a..2c29cb26d5 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/nested-oam_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/nested-oam_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json oam_flavor_name: label: PCRF CM flavor name hidden: false @@ -47,6 +57,26 @@ topology_template: immutable: false type: string description: oam server name + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: server_oam: type: org.openecomp.resource.vfc.nodes.heat.oam_server @@ -113,15 +163,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -138,15 +208,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/nested-pcm_v0.1ServiceTemplate.yaml index a9df9055cd..26cd09769f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedNodesGetAttrIn/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string metadata: label: metadata hidden: false @@ -23,18 +28,71 @@ topology_template: immutable: false type: string description: availabilityzone name - oam_net_gw: - label: CPS network gateway - hidden: false - immutable: false - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false immutable: false type: string description: PCRF CM image name + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + pcm_server_name: + label: PCRF CM server name + hidden: false + immutable: false + type: string + description: PCRF CM server name + cps_net_mask: + label: CPS network mask + hidden: false + immutable: false + type: string + description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + oam_net_name: + label: OAM network name + hidden: false + immutable: false + type: string + description: OAM network name + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string + oam_net_gw: + label: CPS network gateway + hidden: false + immutable: false + type: string + description: CPS network gateway security_group_name: label: security group name hidden: false @@ -47,6 +105,11 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false @@ -71,24 +134,12 @@ topology_template: immutable: false type: string description: CPS Cluman Cinder Volume - pcm_server_name: - label: PCRF CM server name - hidden: false - immutable: false - type: string - description: PCRF CM server name cps_net_name: label: CPS network name hidden: false immutable: false type: string description: CPS network name - cps_net_mask: - label: CPS network mask - hidden: false - immutable: false - type: string - description: CPS network mask oam_net_ip: label: OAM network ip hidden: false @@ -101,12 +152,11 @@ topology_template: immutable: false type: string description: CPS network mask - oam_net_name: - label: OAM network name - hidden: false - immutable: false - type: string - description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -119,15 +169,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -157,15 +227,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index 98d483a970..70506fc553 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string metadata: type: string description: metadata @@ -18,16 +24,73 @@ node_types: description: availabilityzone name required: true status: SUPPORTED - oam_net_gw: - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + pcm_server_name: + type: string + description: PCRF CM server name + required: true + status: SUPPORTED + cps_net_mask: + type: string + description: CPS network mask + required: true + status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + oam_net_name: + type: string + description: OAM network name + required: true + status: SUPPORTED + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + oam_net_gw: + type: string + description: CPS network gateway + required: true + status: SUPPORTED security_group_name: type: string description: the name of security group @@ -38,6 +101,12 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance @@ -53,21 +122,11 @@ node_types: description: CPS Cluman Cinder Volume required: true status: SUPPORTED - pcm_server_name: - type: string - description: PCRF CM server name - required: true - status: SUPPORTED cps_net_name: type: string description: CPS network name required: true status: SUPPORTED - cps_net_mask: - type: string - description: CPS network mask - required: true - status: SUPPORTED oam_net_ip: type: string description: OAM network ip @@ -78,11 +137,12 @@ node_types: description: CPS network mask required: true status: SUPPORTED - oam_net_name: - type: string - description: OAM network name + port_pcm_port_1_order: + type: list required: true status: SUPPORTED + entry_schema: + type: integer attributes: server_pcm_id: type: string @@ -505,6 +565,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.oam_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -515,6 +581,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_flavor_name: type: string description: flavor name of PCRF CM instance @@ -535,6 +607,30 @@ node_types: description: oam server name required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -565,11 +661,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_oam_id: type: string diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/nested-oam_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/nested-oam_v0.1ServiceTemplate.yaml index 0a5403054a..2c29cb26d5 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/nested-oam_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/nested-oam_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json oam_flavor_name: label: PCRF CM flavor name hidden: false @@ -47,6 +57,26 @@ topology_template: immutable: false type: string description: oam server name + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: server_oam: type: org.openecomp.resource.vfc.nodes.heat.oam_server @@ -113,15 +163,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -138,15 +208,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/nested-pcm_v0.1ServiceTemplate.yaml index 102cd3617d..ac4560a682 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedOutputParamGetAttrIn/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string metadata: label: metadata hidden: false @@ -23,18 +28,71 @@ topology_template: immutable: false type: string description: availabilityzone name - oam_net_gw: - label: CPS network gateway - hidden: false - immutable: false - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false immutable: false type: string description: PCRF CM image name + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + pcm_server_name: + label: PCRF CM server name + hidden: false + immutable: false + type: string + description: PCRF CM server name + cps_net_mask: + label: CPS network mask + hidden: false + immutable: false + type: string + description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + oam_net_name: + label: OAM network name + hidden: false + immutable: false + type: string + description: OAM network name + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string + oam_net_gw: + label: CPS network gateway + hidden: false + immutable: false + type: string + description: CPS network gateway security_group_name: label: security group name hidden: false @@ -47,6 +105,11 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false @@ -65,24 +128,12 @@ topology_template: immutable: false type: string description: CPS Cluman Cinder Volume - pcm_server_name: - label: PCRF CM server name - hidden: false - immutable: false - type: string - description: PCRF CM server name cps_net_name: label: CPS network name hidden: false immutable: false type: string description: CPS network name - cps_net_mask: - label: CPS network mask - hidden: false - immutable: false - type: string - description: CPS network mask oam_net_ip: label: OAM network ip hidden: false @@ -95,12 +146,11 @@ topology_template: immutable: false type: string description: CPS network mask - oam_net_name: - label: OAM network name - hidden: false - immutable: false - type: string - description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -113,15 +163,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -151,15 +221,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneCompute/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneCompute/out/GlobalSubstitutionTypesServiceTemplate.yaml index 0f6c0e9f7a..fa86dbe5ce 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneCompute/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneCompute/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -18,6 +24,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -33,11 +45,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -68,11 +104,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneCompute/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneCompute/out/nested-pcm_v0.1ServiceTemplate.yaml index 05a21ce6d1..51429041fe 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneCompute/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneCompute/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -41,12 +51,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -101,15 +151,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -139,15 +209,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/MANIFEST.json b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/MANIFEST.json new file mode 100644 index 0000000000..609c38b28e --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/MANIFEST.json @@ -0,0 +1,21 @@ +{ + "name": "vEP_JSA_Net", + "description": "Version 2.0 02-09-2016 (Authors: John Doe, user PROD)", + "version": "2013-05-23", + "data": [ + { + "file": "hot-nimbus-pcm_v0.4.yaml", + "type": "HEAT", + "data": [ + { + "file": "hot-nimbus-pcm_v0.4.env", + "type": "HEAT_ENV" + } + ] + }, + { + "file": "nested-pcm_v0.1.yaml", + "type": "HEAT" + } + ] +} \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/hot-nimbus-pcm_v0.4.env b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/hot-nimbus-pcm_v0.4.env new file mode 100644 index 0000000000..78cc03e2ea --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/hot-nimbus-pcm_v0.4.env @@ -0,0 +1,14 @@ +parameters: + pcm_server_names: ZRDM1PCRF01PCM001 + pcm_image_name: rhel2 + pcm_flavor_name: cps + availabilityzone_name: nova + cps_net_name: int_pcrf_net_0 + cps_net_ips: 172.26.16.113 + cps_net_mask: 255.255.255.0 + oam_net_name: oam_protected_net_0 + oam_net_ips: 107.239.64.121 + oam_net_gw: 107.239.64.1 + oam_net_mask: 255.255.255.0 + pcm_volumes: 249cb355-8fdf-4382-9c3c-a2ebe767d45b + security_group_name: nimbus_security_group diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/hot-nimbus-pcm_v0.4.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/hot-nimbus-pcm_v0.4.yaml new file mode 100644 index 0000000000..dea5d4296c --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/hot-nimbus-pcm_v0.4.yaml @@ -0,0 +1,103 @@ +heat_template_version: 2013-05-23 + +description: heat template that creates PCRF Cluman stack + +parameters: + pcm_server_names: + type: comma_delimited_list + label: PCRF CM server names + description: name of the PCRF CM instance + pcm_image_name: + type: string + label: PCRF CM image name + description: PCRF CM image name + pcm_flavor_name: + type: string + label: PCRF CM flavor name + description: flavor name of PCRF CM instance + availabilityzone_name: + type: string + label: availabilityzone name + description: availabilityzone name + cps_net_name: + type: string + label: CPS network name + description: CPS network name + cps_net_ips: + type: comma_delimited_list + label: CPS network ips + description: CPS network ips + cps_net_mask: + type: string + label: CPS network mask + description: CPS network mask + oam_net_name: + type: string + label: OAM network name + description: OAM network name + oam_net_ips: + type: comma_delimited_list + label: OAM network ips + description: OAM network ips + oam_net_gw: + type: string + label: CPS network gateway + description: CPS network gateway + oam_net_mask: + type: string + label: CPS network mask + description: CPS network mask + pcm_volumes: + type: comma_delimited_list + label: CPS Cluman Cinder Volume + description: CPS Cluman Cinder Volume + security_group_name: + type: string + label: security group name + description: the name of security group + compute_image_name: + type: string + net_name: + type: string + +resources: + server_pcm_001: + type: nested-pcm_v0.1.yaml + properties: + pcm_server_name: { get_param: [pcm_server_names, 0] } + pcm_image_name: { get_param: pcm_image_name } + pcm_flavor_name: { get_param: pcm_flavor_name } + availabilityzone_name: { get_param: availabilityzone_name } + security_group_name: { get_param: security_group_name } + pcm_vol: { get_param: [pcm_volumes, 0] } + cps_net_name: { get_param: cps_net_name } + cps_net_ip: { get_param: [cps_net_ips, 0] } + cps_net_mask: { get_param: cps_net_mask } + oam_net_name: { get_param: oam_net_name } + oam_net_ip: { get_param: [oam_net_ips, 0] } + oam_net_mask: { get_param: oam_net_mask } + oam_net_gw: { get_param: oam_net_gw } + + server_compute: + type: OS::Nova::Server + properties: + config_drive: {get_attr: [compute_port_0]} + name: { compute_name } + image: { get_param: compute_image_name } + flavor: { compute_flavor_name } + user_data_format: { get_attr: [server_pcm_001 , oam_net_gw] } + metadata: { get_attr: [server_pcm_001]} + + compute_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: net_name } + + packet_mirror_network: + type: OS::Neutron::Net + depends_on: + - server_pcm_001 + properties: + name: + get_param: net_name + diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/nested-pcm_v0.1.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/nested-pcm_v0.1.yaml new file mode 100644 index 0000000000..be8cb80777 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/in/nested-pcm_v0.1.yaml @@ -0,0 +1,101 @@ +heat_template_version: 2013-05-23 + +description: heat template that creates PCRF Cluman stack + +parameters: + pcm_server_name: + type: string + label: PCRF CM server name + description: PCRF CM server name + pcm_image_name: + type: string + label: image name + description: PCRF CM image name + pcm_flavor_name: + type: string + label: PCRF CM flavor name + description: flavor name of PCRF CM instance + availabilityzone_name: + type: string + label: availabilityzone name + description: availabilityzone name + cps_net_name: + type: string + label: CPS network name + description: CPS network name + cps_net_ip: + type: string + label: CPS network ip + description: CPS network ip + cps_net_mask: + type: string + label: CPS network mask + description: CPS network mask + oam_net_name: + type: string + label: OAM network name + description: OAM network name + oam_net_ip: + type: string + label: OAM network ip + description: OAM network ip + oam_net_gw: + type: string + label: CPS network gateway + description: CPS network gateway + oam_net_mask: + type: string + label: CPS network mask + description: CPS network mask + pcm_vol: + type: string + label: CPS Cluman Cinder Volume + description: CPS Cluman Cinder Volume + security_group_name: + type: string + label: security group name + description: the name of security group + +resources: + server_pcm: + type: OS::Nova::Server + properties: + config_drive: "True" + name: { get_param: pcm_server_name } + image: { get_param: pcm_image_name } + flavor: { get_param: pcm_flavor_name } + availability_zone: { get_param: availabilityzone_name } + networks: + - port: { get_resource: pcm_1port_0} + - port: { get_resource: pcm_2port_1} + block_device_mapping: + - device_name: vdb + volume_id: { get_param: pcm_vol} + user_data_format: RAW + + pcm_1port_0: + type: OS::Neutron::Port + properties: + network: { get_param: cps_net_name } + fixed_ips: + - ip_address: { get_param: cps_net_ip } + security_groups: [{ get_param: security_group_name }] + + pcm_2port_1: + type: OS::Neutron::Port + properties: + network: { get_param: oam_net_name } + fixed_ips: + - ip_address: { get_param: oam_net_ip } + security_groups: [{ get_param: security_group_name }] + + #pcm_vol_attachment: + # type: OS::Cinder::VolumeAttachment + # properties: + # volume_id: { get_param: pcm_vol } + # mountpoint: /dev/vdb + # instance_uuid: { get_resource: server_pcm } +outputs: + server_pcm_id: + description: the pcm nova service id + value: { get_resource: server_pcm } \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/GlobalSubstitutionTypesServiceTemplate.yaml new file mode 100644 index 0000000000..670f8d23ae --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -0,0 +1,855 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +metadata: + template_name: GlobalSubstitutionTypes +imports: +- openecomp_heat_index: + file: openecomp-heat/_index.yml +node_types: + org.openecomp.resource.abstract.nodes.heat.pcm_server: + derived_from: org.openecomp.resource.abstract.nodes.VFC + properties: + availabilityzone_name: + type: string + description: availabilityzone name + required: true + status: SUPPORTED + port_pcm_2port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + oam_net_gw: + type: string + description: CPS network gateway + required: true + status: SUPPORTED + pcm_image_name: + type: string + description: PCRF CM image name + required: true + status: SUPPORTED + port_pcm_1port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_1port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + security_group_name: + type: string + description: the name of security group + required: true + status: SUPPORTED + port_pcm_1port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + cps_net_ip: + type: string + description: CPS network ip + required: true + status: SUPPORTED + port_pcm_2port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + pcm_flavor_name: + type: string + description: flavor name of PCRF CM instance + required: true + status: SUPPORTED + port_pcm_2port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + pcm_vol: + type: string + description: CPS Cluman Cinder Volume + required: true + status: SUPPORTED + port_pcm_1port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_1port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + pcm_server_name: + type: string + description: PCRF CM server name + required: true + status: SUPPORTED + cps_net_name: + type: string + description: CPS network name + required: true + status: SUPPORTED + cps_net_mask: + type: string + description: CPS network mask + required: true + status: SUPPORTED + oam_net_ip: + type: string + description: OAM network ip + required: true + status: SUPPORTED + oam_net_mask: + type: string + description: CPS network mask + required: true + status: SUPPORTED + oam_net_name: + type: string + description: OAM network name + required: true + status: SUPPORTED + port_pcm_2port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_2port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + attributes: + server_pcm_id: + type: string + description: the pcm nova service id + status: SUPPORTED + requirements: + - dependency_server_pcm: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - local_storage_server_pcm: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: + - 0 + - UNBOUNDED + - dependency_pcm_1port_0: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - link_pcm_1port_0: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo + occurrences: + - 1 + - 1 + - dependency_pcm_2port_1: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - link_pcm_2port_1: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo + occurrences: + - 1 + - 1 + capabilities: + binding_pcm_2port_1: + type: tosca.capabilities.network.Bindable + valid_source_types: + - org.openecomp.resource.cp.nodes.heat.network.contrailV2.VLANSubInterface + occurrences: + - 0 + - UNBOUNDED + cpu_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + attachment_pcm_2port_1: + type: tosca.capabilities.Attachment + occurrences: + - 1 + - UNBOUNDED + network.outgoing.bytes.rate_pcm_2port_1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + memory_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.write.requests_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.incoming.bytes_pcm_2port_1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + feature_pcm_1port_0: + type: tosca.capabilities.Node + occurrences: + - 1 + - UNBOUNDED + network.incoming.packets.rate_pcm_2port_1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.outpoing.packets_pcm_2port_1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.iops_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + memory.resident_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.write.requests_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.outgoing.packets.rate_pcm_2port_1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.usage_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.allocation_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.incoming.packets_pcm_2port_1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.outpoing.packets_pcm_1port_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.usage_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.write.bytes_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.root.size_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.ephemeral.size_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.latency_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.incoming.bytes_pcm_1port_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + memory.usage_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.read.requests_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.capacity_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + os_server_pcm: + type: tosca.capabilities.OperatingSystem + occurrences: + - 1 + - UNBOUNDED + disk.read.bytes_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.read.bytes_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.incoming.packets_pcm_1port_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + endpoint_server_pcm: + type: tosca.capabilities.Endpoint.Admin + occurrences: + - 1 + - UNBOUNDED + disk.device.read.requests.rate_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + vcpus_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.write.bytes_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.iops_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.incoming.bytes.rate_pcm_1port_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.read.bytes.rate_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.allocation_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.incoming.packets.rate_pcm_1port_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + feature_pcm_2port_1: + type: tosca.capabilities.Node + occurrences: + - 1 + - UNBOUNDED + scalable_server_pcm: + type: tosca.capabilities.Scalable + occurrences: + - 1 + - UNBOUNDED + network.outgoing.bytes.rate_pcm_1port_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.outgoing.bytes_pcm_2port_1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.read.bytes.rate_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + cpu_util_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + attachment_pcm_1port_0: + type: tosca.capabilities.Attachment + occurrences: + - 1 + - UNBOUNDED + disk.write.requests.rate_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.incoming.bytes.rate_pcm_2port_1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.write.bytes.rate_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + host_server_pcm: + type: tosca.capabilities.Container + valid_source_types: + - tosca.nodes.SoftwareComponent + occurrences: + - 1 + - UNBOUNDED + network.outgoing.bytes_pcm_1port_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + binding_pcm_1port_0: + type: tosca.capabilities.network.Bindable + valid_source_types: + - org.openecomp.resource.cp.nodes.heat.network.contrailV2.VLANSubInterface + occurrences: + - 0 + - UNBOUNDED + cpu.delta_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + network.outgoing.packets.rate_pcm_1port_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + binding_server_pcm: + type: tosca.capabilities.network.Bindable + occurrences: + - 1 + - UNBOUNDED + disk.device.capacity_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + instance_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.write.requests.rate_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.latency_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.read.requests_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + feature_server_pcm: + type: tosca.capabilities.Node + occurrences: + - 1 + - UNBOUNDED + disk.write.bytes.rate_server_pcm: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + org.openecomp.resource.abstract.nodes.compute: + derived_from: org.openecomp.resource.abstract.nodes.VFC + properties: + compute_compute_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_image_name: + type: string + required: true + status: SUPPORTED + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_compute_metadata: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + compute_compute_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + compute_compute_config_drive: + type: list + required: true + status: SUPPORTED + entry_schema: + type: boolean + requirements: + - dependency_compute: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - local_storage_compute: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: + - 0 + - UNBOUNDED + capabilities: + disk.device.usage_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.write.requests_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + instance_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.ephemeral.size_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.read.bytes.rate_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.latency_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + memory.resident_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + memory_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.iops_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.root.size_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.write.requests.rate_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.read.requests_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.read.requests.rate_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.read.bytes_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.read.bytes_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.write.bytes_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.usage_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + os_compute: + type: tosca.capabilities.OperatingSystem + occurrences: + - 1 + - UNBOUNDED + disk.write.bytes.rate_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + vcpus_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.capacity_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + cpu_util_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.read.bytes.rate_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.latency_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.write.requests_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.iops_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.write.requests.rate_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + endpoint_compute: + type: tosca.capabilities.Endpoint.Admin + occurrences: + - 1 + - UNBOUNDED + memory.usage_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + host_compute: + type: tosca.capabilities.Container + valid_source_types: + - tosca.nodes.SoftwareComponent + occurrences: + - 1 + - UNBOUNDED + feature_compute: + type: tosca.capabilities.Node + occurrences: + - 1 + - UNBOUNDED + disk.device.write.bytes_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + cpu_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.write.bytes.rate_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + scalable_compute: + type: tosca.capabilities.Scalable + occurrences: + - 1 + - UNBOUNDED + disk.device.read.requests_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.allocation_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.capacity_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.allocation_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + cpu.delta_compute: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + binding_compute: + type: tosca.capabilities.network.Bindable + occurrences: + - 1 + - UNBOUNDED \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/MainServiceTemplate.yaml new file mode 100644 index 0000000000..03d069f43d --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/MainServiceTemplate.yaml @@ -0,0 +1,243 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +metadata: + template_name: Main +imports: +- openecomp_heat_index: + file: openecomp-heat/_index.yml +- GlobalSubstitutionTypes: + file: GlobalSubstitutionTypesServiceTemplate.yaml +topology_template: + inputs: + oam_net_ips: + label: OAM network ips + hidden: false + immutable: false + type: list + description: OAM network ips + default: + - 107.239.64.121 + entry_schema: + type: string + availabilityzone_name: + label: availabilityzone name + hidden: false + immutable: false + type: string + description: availabilityzone name + default: nova + oam_net_gw: + label: CPS network gateway + hidden: false + immutable: false + type: string + description: CPS network gateway + default: 107.239.64.1 + pcm_server_names: + label: PCRF CM server names + hidden: false + immutable: false + type: list + description: name of the PCRF CM instance + default: + - ZRDM1PCRF01PCM001 + entry_schema: + type: string + pcm_image_name: + label: PCRF CM image name + hidden: false + immutable: false + type: string + description: PCRF CM image name + default: rhel2 + cps_net_ips: + label: CPS network ips + hidden: false + immutable: false + type: list + description: CPS network ips + default: + - 172.26.16.113 + entry_schema: + type: string + security_group_name: + label: security group name + hidden: false + immutable: false + type: string + description: the name of security group + default: nimbus_security_group + pcm_volumes: + label: CPS Cluman Cinder Volume + hidden: false + immutable: false + type: list + description: CPS Cluman Cinder Volume + default: + - 249cb355-8fdf-4382-9c3c-a2ebe767d45b + entry_schema: + type: string + compute_image_name: + hidden: false + immutable: false + type: string + pcm_flavor_name: + label: PCRF CM flavor name + hidden: false + immutable: false + type: string + description: flavor name of PCRF CM instance + default: cps + net_name: + hidden: false + immutable: false + type: string + cps_net_name: + label: CPS network name + hidden: false + immutable: false + type: string + description: CPS network name + default: int_pcrf_net_0 + cps_net_mask: + label: CPS network mask + hidden: false + immutable: false + type: string + description: CPS network mask + default: 255.255.255.0 + oam_net_mask: + label: CPS network mask + hidden: false + immutable: false + type: string + description: CPS network mask + default: 255.255.255.0 + oam_net_name: + label: OAM network name + hidden: false + immutable: false + type: string + description: OAM network name + default: oam_protected_net_0 + node_templates: + abstract_pcm_server_0: + type: org.openecomp.resource.abstract.nodes.heat.pcm_server + directives: + - substitutable + properties: + availabilityzone_name: + get_input: availabilityzone_name + oam_net_gw: + get_input: oam_net_gw + pcm_image_name: + get_input: pcm_image_name + security_group_name: + get_input: security_group_name + cps_net_ip: + get_input: + - cps_net_ips + - 0 + pcm_flavor_name: + get_input: pcm_flavor_name + service_template_filter: + substitute_service_template: nested-pcm_v0.1ServiceTemplate.yaml + pcm_vol: + get_input: + - pcm_volumes + - 0 + pcm_server_name: + get_input: + - pcm_server_names + - 0 + cps_net_name: + get_input: cps_net_name + cps_net_mask: + get_input: cps_net_mask + oam_net_ip: + get_input: + - oam_net_ips + - 0 + oam_net_mask: + get_input: oam_net_mask + oam_net_name: + get_input: oam_net_name + packet_mirror_network: + type: org.openecomp.resource.vl.nodes.heat.network.neutron.Net + properties: + network_name: + get_input: net_name + requirements: + - dependency: + capability: tosca.capabilities.Node + node: abstract_pcm_server_0 + relationship: tosca.relationships.DependsOn + compute_port_0: + type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port + properties: + ip_requirements: + - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + mac_requirements: + mac_count_required: + is_required: false + network: + get_input: net_name + abstract_compute: + type: org.openecomp.resource.abstract.nodes.compute + directives: + - substitutable + properties: + compute_compute_user_data_format: + - get_attribute: + - abstract_pcm_server_0 + - oam_net_gw + vm_image_name: + get_input: compute_image_name + compute_compute_metadata: + - get_attribute: + - abstract_pcm_server_0 + - server_pcm_id + compute_compute_name: + - compute_name: null + vm_flavor_name: + compute_flavor_name: null + compute_compute_config_drive: + - get_attribute: + - compute_port_0 + - tenant_id + - port_security_enabled + - device_id + - qos_policy + - allowed_address_pairs + - show + - device_owner + - network + - security_groups + - fixed_ips + - mac_address + - admin_state_up + - name + - subnets + - status + service_template_filter: + substitute_service_template: Nested_computeServiceTemplate.yaml + count: 1 + index_value: + get_property: + - SELF + - service_template_filter + - index_value + groups: + hot-nimbus-pcm_v0.4_group: + type: org.openecomp.groups.heat.HeatStack + properties: + heat_file: ../Artifacts/hot-nimbus-pcm_v0.4.yaml + description: heat template that creates PCRF Cluman stack + members: + - packet_mirror_network + - compute_port_0 + - abstract_compute + - abstract_pcm_server_0 \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/Nested_computeServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/Nested_computeServiceTemplate.yaml new file mode 100644 index 0000000000..22bdef3d42 --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/Nested_computeServiceTemplate.yaml @@ -0,0 +1,203 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +metadata: + template_name: Nested_compute +imports: +- openecomp_heat_index: + file: openecomp-heat/_index.yml +- GlobalSubstitutionTypes: + file: GlobalSubstitutionTypesServiceTemplate.yaml +node_types: + org.openecomp.resource.vfc.nodes.heat.compute: + derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server +topology_template: + inputs: + compute_compute_user_data_format: + type: list + required: true + entry_schema: + type: string + vm_image_name: + type: string + required: true + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_compute_metadata: + type: list + required: true + entry_schema: + type: json + compute_compute_name: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + compute_compute_config_drive: + type: list + required: true + entry_schema: + type: boolean + node_templates: + compute: + type: org.openecomp.resource.vfc.nodes.heat.compute + properties: + flavor: + get_input: vm_flavor_name + metadata: + get_input: + - compute_compute_metadata + - index_value + config_drive: + get_input: + - compute_compute_config_drive + - index_value + image: + get_input: vm_image_name + name: + get_input: + - compute_compute_name + - index_value + user_data_format: + get_input: + - compute_compute_user_data_format + - index_value + substitution_mappings: + node_type: org.openecomp.resource.abstract.nodes.compute + capabilities: + disk.device.usage_compute: + - compute + - disk.device.usage + disk.write.requests_compute: + - compute + - disk.write.requests + instance_compute: + - compute + - instance + disk.ephemeral.size_compute: + - compute + - disk.ephemeral.size + disk.device.read.bytes.rate_compute: + - compute + - disk.device.read.bytes.rate + disk.latency_compute: + - compute + - disk.latency + memory.resident_compute: + - compute + - memory.resident + memory_compute: + - compute + - memory + disk.iops_compute: + - compute + - disk.iops + disk.root.size_compute: + - compute + - disk.root.size + disk.write.requests.rate_compute: + - compute + - disk.write.requests.rate + disk.read.requests_compute: + - compute + - disk.read.requests + disk.device.read.requests.rate_compute: + - compute + - disk.device.read.requests.rate + disk.read.bytes_compute: + - compute + - disk.read.bytes + disk.device.read.bytes_compute: + - compute + - disk.device.read.bytes + disk.write.bytes_compute: + - compute + - disk.write.bytes + disk.usage_compute: + - compute + - disk.usage + os_compute: + - compute + - os + disk.write.bytes.rate_compute: + - compute + - disk.write.bytes.rate + vcpus_compute: + - compute + - vcpus + disk.capacity_compute: + - compute + - disk.capacity + cpu_util_compute: + - compute + - cpu_util + disk.read.bytes.rate_compute: + - compute + - disk.read.bytes.rate + disk.device.latency_compute: + - compute + - disk.device.latency + disk.device.write.requests_compute: + - compute + - disk.device.write.requests + disk.device.iops_compute: + - compute + - disk.device.iops + disk.device.write.requests.rate_compute: + - compute + - disk.device.write.requests.rate + endpoint_compute: + - compute + - endpoint + memory.usage_compute: + - compute + - memory.usage + host_compute: + - compute + - host + feature_compute: + - compute + - feature + disk.device.write.bytes_compute: + - compute + - disk.device.write.bytes + cpu_compute: + - compute + - cpu + disk.device.write.bytes.rate_compute: + - compute + - disk.device.write.bytes.rate + scalable_compute: + - compute + - scalable + disk.device.read.requests_compute: + - compute + - disk.device.read.requests + disk.allocation_compute: + - compute + - disk.allocation + disk.device.capacity_compute: + - compute + - disk.device.capacity + disk.device.allocation_compute: + - compute + - disk.device.allocation + cpu.delta_compute: + - compute + - cpu.delta + binding_compute: + - compute + - binding + requirements: + local_storage_compute: + - compute + - local_storage + dependency_compute: + - compute + - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/nested-pcm_v0.1ServiceTemplate.yaml new file mode 100644 index 0000000000..ad1fe6a24e --- /dev/null +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithOneComputeDiffPortType/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -0,0 +1,470 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +metadata: + template_name: nested-pcm_v0.1 +imports: +- openecomp_heat_index: + file: openecomp-heat/_index.yml +- GlobalSubstitutionTypes: + file: GlobalSubstitutionTypesServiceTemplate.yaml +node_types: + org.openecomp.resource.vfc.nodes.heat.pcm_server: + derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server +topology_template: + inputs: + availabilityzone_name: + label: availabilityzone name + hidden: false + immutable: false + type: string + description: availabilityzone name + port_pcm_2port_1_network_role: + type: list + required: true + entry_schema: + type: string + oam_net_gw: + label: CPS network gateway + hidden: false + immutable: false + type: string + description: CPS network gateway + pcm_image_name: + label: image name + hidden: false + immutable: false + type: string + description: PCRF CM image name + port_pcm_1port_0_network_role: + type: list + required: true + entry_schema: + type: string + port_pcm_1port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + security_group_name: + label: security group name + hidden: false + immutable: false + type: string + description: the name of security group + port_pcm_1port_0_order: + type: list + required: true + entry_schema: + type: integer + cps_net_ip: + label: CPS network ip + hidden: false + immutable: false + type: string + description: CPS network ip + port_pcm_2port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + pcm_flavor_name: + label: PCRF CM flavor name + hidden: false + immutable: false + type: string + description: flavor name of PCRF CM instance + port_pcm_2port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + pcm_vol: + label: CPS Cluman Cinder Volume + hidden: false + immutable: false + type: string + description: CPS Cluman Cinder Volume + port_pcm_1port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pcm_1port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + pcm_server_name: + label: PCRF CM server name + hidden: false + immutable: false + type: string + description: PCRF CM server name + cps_net_name: + label: CPS network name + hidden: false + immutable: false + type: string + description: CPS network name + cps_net_mask: + label: CPS network mask + hidden: false + immutable: false + type: string + description: CPS network mask + oam_net_ip: + label: OAM network ip + hidden: false + immutable: false + type: string + description: OAM network ip + oam_net_mask: + label: CPS network mask + hidden: false + immutable: false + type: string + description: CPS network mask + oam_net_name: + label: OAM network name + hidden: false + immutable: false + type: string + description: OAM network name + port_pcm_2port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_2port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + node_templates: + server_pcm: + type: org.openecomp.resource.vfc.nodes.heat.pcm_server + properties: + flavor: + get_input: pcm_flavor_name + availability_zone: + get_input: availabilityzone_name + image: + get_input: pcm_image_name + config_drive: true + user_data_format: RAW + name: + get_input: pcm_server_name + pcm_1port_0: + type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port + properties: + ip_requirements: + - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false + security_groups: + - get_input: security_group_name + network_role: + get_input: + - port_pcm_1port_0_network_role + - index_value + fixed_ips: + - ip_address: + get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_1port_0_subnetpoolid + - index_value + mac_requirements: + mac_count_required: + is_required: false + exCP_naming: + get_input: + - port_pcm_1port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_1port_0_vlan_requirements + - index_value + network_role_tag: cps + network: + get_input: cps_net_name + order: + get_input: + - port_pcm_1port_0_order + - index_value + requirements: + - binding: + capability: tosca.capabilities.network.Bindable + node: server_pcm + relationship: tosca.relationships.network.BindsTo + pcm_2port_1: + type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port + properties: + ip_requirements: + - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false + security_groups: + - get_input: security_group_name + network_role: + get_input: + - port_pcm_2port_1_network_role + - index_value + fixed_ips: + - ip_address: + get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_2port_1_subnetpoolid + - index_value + mac_requirements: + mac_count_required: + is_required: false + exCP_naming: + get_input: + - port_pcm_2port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_2port_1_vlan_requirements + - index_value + network_role_tag: oam + network: + get_input: oam_net_name + order: + get_input: + - port_pcm_2port_1_order + - index_value + requirements: + - binding: + capability: tosca.capabilities.network.Bindable + node: server_pcm + relationship: tosca.relationships.network.BindsTo + groups: + nested-pcm_v0.1_group: + type: org.openecomp.groups.heat.HeatStack + properties: + heat_file: ../Artifacts/nested-pcm_v0.1.yaml + description: heat template that creates PCRF Cluman stack + members: + - server_pcm + - pcm_1port_0 + - pcm_2port_1 + outputs: + server_pcm_id: + description: the pcm nova service id + value: server_pcm + substitution_mappings: + node_type: org.openecomp.resource.abstract.nodes.heat.pcm_server + capabilities: + binding_pcm_2port_1: + - pcm_2port_1 + - binding + cpu_server_pcm: + - server_pcm + - cpu + attachment_pcm_2port_1: + - pcm_2port_1 + - attachment + network.outgoing.bytes.rate_pcm_2port_1: + - pcm_2port_1 + - network.outgoing.bytes.rate + memory_server_pcm: + - server_pcm + - memory + disk.write.requests_server_pcm: + - server_pcm + - disk.write.requests + network.incoming.bytes_pcm_2port_1: + - pcm_2port_1 + - network.incoming.bytes + feature_pcm_1port_0: + - pcm_1port_0 + - feature + network.incoming.packets.rate_pcm_2port_1: + - pcm_2port_1 + - network.incoming.packets.rate + network.outpoing.packets_pcm_2port_1: + - pcm_2port_1 + - network.outpoing.packets + disk.device.iops_server_pcm: + - server_pcm + - disk.device.iops + memory.resident_server_pcm: + - server_pcm + - memory.resident + disk.device.write.requests_server_pcm: + - server_pcm + - disk.device.write.requests + network.outgoing.packets.rate_pcm_2port_1: + - pcm_2port_1 + - network.outgoing.packets.rate + disk.device.usage_server_pcm: + - server_pcm + - disk.device.usage + disk.allocation_server_pcm: + - server_pcm + - disk.allocation + network.incoming.packets_pcm_2port_1: + - pcm_2port_1 + - network.incoming.packets + network.outpoing.packets_pcm_1port_0: + - pcm_1port_0 + - network.outpoing.packets + disk.usage_server_pcm: + - server_pcm + - disk.usage + disk.device.write.bytes_server_pcm: + - server_pcm + - disk.device.write.bytes + disk.root.size_server_pcm: + - server_pcm + - disk.root.size + disk.ephemeral.size_server_pcm: + - server_pcm + - disk.ephemeral.size + disk.device.latency_server_pcm: + - server_pcm + - disk.device.latency + network.incoming.bytes_pcm_1port_0: + - pcm_1port_0 + - network.incoming.bytes + memory.usage_server_pcm: + - server_pcm + - memory.usage + disk.read.requests_server_pcm: + - server_pcm + - disk.read.requests + disk.capacity_server_pcm: + - server_pcm + - disk.capacity + os_server_pcm: + - server_pcm + - os + disk.read.bytes_server_pcm: + - server_pcm + - disk.read.bytes + disk.device.read.bytes_server_pcm: + - server_pcm + - disk.device.read.bytes + network.incoming.packets_pcm_1port_0: + - pcm_1port_0 + - network.incoming.packets + endpoint_server_pcm: + - server_pcm + - endpoint + disk.device.read.requests.rate_server_pcm: + - server_pcm + - disk.device.read.requests.rate + vcpus_server_pcm: + - server_pcm + - vcpus + disk.write.bytes_server_pcm: + - server_pcm + - disk.write.bytes + disk.iops_server_pcm: + - server_pcm + - disk.iops + network.incoming.bytes.rate_pcm_1port_0: + - pcm_1port_0 + - network.incoming.bytes.rate + disk.read.bytes.rate_server_pcm: + - server_pcm + - disk.read.bytes.rate + disk.device.allocation_server_pcm: + - server_pcm + - disk.device.allocation + network.incoming.packets.rate_pcm_1port_0: + - pcm_1port_0 + - network.incoming.packets.rate + feature_pcm_2port_1: + - pcm_2port_1 + - feature + scalable_server_pcm: + - server_pcm + - scalable + network.outgoing.bytes.rate_pcm_1port_0: + - pcm_1port_0 + - network.outgoing.bytes.rate + network.outgoing.bytes_pcm_2port_1: + - pcm_2port_1 + - network.outgoing.bytes + disk.device.read.bytes.rate_server_pcm: + - server_pcm + - disk.device.read.bytes.rate + cpu_util_server_pcm: + - server_pcm + - cpu_util + attachment_pcm_1port_0: + - pcm_1port_0 + - attachment + disk.write.requests.rate_server_pcm: + - server_pcm + - disk.write.requests.rate + network.incoming.bytes.rate_pcm_2port_1: + - pcm_2port_1 + - network.incoming.bytes.rate + disk.device.write.bytes.rate_server_pcm: + - server_pcm + - disk.device.write.bytes.rate + host_server_pcm: + - server_pcm + - host + network.outgoing.bytes_pcm_1port_0: + - pcm_1port_0 + - network.outgoing.bytes + binding_pcm_1port_0: + - pcm_1port_0 + - binding + cpu.delta_server_pcm: + - server_pcm + - cpu.delta + network.outgoing.packets.rate_pcm_1port_0: + - pcm_1port_0 + - network.outgoing.packets.rate + binding_server_pcm: + - server_pcm + - binding + disk.device.capacity_server_pcm: + - server_pcm + - disk.device.capacity + instance_server_pcm: + - server_pcm + - instance + disk.device.write.requests.rate_server_pcm: + - server_pcm + - disk.device.write.requests.rate + disk.latency_server_pcm: + - server_pcm + - disk.latency + disk.device.read.requests_server_pcm: + - server_pcm + - disk.device.read.requests + feature_server_pcm: + - server_pcm + - feature + disk.write.bytes.rate_server_pcm: + - server_pcm + - disk.write.bytes.rate + requirements: + dependency_pcm_2port_1: + - pcm_2port_1 + - dependency + local_storage_server_pcm: + - server_pcm + - local_storage + link_pcm_1port_0: + - pcm_1port_0 + - link + dependency_pcm_1port_0: + - pcm_1port_0 + - dependency + dependency_server_pcm: + - server_pcm + - dependency + link_pcm_2port_1: + - pcm_2port_1 + - link \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/in/hot-nimbus-pcm_v0.4.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/in/hot-nimbus-pcm_v0.4.yaml index c1597faeff..0b1c25ee74 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/in/hot-nimbus-pcm_v0.4.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/in/hot-nimbus-pcm_v0.4.yaml @@ -73,7 +73,7 @@ parameters: type: string resources: - server_pcm: + server_pcm_1: type: nested-pcm_v0.1.yaml properties: pcm_server_name: { get_param: [pcm_server_names, 0] } @@ -90,7 +90,7 @@ resources: oam_net_mask: { get_param: oam_net_mask } oam_net_gw: { get_param: oam_net_gw } - server_pd: + server_pd_1: type: nested-pcm_v0.1.yaml properties: pcm_server_name: { get_param: [pd_server_names, 1] } diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/in/nested-pcm_v0.1.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/in/nested-pcm_v0.1.yaml index 443a6886dc..5844fd6f02 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/in/nested-pcm_v0.1.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/in/nested-pcm_v0.1.yaml @@ -69,7 +69,7 @@ parameters: description: the name of security group resources: - server_pcm: + server_pcm_0: type: OS::Nova::Server properties: config_drive: "True" @@ -84,7 +84,7 @@ resources: volume_id: { get_param: pcm_vol} user_data_format: RAW - server_pd: + server_pd_0: type: OS::Nova::Server properties: config_drive: "True" @@ -117,8 +117,8 @@ resources: outputs: server_pcm_id_1: description: the pcm nova service id - value: { get_resource: server_pcm } + value: { get_resource: server_pcm_0 } server_pcm_id_2: description: the pcm nova service id - value: { get_resource: server_pd } \ No newline at end of file + value: { get_resource: server_pd_0 } \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/GlobalSubstitutionTypesServiceTemplate.yaml index 227c1af00a..ab2625118b 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -98,41 +98,41 @@ node_types: description: the pcm nova service id status: SUPPORTED requirements: - - dependency_server_pcm: + - dependency_pcm_port_1: capability: tosca.capabilities.Node node: tosca.nodes.Root relationship: tosca.relationships.DependsOn occurrences: - 0 - UNBOUNDED - - local_storage_server_pcm: - capability: tosca.capabilities.Attachment - node: tosca.nodes.BlockStorage - relationship: tosca.relationships.AttachesTo + - link_pcm_port_1: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo occurrences: - - 0 - - UNBOUNDED - - dependency_pcm_port_1: + - 1 + - 1 + - dependency_server_pcm_0: capability: tosca.capabilities.Node node: tosca.nodes.Root relationship: tosca.relationships.DependsOn occurrences: - 0 - UNBOUNDED - - link_pcm_port_1: - capability: tosca.capabilities.network.Linkable - relationship: tosca.relationships.network.LinksTo + - local_storage_server_pcm_0: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo occurrences: - - 1 - - 1 - - dependency_server_pd: + - 0 + - UNBOUNDED + - dependency_server_pd_0: capability: tosca.capabilities.Node node: tosca.nodes.Root relationship: tosca.relationships.DependsOn occurrences: - 0 - UNBOUNDED - - local_storage_server_pd: + - local_storage_server_pd_0: capability: tosca.capabilities.Attachment node: tosca.nodes.BlockStorage relationship: tosca.relationships.AttachesTo @@ -159,13 +159,7 @@ node_types: occurrences: - 1 - UNBOUNDED - disk.iops_server_pd: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED - disk.device.read.bytes.rate_server_pd: + disk.iops_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -177,12 +171,6 @@ node_types: occurrences: - 1 - UNBOUNDED - memory_server_pcm: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED network.outpoing.packets_pcm_port_1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. @@ -195,61 +183,37 @@ node_types: occurrences: - 1 - UNBOUNDED - disk.device.read.requests_server_pd: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED - disk.device.iops_server_pcm: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED - disk.device.allocation_server_pd: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED - disk.allocation_server_pcm: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED - memory.usage_server_pd: + disk.write.bytes.rate_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.read.bytes.rate_server_pd: + cpu.delta_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.usage_server_pcm: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + feature_server_pd_0: + type: tosca.capabilities.Node occurrences: - 1 - UNBOUNDED - disk.root.size_server_pcm: + disk.capacity_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - memory_server_pd: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + host_server_pd_0: + type: tosca.capabilities.Container + valid_source_types: + - tosca.nodes.SoftwareComponent occurrences: - 1 - UNBOUNDED - disk.device.latency_server_pcm: + memory_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -261,13 +225,13 @@ node_types: occurrences: - 1 - UNBOUNDED - disk.device.write.requests_server_pd: + network.incoming.bytes_pcm_port_1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.bytes_pcm_port_1: + disk.usage_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -280,12 +244,6 @@ node_types: occurrences: - 0 - UNBOUNDED - memory.usage_server_pcm: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED binding_pcm_port_1: type: tosca.capabilities.network.Bindable valid_source_types: @@ -293,18 +251,29 @@ node_types: occurrences: - 0 - UNBOUNDED - disk.read.requests_server_pcm: + vcpus_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.read.bytes_server_pcm: + memory.resident_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED + disk.write.requests_server_pd_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + feature_server_pcm_0: + type: tosca.capabilities.Node + occurrences: + - 1 + - UNBOUNDED network.outgoing.packets.rate_pcm_port_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. @@ -322,19 +291,13 @@ node_types: occurrences: - 1 - UNBOUNDED - network.outgoing.bytes_pcm_port_0: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED - disk.device.read.bytes_server_pcm: + disk.ephemeral.size_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.read.bytes_server_pd: + network.outgoing.bytes_pcm_port_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -351,6 +314,12 @@ node_types: occurrences: - 1 - UNBOUNDED + cpu_server_pcm_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED attachment_pcm_port_0: type: tosca.capabilities.Attachment occurrences: @@ -361,320 +330,345 @@ node_types: occurrences: - 1 - UNBOUNDED - disk.device.read.bytes_server_pd: + disk.write.bytes_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.requests.rate_server_pcm: + disk.read.requests_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - vcpus_server_pcm: + disk.device.usage_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.bytes_server_pcm: + disk.device.read.bytes_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - host_server_pd: + endpoint_server_pcm_0: + type: tosca.capabilities.Endpoint.Admin + occurrences: + - 1 + - UNBOUNDED + host_server_pcm_0: type: tosca.capabilities.Container valid_source_types: - tosca.nodes.SoftwareComponent occurrences: - 1 - UNBOUNDED - disk.read.bytes.rate_server_pcm: + disk.write.requests.rate_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - vcpus_server_pd: + disk.device.capacity_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.allocation_server_pcm: + disk.root.size_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.ephemeral.size_server_pd: + disk.latency_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.requests.rate_server_pd: + disk.device.iops_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - scalable_server_pcm: - type: tosca.capabilities.Scalable + disk.write.requests.rate_server_pcm_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - cpu_util_server_pcm: + memory_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.requests_server_pd: + disk.device.read.bytes.rate_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - host_server_pcm: - type: tosca.capabilities.Container - valid_source_types: - - tosca.nodes.SoftwareComponent + instance_server_pcm_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - cpu.delta_server_pcm: + disk.device.allocation_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - binding_server_pcm: - type: tosca.capabilities.network.Bindable + disk.usage_server_pd_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.write.bytes_server_pcm_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.capacity_server_pcm: + disk.device.read.requests.rate_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - binding_server_pd: + binding_server_pcm_0: type: tosca.capabilities.network.Bindable occurrences: - 1 - UNBOUNDED - disk.device.write.requests.rate_server_pcm: + disk.read.bytes.rate_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.latency_server_pcm: + disk.write.bytes.rate_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.requests_server_pcm: + cpu_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - feature_server_pcm: - type: tosca.capabilities.Node + disk.root.size_server_pcm_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.root.size_server_pd: + vcpus_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.requests.rate_server_pd: + disk.iops_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.bytes.rate_server_pcm: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + endpoint_server_pd_0: + type: tosca.capabilities.Endpoint.Admin occurrences: - 1 - UNBOUNDED - disk.device.write.bytes_server_pd: + disk.device.write.bytes.rate_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - cpu_server_pcm: + disk.device.capacity_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - memory.resident_server_pd: + disk.device.write.bytes.rate_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.requests_server_pcm: + disk.write.requests_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - cpu_util_server_pd: + disk.read.bytes_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - memory.resident_server_pcm: + disk.device.latency_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.write.requests_server_pcm: + cpu_util_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.usage_server_pd: + disk.device.read.requests.rate_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.usage_server_pcm: + disk.device.write.bytes_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.capacity_server_pd: + disk.allocation_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - endpoint_server_pd: - type: tosca.capabilities.Endpoint.Admin + memory.usage_server_pcm_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.capacity_server_pd: + instance_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.allocation_server_pd: + disk.allocation_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.write.bytes_server_pcm: + disk.device.read.bytes_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.ephemeral.size_server_pcm: + cpu_util_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.usage_server_pd: + disk.read.bytes.rate_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.capacity_server_pcm: + disk.device.iops_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - os_server_pcm: - type: tosca.capabilities.OperatingSystem + disk.device.write.bytes_server_pd_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - endpoint_server_pcm: - type: tosca.capabilities.Endpoint.Admin + disk.capacity_server_pd_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - instance_server_pd: + disk.device.read.bytes.rate_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.iops_server_pcm: + cpu.delta_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - cpu.delta_server_pd: + memory.resident_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.latency_server_pd: + disk.ephemeral.size_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.write.bytes.rate_server_pd: + disk.read.requests_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.bytes.rate_server_pcm: + disk.device.write.requests.rate_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.requests.rate_server_pcm: + disk.device.write.requests_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.write.bytes.rate_server_pcm: + binding_server_pd_0: + type: tosca.capabilities.network.Bindable + occurrences: + - 1 + - UNBOUNDED + scalable_server_pcm_0: + type: tosca.capabilities.Scalable + occurrences: + - 1 + - UNBOUNDED + disk.device.allocation_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.iops_server_pd: + disk.read.bytes_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.read.requests_server_pd: + disk.device.read.requests_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -692,70 +686,71 @@ node_types: occurrences: - 1 - UNBOUNDED - os_server_pd: - type: tosca.capabilities.OperatingSystem + disk.device.latency_server_pcm_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.latency_server_pd: + disk.device.usage_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.outgoing.bytes.rate_pcm_port_0: + disk.latency_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.packets_pcm_port_1: + network.outgoing.bytes.rate_pcm_port_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - scalable_server_pd: - type: tosca.capabilities.Scalable + memory.usage_server_pd_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - instance_server_pcm: + network.incoming.packets_pcm_port_1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.bytes_server_pd: + disk.device.write.requests_server_pcm_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.bytes.rate_server_pd: + disk.device.write.requests.rate_server_pd_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - feature_server_pd: - type: tosca.capabilities.Node + disk.device.read.requests_server_pcm_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.bytes.rate_pcm_port_0: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + scalable_server_pd_0: + type: tosca.capabilities.Scalable occurrences: - 1 - UNBOUNDED - disk.device.write.requests.rate_server_pd: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + os_server_pcm_0: + type: tosca.capabilities.OperatingSystem occurrences: - 1 - UNBOUNDED - cpu_server_pd: + network.incoming.bytes.rate_pcm_port_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -766,4 +761,9 @@ node_types: description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 + - UNBOUNDED + os_server_pd_0: + type: tosca.capabilities.OperatingSystem + occurrences: + - 1 - UNBOUNDED \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/MainServiceTemplate.yaml index e51dba5a7c..1dc9eebe59 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/MainServiceTemplate.yaml @@ -144,7 +144,7 @@ topology_template: description: OAM network name default: oam_protected_net_0 node_templates: - server_pcm: + server_pd_1: type: org.openecomp.resource.abstract.nodes.heat.nested-pcm_v0.1 directives: - substitutable @@ -154,7 +154,7 @@ topology_template: oam_net_gw: get_input: oam_net_gw pcm_image_name: - get_input: pcm_image_name + get_input: pd_image_name security_group_name: get_input: security_group_name cps_net_ip: @@ -162,7 +162,7 @@ topology_template: - cps_net_ips - 0 pcm_flavor_name: - get_input: pcm_flavor_name + get_input: pd_flavor_name service_template_filter: substitute_service_template: nested-pcm_v0.1ServiceTemplate.yaml pcm_vol: @@ -171,8 +171,8 @@ topology_template: - 0 pcm_server_name: get_input: - - pcm_server_names - - 0 + - pd_server_names + - 1 cps_net_name: get_input: cps_net_name cps_net_mask: @@ -185,21 +185,7 @@ topology_template: get_input: oam_net_mask oam_net_name: get_input: oam_net_name - compute_port_0: - type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port - properties: - ip_requirements: - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - mac_requirements: - mac_count_required: - is_required: false - network: - get_input: net_name - server_pd: + server_pcm_1: type: org.openecomp.resource.abstract.nodes.heat.nested-pcm_v0.1 directives: - substitutable @@ -209,7 +195,7 @@ topology_template: oam_net_gw: get_input: oam_net_gw pcm_image_name: - get_input: pd_image_name + get_input: pcm_image_name security_group_name: get_input: security_group_name cps_net_ip: @@ -217,7 +203,7 @@ topology_template: - cps_net_ips - 0 pcm_flavor_name: - get_input: pd_flavor_name + get_input: pcm_flavor_name service_template_filter: substitute_service_template: nested-pcm_v0.1ServiceTemplate.yaml pcm_vol: @@ -226,8 +212,8 @@ topology_template: - 0 pcm_server_name: get_input: - - pd_server_names - - 1 + - pcm_server_names + - 0 cps_net_name: get_input: cps_net_name cps_net_mask: @@ -240,6 +226,20 @@ topology_template: get_input: oam_net_mask oam_net_name: get_input: oam_net_name + compute_port_0: + type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port + properties: + ip_requirements: + - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + mac_requirements: + mac_count_required: + is_required: false + network: + get_input: net_name groups: hot-nimbus-pcm_v0.4_group: type: org.openecomp.groups.heat.HeatStack @@ -247,6 +247,6 @@ topology_template: heat_file: ../Artifacts/hot-nimbus-pcm_v0.4.yaml description: heat template that creates PCRF Cluman stack members: - - server_pcm - - compute_port_0 - - server_pd \ No newline at end of file + - server_pd_1 + - server_pcm_1 + - compute_port_0 \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/nested-pcm_v0.1ServiceTemplate.yaml index dce37eb21a..65088158c3 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/nestedWithTwoDiffComputeTypes/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -110,19 +110,6 @@ topology_template: type: string description: OAM network name node_templates: - server_pcm: - type: org.openecomp.resource.vfc.nodes.heat.pcm_server - properties: - flavor: - get_input: pcm_flavor_name - availability_zone: - get_input: availabilityzone_name - image: - get_input: pcm_image_name - config_drive: true - user_data_format: RAW - name: - get_input: pcm_server_name pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: @@ -146,9 +133,22 @@ topology_template: requirements: - binding: capability: tosca.capabilities.network.Bindable - node: server_pd + node: server_pd_0 relationship: tosca.relationships.network.BindsTo - server_pd: + server_pcm_0: + type: org.openecomp.resource.vfc.nodes.heat.pcm_server + properties: + flavor: + get_input: pcm_flavor_name + availability_zone: + get_input: availabilityzone_name + image: + get_input: pcm_image_name + config_drive: true + user_data_format: RAW + name: + get_input: pcm_server_name + server_pd_0: type: org.openecomp.resource.vfc.nodes.heat.pd_server properties: flavor: @@ -184,7 +184,7 @@ topology_template: requirements: - binding: capability: tosca.capabilities.network.Bindable - node: server_pcm + node: server_pcm_0 relationship: tosca.relationships.network.BindsTo groups: nested-pcm_v0.1_group: @@ -193,95 +193,80 @@ topology_template: heat_file: ../Artifacts/nested-pcm_v0.1.yaml description: heat template that creates PCRF Cluman stack members: - - server_pcm - pcm_port_1 - - server_pd + - server_pcm_0 + - server_pd_0 - pcm_port_0 outputs: server_pcm_id_2: description: the pcm nova service id - value: server_pd + value: server_pd_0 server_pcm_id_1: description: the pcm nova service id - value: server_pcm + value: server_pcm_0 substitution_mappings: node_type: org.openecomp.resource.abstract.nodes.heat.nested-pcm_v0.1 capabilities: network.incoming.packets.rate_pcm_port_0: - pcm_port_0 - network.incoming.packets.rate - disk.iops_server_pd: - - server_pd + disk.iops_server_pd_0: + - server_pd_0 - disk.iops - disk.device.read.bytes.rate_server_pd: - - server_pd - - disk.device.read.bytes.rate network.incoming.packets.rate_pcm_port_1: - pcm_port_1 - network.incoming.packets.rate - memory_server_pcm: - - server_pcm - - memory network.outpoing.packets_pcm_port_1: - pcm_port_1 - network.outpoing.packets network.outpoing.packets_pcm_port_0: - pcm_port_0 - network.outpoing.packets - disk.device.read.requests_server_pd: - - server_pd - - disk.device.read.requests - disk.device.iops_server_pcm: - - server_pcm - - disk.device.iops - disk.device.allocation_server_pd: - - server_pd - - disk.device.allocation - disk.allocation_server_pcm: - - server_pcm - - disk.allocation - memory.usage_server_pd: - - server_pd - - memory.usage - disk.read.bytes.rate_server_pd: - - server_pd - - disk.read.bytes.rate - disk.usage_server_pcm: - - server_pcm - - disk.usage - disk.root.size_server_pcm: - - server_pcm - - disk.root.size - memory_server_pd: - - server_pd + disk.write.bytes.rate_server_pd_0: + - server_pd_0 + - disk.write.bytes.rate + cpu.delta_server_pd_0: + - server_pd_0 + - cpu.delta + feature_server_pd_0: + - server_pd_0 + - feature + disk.capacity_server_pcm_0: + - server_pcm_0 + - disk.capacity + host_server_pd_0: + - server_pd_0 + - host + memory_server_pd_0: + - server_pd_0 - memory - disk.device.latency_server_pcm: - - server_pcm - - disk.device.latency network.incoming.bytes_pcm_port_0: - pcm_port_0 - network.incoming.bytes - disk.device.write.requests_server_pd: - - server_pd - - disk.device.write.requests network.incoming.bytes_pcm_port_1: - pcm_port_1 - network.incoming.bytes + disk.usage_server_pcm_0: + - server_pcm_0 + - disk.usage binding_pcm_port_0: - pcm_port_0 - binding - memory.usage_server_pcm: - - server_pcm - - memory.usage binding_pcm_port_1: - pcm_port_1 - binding - disk.read.requests_server_pcm: - - server_pcm - - disk.read.requests - disk.read.bytes_server_pcm: - - server_pcm - - disk.read.bytes + vcpus_server_pcm_0: + - server_pcm_0 + - vcpus + memory.resident_server_pcm_0: + - server_pcm_0 + - memory.resident + disk.write.requests_server_pd_0: + - server_pd_0 + - disk.write.requests + feature_server_pcm_0: + - server_pcm_0 + - feature network.outgoing.packets.rate_pcm_port_0: - pcm_port_0 - network.outgoing.packets.rate @@ -291,255 +276,270 @@ topology_template: feature_pcm_port_1: - pcm_port_1 - feature + disk.ephemeral.size_server_pd_0: + - server_pd_0 + - disk.ephemeral.size network.outgoing.bytes_pcm_port_0: - pcm_port_0 - network.outgoing.bytes - disk.device.read.bytes_server_pcm: - - server_pcm - - disk.device.read.bytes - disk.read.bytes_server_pd: - - server_pd - - disk.read.bytes feature_pcm_port_0: - pcm_port_0 - feature network.outgoing.bytes_pcm_port_1: - pcm_port_1 - network.outgoing.bytes + cpu_server_pcm_0: + - server_pcm_0 + - cpu attachment_pcm_port_0: - pcm_port_0 - attachment attachment_pcm_port_1: - pcm_port_1 - attachment - disk.device.read.bytes_server_pd: - - server_pd - - disk.device.read.bytes - disk.device.read.requests.rate_server_pcm: - - server_pcm - - disk.device.read.requests.rate - vcpus_server_pcm: - - server_pcm - - vcpus - disk.write.bytes_server_pcm: - - server_pcm + disk.write.bytes_server_pd_0: + - server_pd_0 - disk.write.bytes - host_server_pd: - - server_pd + disk.read.requests_server_pd_0: + - server_pd_0 + - disk.read.requests + disk.device.usage_server_pd_0: + - server_pd_0 + - disk.device.usage + disk.device.read.bytes_server_pd_0: + - server_pd_0 + - disk.device.read.bytes + endpoint_server_pcm_0: + - server_pcm_0 + - endpoint + host_server_pcm_0: + - server_pcm_0 - host - disk.read.bytes.rate_server_pcm: - - server_pcm - - disk.read.bytes.rate - vcpus_server_pd: - - server_pd - - vcpus - disk.device.allocation_server_pcm: - - server_pcm - - disk.device.allocation - disk.ephemeral.size_server_pd: - - server_pd - - disk.ephemeral.size - disk.write.requests.rate_server_pd: - - server_pd + disk.write.requests.rate_server_pd_0: + - server_pd_0 - disk.write.requests.rate - scalable_server_pcm: - - server_pcm - - scalable - cpu_util_server_pcm: - - server_pcm - - cpu_util - disk.write.requests_server_pd: - - server_pd - - disk.write.requests - host_server_pcm: - - server_pcm - - host - cpu.delta_server_pcm: - - server_pcm - - cpu.delta - binding_server_pcm: - - server_pcm - - binding - disk.device.capacity_server_pcm: - - server_pcm + disk.device.capacity_server_pcm_0: + - server_pcm_0 - disk.device.capacity - binding_server_pd: - - server_pd - - binding - disk.device.write.requests.rate_server_pcm: - - server_pcm - - disk.device.write.requests.rate - disk.latency_server_pcm: - - server_pcm - - disk.latency - disk.device.read.requests_server_pcm: - - server_pcm - - disk.device.read.requests - feature_server_pcm: - - server_pcm - - feature - disk.root.size_server_pd: - - server_pd + disk.root.size_server_pd_0: + - server_pd_0 - disk.root.size - disk.device.read.requests.rate_server_pd: - - server_pd + disk.latency_server_pcm_0: + - server_pcm_0 + - disk.latency + disk.device.iops_server_pd_0: + - server_pd_0 + - disk.device.iops + disk.write.requests.rate_server_pcm_0: + - server_pcm_0 + - disk.write.requests.rate + memory_server_pcm_0: + - server_pcm_0 + - memory + disk.device.read.bytes.rate_server_pcm_0: + - server_pcm_0 + - disk.device.read.bytes.rate + instance_server_pcm_0: + - server_pcm_0 + - instance + disk.device.allocation_server_pcm_0: + - server_pcm_0 + - disk.device.allocation + disk.usage_server_pd_0: + - server_pd_0 + - disk.usage + disk.write.bytes_server_pcm_0: + - server_pcm_0 + - disk.write.bytes + disk.device.read.requests.rate_server_pcm_0: + - server_pcm_0 - disk.device.read.requests.rate - disk.write.bytes.rate_server_pcm: - - server_pcm + binding_server_pcm_0: + - server_pcm_0 + - binding + disk.read.bytes.rate_server_pd_0: + - server_pd_0 + - disk.read.bytes.rate + disk.write.bytes.rate_server_pcm_0: + - server_pcm_0 - disk.write.bytes.rate - disk.device.write.bytes_server_pd: - - server_pd - - disk.device.write.bytes - cpu_server_pcm: - - server_pcm + cpu_server_pd_0: + - server_pd_0 - cpu - memory.resident_server_pd: - - server_pd - - memory.resident - disk.write.requests_server_pcm: - - server_pcm - - disk.write.requests - cpu_util_server_pd: - - server_pd - - cpu_util - memory.resident_server_pcm: - - server_pcm - - memory.resident - disk.device.write.requests_server_pcm: - - server_pcm - - disk.device.write.requests - disk.usage_server_pd: - - server_pd - - disk.usage - disk.device.usage_server_pcm: - - server_pcm - - disk.device.usage - disk.capacity_server_pd: - - server_pd - - disk.capacity - endpoint_server_pd: - - server_pd + disk.root.size_server_pcm_0: + - server_pcm_0 + - disk.root.size + vcpus_server_pd_0: + - server_pd_0 + - vcpus + disk.iops_server_pcm_0: + - server_pcm_0 + - disk.iops + endpoint_server_pd_0: + - server_pd_0 - endpoint - disk.device.capacity_server_pd: - - server_pd + disk.device.write.bytes.rate_server_pd_0: + - server_pd_0 + - disk.device.write.bytes.rate + disk.device.capacity_server_pd_0: + - server_pd_0 - disk.device.capacity - disk.allocation_server_pd: - - server_pd + disk.device.write.bytes.rate_server_pcm_0: + - server_pcm_0 + - disk.device.write.bytes.rate + disk.write.requests_server_pcm_0: + - server_pcm_0 + - disk.write.requests + disk.read.bytes_server_pcm_0: + - server_pcm_0 + - disk.read.bytes + disk.device.latency_server_pd_0: + - server_pd_0 + - disk.device.latency + cpu_util_server_pcm_0: + - server_pcm_0 + - cpu_util + disk.device.read.requests.rate_server_pd_0: + - server_pd_0 + - disk.device.read.requests.rate + disk.device.write.bytes_server_pcm_0: + - server_pcm_0 + - disk.device.write.bytes + disk.allocation_server_pcm_0: + - server_pcm_0 - disk.allocation - disk.device.write.bytes_server_pcm: - - server_pcm + memory.usage_server_pcm_0: + - server_pcm_0 + - memory.usage + instance_server_pd_0: + - server_pd_0 + - instance + disk.allocation_server_pd_0: + - server_pd_0 + - disk.allocation + disk.device.read.bytes_server_pcm_0: + - server_pcm_0 + - disk.device.read.bytes + cpu_util_server_pd_0: + - server_pd_0 + - cpu_util + disk.read.bytes.rate_server_pcm_0: + - server_pcm_0 + - disk.read.bytes.rate + disk.device.iops_server_pcm_0: + - server_pcm_0 + - disk.device.iops + disk.device.write.bytes_server_pd_0: + - server_pd_0 - disk.device.write.bytes - disk.ephemeral.size_server_pcm: - - server_pcm - - disk.ephemeral.size - disk.device.usage_server_pd: - - server_pd - - disk.device.usage - disk.capacity_server_pcm: - - server_pcm + disk.capacity_server_pd_0: + - server_pd_0 - disk.capacity - os_server_pcm: - - server_pcm - - os - endpoint_server_pcm: - - server_pcm - - endpoint - instance_server_pd: - - server_pd - - instance - disk.iops_server_pcm: - - server_pcm - - disk.iops - cpu.delta_server_pd: - - server_pd - - cpu.delta - disk.latency_server_pd: - - server_pd - - disk.latency - disk.device.write.bytes.rate_server_pd: - - server_pd - - disk.device.write.bytes.rate - disk.device.read.bytes.rate_server_pcm: - - server_pcm + disk.device.read.bytes.rate_server_pd_0: + - server_pd_0 - disk.device.read.bytes.rate - disk.write.requests.rate_server_pcm: - - server_pcm - - disk.write.requests.rate - disk.device.write.bytes.rate_server_pcm: - - server_pcm - - disk.device.write.bytes.rate - disk.device.iops_server_pd: - - server_pd - - disk.device.iops - disk.read.requests_server_pd: - - server_pd + cpu.delta_server_pcm_0: + - server_pcm_0 + - cpu.delta + memory.resident_server_pd_0: + - server_pd_0 + - memory.resident + disk.ephemeral.size_server_pcm_0: + - server_pcm_0 + - disk.ephemeral.size + disk.read.requests_server_pcm_0: + - server_pcm_0 - disk.read.requests + disk.device.write.requests.rate_server_pcm_0: + - server_pcm_0 + - disk.device.write.requests.rate + disk.device.write.requests_server_pd_0: + - server_pd_0 + - disk.device.write.requests + binding_server_pd_0: + - server_pd_0 + - binding + scalable_server_pcm_0: + - server_pcm_0 + - scalable + disk.device.allocation_server_pd_0: + - server_pd_0 + - disk.device.allocation + disk.read.bytes_server_pd_0: + - server_pd_0 + - disk.read.bytes + disk.device.read.requests_server_pd_0: + - server_pd_0 + - disk.device.read.requests network.outgoing.bytes.rate_pcm_port_1: - pcm_port_1 - network.outgoing.bytes.rate network.incoming.packets_pcm_port_0: - pcm_port_0 - network.incoming.packets - os_server_pd: - - server_pd - - os - disk.device.latency_server_pd: - - server_pd + disk.device.latency_server_pcm_0: + - server_pcm_0 - disk.device.latency + disk.device.usage_server_pcm_0: + - server_pcm_0 + - disk.device.usage + disk.latency_server_pd_0: + - server_pd_0 + - disk.latency network.outgoing.bytes.rate_pcm_port_0: - pcm_port_0 - network.outgoing.bytes.rate + memory.usage_server_pd_0: + - server_pd_0 + - memory.usage network.incoming.packets_pcm_port_1: - pcm_port_1 - network.incoming.packets - scalable_server_pd: - - server_pd + disk.device.write.requests_server_pcm_0: + - server_pcm_0 + - disk.device.write.requests + disk.device.write.requests.rate_server_pd_0: + - server_pd_0 + - disk.device.write.requests.rate + disk.device.read.requests_server_pcm_0: + - server_pcm_0 + - disk.device.read.requests + scalable_server_pd_0: + - server_pd_0 - scalable - instance_server_pcm: - - server_pcm - - instance - disk.write.bytes_server_pd: - - server_pd - - disk.write.bytes - disk.write.bytes.rate_server_pd: - - server_pd - - disk.write.bytes.rate - feature_server_pd: - - server_pd - - feature + os_server_pcm_0: + - server_pcm_0 + - os network.incoming.bytes.rate_pcm_port_0: - pcm_port_0 - network.incoming.bytes.rate - disk.device.write.requests.rate_server_pd: - - server_pd - - disk.device.write.requests.rate - cpu_server_pd: - - server_pd - - cpu network.incoming.bytes.rate_pcm_port_1: - pcm_port_1 - network.incoming.bytes.rate + os_server_pd_0: + - server_pd_0 + - os requirements: + dependency_server_pcm_0: + - server_pcm_0 + - dependency + local_storage_server_pcm_0: + - server_pcm_0 + - local_storage link_pcm_port_0: - pcm_port_0 - link link_pcm_port_1: - pcm_port_1 - link - local_storage_server_pd: - - server_pd - - local_storage - dependency_server_pd: - - server_pd - - dependency - local_storage_server_pcm: - - server_pcm - - local_storage dependency_pcm_port_0: - pcm_port_0 - dependency - dependency_server_pcm: - - server_pcm + local_storage_server_pd_0: + - server_pd_0 + - local_storage + dependency_server_pd_0: + - server_pd_0 - dependency dependency_pcm_port_1: - pcm_port_1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml index 18acb4f442..de3481367e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -18,6 +24,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -33,11 +45,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -68,11 +104,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string @@ -495,6 +555,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server_2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -505,6 +571,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -520,11 +592,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -555,11 +651,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string @@ -982,6 +1102,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -992,6 +1118,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -1007,11 +1139,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -1042,11 +1198,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml index 1ab6da631d..1a50030cb0 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -41,12 +51,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -101,15 +151,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -139,15 +209,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.2ServiceTemplate.yaml index a5e41ea4fa..e75b827856 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.2ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -41,12 +51,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -101,15 +151,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -139,15 +209,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.3ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.3ServiceTemplate.yaml index 9002b35770..4803278efc 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.3ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedPointingToThreeDiffNestedFilesSameComputeType/out/nested-pcm_v0.3ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -41,12 +51,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -101,15 +151,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -139,15 +209,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -377,4 +467,4 @@ topology_template: - dependency dependency_pcm_port_1: - pcm_port_1 - - dependency + - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/GlobalSubstitutionTypesServiceTemplate.yaml index daaf03d55e..fe6e819385 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -18,6 +24,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -33,11 +45,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -68,11 +104,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string @@ -495,6 +555,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -505,6 +571,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -520,11 +592,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -555,11 +651,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/nested-pcm_v0.1ServiceTemplate.yaml index 05a21ce6d1..51429041fe 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -41,12 +51,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -101,15 +151,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -139,15 +209,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/nested-pcm_v0.2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/nested-pcm_v0.2ServiceTemplate.yaml index a788426a41..bae5cf0d08 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/nested-pcm_v0.2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/threeNestedSameTypeTwoPointingOnSameNestedFile/out/nested-pcm_v0.2ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -41,12 +51,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -101,15 +151,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -139,15 +209,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/twoNestedNodeTemplatesWithSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/twoNestedNodeTemplatesWithSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml index 14d9ffa1f4..b9bd9b6cf8 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/twoNestedNodeTemplatesWithSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/twoNestedNodeTemplatesWithSameComputeType/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,12 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name @@ -18,6 +24,12 @@ node_types: description: CPS network gateway required: true status: SUPPORTED + port_pcm_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -33,11 +45,35 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string pcm_vol: type: string description: CPS Cluman Cinder Volume @@ -68,11 +104,35 @@ node_types: description: CPS network mask required: true status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json oam_net_name: type: string description: OAM network name required: true status: SUPPORTED + port_pcm_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string attributes: server_pcm_id: type: string diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/twoNestedNodeTemplatesWithSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/twoNestedNodeTemplatesWithSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml index 05a21ce6d1..51429041fe 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/twoNestedNodeTemplatesWithSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/nestedSingleCompute/twoNestedNodeTemplatesWithSameComputeType/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,6 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false @@ -23,6 +28,11 @@ topology_template: immutable: false type: string description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -41,12 +51,32 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false immutable: false type: string description: flavor name of PCRF CM instance + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string pcm_vol: label: CPS Cluman Cinder Volume hidden: false @@ -83,12 +113,32 @@ topology_template: immutable: false type: string description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json oam_net_name: label: OAM network name hidden: false immutable: false type: string description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -101,15 +151,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -139,15 +209,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/GlobalSubstitutionTypesServiceTemplate.yaml index f3b983e920..c91ab33909 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,42 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +66,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/MainServiceTemplate.yaml index 7997fe0a81..cb58589bfe 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/MainServiceTemplate.yaml @@ -46,6 +46,21 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + port_pd01_port_replacement_policy: + - AUTO_PORT_1 + - AUTO_PORT_0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -67,21 +82,6 @@ topology_template: port_pd01_port_network: - Network-1 - Network-0 - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - port_pd01_port_replacement_policy: - - AUTO_PORT_1 - - AUTO_PORT_0 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW_SERVER_PD_2 - RAW_SERVER_PD_1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/Nested_pd_serverServiceTemplate.yaml index 45fd36f894..ce1fbac923 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePort/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,36 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +59,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,18 +112,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index 2080edef46..e073c59ae5 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,42 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +66,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/MainServiceTemplate.yaml index c87498fa1d..3f3be668d3 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/MainServiceTemplate.yaml @@ -60,6 +60,21 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + port_pd01_port_replacement_policy: + - AUTO_PORT_1 + - AUTO_PORT_0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -81,21 +96,6 @@ topology_template: port_pd01_port_network: - Network-1 - Network-0 - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - port_pd01_port_replacement_policy: - - AUTO_PORT_1 - - AUTO_PORT_0 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW_SERVER_PD_2 - RAW_SERVER_PD_1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml index 9923db380e..34003c6f29 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,36 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +59,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,18 +112,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/GlobalSubstitutionTypesServiceTemplate.yaml index 84dba74e5c..71c1bf5986 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,42 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +66,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/MainServiceTemplate.yaml index b31071fa0a..a5a1489254 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/MainServiceTemplate.yaml @@ -53,6 +53,23 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + port_pd01_port_replacement_policy: + - get_attribute: + - network_policy_server + - name + - AUTO_PORT_0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -74,23 +91,6 @@ topology_template: port_pd01_port_network: - Network-1 - Network-0 - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - port_pd01_port_replacement_policy: - - get_attribute: - - network_policy_server - - name - - AUTO_PORT_0 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW_SERVER_PD_2 - get_attribute: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/Nested_pd_serverServiceTemplate.yaml index c588df7d89..a4bb6fb890 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOut/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,36 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +59,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -91,18 +121,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/GlobalSubstitutionTypesServiceTemplate.yaml index 36bd7af7d6..18abf27241 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,30 +60,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json requirements: - dependency_pd_server: capability: tosca.capabilities.Node diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/MainServiceTemplate.yaml index bd65262adb..baffa1f9d1 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/MainServiceTemplate.yaml @@ -46,6 +46,18 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -67,18 +79,6 @@ topology_template: port_pd01_port_network: - Network-1 - Network-0 - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - vm_flavor_name: - get_input: pd_flavor_name service_template_filter: substitute_service_template: Nested_pd_serverServiceTemplate.yaml count: 2 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/Nested_pd_serverServiceTemplate.yaml index 1ebbdaa7f0..72af3bb88c 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortGetAttrOutComputePort/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,26 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json node_templates: pd_server: type: org.openecomp.resource.vfc.nodes.heat.pd_server @@ -72,18 +102,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_attribute: - pd_server - accessIPv4 + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index 1acef555cb..d594580a18 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,48 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_pd01_port_security_groups: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_mac_requirements: type: list required: true @@ -30,37 +72,31 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list required: true status: SUPPORTED - port_pd01_port_security_groups: + entry_schema: + type: string + port_pd01_port_vlan_requirements: type: list required: true status: SUPPORTED diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/MainServiceTemplate.yaml index ae7dd92592..8984db0da7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/MainServiceTemplate.yaml @@ -67,6 +67,24 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + port_pd01_port_replacement_policy: + - AUTO_PORT_1 + - AUTO_PORT_0 + vm_flavor_name: + get_input: pd_flavor_name + port_pd01_port_security_groups: + - - jsa_security_group + - - jsa_security_group port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -88,24 +106,6 @@ topology_template: port_pd01_port_network: - Network-1 - Network-0 - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - port_pd01_port_replacement_policy: - - AUTO_PORT_1 - - AUTO_PORT_0 - vm_flavor_name: - get_input: pd_flavor_name - port_pd01_port_security_groups: - - - jsa_security_group - - - jsa_security_group compute_pd_server_user_data_format: - RAW_SERVER_PD_2 - RAW_SERVER_PD_1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml index a71e2c4593..9aa0aa9eb3 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,41 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_pd01_port_security_groups: + type: list + required: true + entry_schema: + type: json port_pd01_port_mac_requirements: type: list required: true @@ -29,32 +64,27 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list required: true - port_pd01_port_security_groups: + entry_schema: + type: string + port_pd01_port_vlan_requirements: type: list required: true entry_schema: @@ -91,18 +121,42 @@ topology_template: get_input: - port_pd01_port_security_groups - index_value + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml index f3b983e920..c91ab33909 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,42 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +66,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/MainServiceTemplate.yaml index 4ef370388a..8501ed37c2 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/MainServiceTemplate.yaml @@ -75,6 +75,21 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + port_pd01_port_replacement_policy: + - AUTO_PORT_1 + - AUTO_PORT_0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -96,21 +111,6 @@ topology_template: port_pd01_port_network: - packet_mirror_network - packet_mirror_network - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - port_pd01_port_replacement_policy: - - AUTO_PORT_1 - - AUTO_PORT_0 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW_SERVER_PD_2 - RAW_SERVER_PD_1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml index 45fd36f894..ce1fbac923 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,36 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +59,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,18 +112,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/GlobalSubstitutionTypesServiceTemplate.yaml index 96d645f0e2..27d88f15be 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,13 +8,49 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_pd01_port_mac_requirements: + compute_pd_server_scheduler_hints: type: list required: true status: SUPPORTED entry_schema: type: json - compute_pd_server_scheduler_hints: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_pd01_port_mac_requirements: type: list required: true status: SUPPORTED @@ -36,36 +72,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/MainServiceTemplate.yaml index baf0b4a3b2..d12bf29530 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/MainServiceTemplate.yaml @@ -46,14 +46,29 @@ topology_template: directives: - substitutable properties: + compute_pd_server_scheduler_hints: + - group: BE_Affinity_group + - group: BE_Affinity_group + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + port_pd01_port_replacement_policy: + - AUTO_PORT_1 + - AUTO_PORT_0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false - mac_count_required: is_required: false - compute_pd_server_scheduler_hints: - - group: BE_Affinity_group - - group: BE_Affinity_group vm_image_name: get_input: pd_image_name port_pd01_port_ip_requirements: @@ -70,21 +85,6 @@ topology_template: port_pd01_port_network: - Network-1 - Network-0 - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - port_pd01_port_replacement_policy: - - AUTO_PORT_1 - - AUTO_PORT_0 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW_SERVER_PD_2 - RAW_SERVER_PD_1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/Nested_pd_serverServiceTemplate.yaml index 0d1df3e26b..16c6ed13a1 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOneGroup/out/Nested_pd_serverServiceTemplate.yaml @@ -11,12 +11,42 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_pd01_port_mac_requirements: + compute_pd_server_scheduler_hints: type: list required: true entry_schema: type: json - compute_pd_server_scheduler_hints: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_pd01_port_mac_requirements: type: list required: true entry_schema: @@ -34,31 +64,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -91,18 +121,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index cf7b8e5315..8e7dc7ab42 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,42 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +66,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/MainServiceTemplate.yaml index 38f0073e5d..d1b8f72259 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/MainServiceTemplate.yaml @@ -46,6 +46,21 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + port_pd01_port_replacement_policy: + - AUTO_PORT_1 + - AUTO_PORT_0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -67,21 +82,6 @@ topology_template: port_pd01_port_network: - Network-1 - Network-0 - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - port_pd01_port_replacement_policy: - - AUTO_PORT_1 - - AUTO_PORT_0 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW_SERVER_PD_2 - RAW_SERVER_PD_1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml index f49877e3d1..b358a96558 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/oneComputeTypeOnePortOutputParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,36 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +59,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,18 +112,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/GlobalSubstitutionTypesServiceTemplate.yaml index cf85c2d08a..102842abb6 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,42 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +66,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -411,10 +447,12 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string + port_ps01_port_subnetpoolid: + type: list required: true status: SUPPORTED + entry_schema: + type: string compute_ps_server_availability_zone: type: list required: true @@ -435,6 +473,32 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 + port_ps01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_ps01_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + vm_image_name: + type: string + required: true + status: SUPPORTED + port_ps01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_ps01_port_replacement_policy: type: list required: true @@ -453,11 +517,19 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_ps01_port_ip_requirements: + type: list required: true status: SUPPORTED - port_ps01_port_ip_requirements: + entry_schema: + type: json + port_ps01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_ps01_port_exCP_naming: type: list required: true status: SUPPORTED diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/MainServiceTemplate.yaml index a1c581355c..661adcc7e4 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/MainServiceTemplate.yaml @@ -73,6 +73,21 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + port_pd01_port_replacement_policy: + - AUTO + - AUTO + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -94,21 +109,6 @@ topology_template: port_pd01_port_network: - Network-PD-1 - Network-PD-0 - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - port_pd01_port_replacement_policy: - - AUTO - - AUTO - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - null - RAW @@ -132,14 +132,16 @@ topology_template: - get_input: - ps_server_names - 1 - vm_image_name: - get_input: ps_image_name compute_ps_server_availability_zone: - get_input: availabilityzone_name - get_input: availabilityzone_name compute_ps_server_user_data_format: - null - RAW + vm_flavor_name: + get_input: ps_flavor_name + vm_image_name: + get_input: ps_image_name port_ps01_port_replacement_policy: - AUTO - AUTO @@ -151,8 +153,6 @@ topology_template: port_ps01_port_network: - Network-PS-0 - Network-PS-1 - vm_flavor_name: - get_input: ps_flavor_name port_ps01_port_ip_requirements: - - ip_version: 4 ip_count_required: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/Nested_pd_serverServiceTemplate.yaml index 45fd36f894..ce1fbac923 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,36 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +59,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,18 +112,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/Nested_ps_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/Nested_ps_serverServiceTemplate.yaml index 3de2a46d80..87e999cf79 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/Nested_ps_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePort/out/Nested_ps_serverServiceTemplate.yaml @@ -16,9 +16,11 @@ topology_template: required: true entry_schema: type: string - vm_image_name: - type: string + port_ps01_port_subnetpoolid: + type: list required: true + entry_schema: + type: string compute_ps_server_availability_zone: type: list required: true @@ -36,6 +38,27 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_ps01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_ps01_port_order: + type: list + required: true + entry_schema: + type: integer + vm_image_name: + type: string + required: true + port_ps01_port_network_role: + type: list + required: true + entry_schema: + type: string port_ps01_port_replacement_policy: type: list required: true @@ -51,14 +74,21 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string - required: true port_ps01_port_ip_requirements: type: list required: true entry_schema: type: json + port_ps01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_ps01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json node_templates: ps_server: type: org.openecomp.resource.vfc.nodes.heat.ps_server @@ -82,18 +112,42 @@ topology_template: ps_server_ps01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_ps01_port_exCP_naming + - index_value replacement_policy: get_input: - port_ps01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_ps01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_ps01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_ps01_port_network_role_tag + - index_value mac_requirements: get_input: - port_ps01_port_mac_requirements - index_value + order: + get_input: + - port_ps01_port_order + - index_value + network_role: + get_input: + - port_ps01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_ps01_port_subnetpoolid + - index_value network: get_input: - port_ps01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/GlobalSubstitutionTypesServiceTemplate.yaml index c814e074c2..762c7c10c4 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,42 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +66,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -417,10 +453,12 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string + port_ps01_port_subnetpoolid: + type: list required: true status: SUPPORTED + entry_schema: + type: string compute_ps_server_availability_zone: type: list required: true @@ -441,6 +479,32 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 + port_ps01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_ps01_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + vm_image_name: + type: string + required: true + status: SUPPORTED + port_ps01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_ps01_port_replacement_policy: type: list required: true @@ -459,11 +523,19 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_ps01_port_ip_requirements: + type: list required: true status: SUPPORTED - port_ps01_port_ip_requirements: + entry_schema: + type: json + port_ps01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_ps01_port_exCP_naming: type: list required: true status: SUPPORTED diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/MainServiceTemplate.yaml index 871efb849a..2174bb769f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/MainServiceTemplate.yaml @@ -73,6 +73,21 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + - get_input: + - pd_server_names + - 0 + port_pd01_port_replacement_policy: + - AUTO + - AUTO + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -94,21 +109,6 @@ topology_template: port_pd01_port_network: - Network-PD-1 - Network-PD-0 - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - - get_input: - - pd_server_names - - 0 - port_pd01_port_replacement_policy: - - AUTO - - AUTO - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - null - get_attribute: @@ -134,8 +134,6 @@ topology_template: - get_input: - ps_server_names - 1 - vm_image_name: - get_input: ps_image_name compute_ps_server_availability_zone: - get_input: availabilityzone_name - get_input: availabilityzone_name @@ -144,6 +142,10 @@ topology_template: - abstract_pd_server - pd_server_accessIPv4 - null + vm_flavor_name: + get_input: ps_flavor_name + vm_image_name: + get_input: ps_image_name port_ps01_port_replacement_policy: - AUTO - AUTO @@ -155,8 +157,6 @@ topology_template: port_ps01_port_network: - Network-PS-0 - Network-PS-1 - vm_flavor_name: - get_input: ps_flavor_name port_ps01_port_ip_requirements: - - ip_version: 4 ip_count_required: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/Nested_pd_serverServiceTemplate.yaml index dc5f1e5474..a03be48f50 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,36 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +59,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - port_pd01_port_replacement_policy: + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,18 +112,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/Nested_ps_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/Nested_ps_serverServiceTemplate.yaml index be9be2ceb6..f65ddfa0ca 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/Nested_ps_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/scalingInstances/twoComputeTypesOnePortWithGetAttr/out/Nested_ps_serverServiceTemplate.yaml @@ -16,9 +16,11 @@ topology_template: required: true entry_schema: type: string - vm_image_name: - type: string + port_ps01_port_subnetpoolid: + type: list required: true + entry_schema: + type: string compute_ps_server_availability_zone: type: list required: true @@ -36,6 +38,27 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_ps01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_ps01_port_order: + type: list + required: true + entry_schema: + type: integer + vm_image_name: + type: string + required: true + port_ps01_port_network_role: + type: list + required: true + entry_schema: + type: string port_ps01_port_replacement_policy: type: list required: true @@ -51,14 +74,21 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string - required: true port_ps01_port_ip_requirements: type: list required: true entry_schema: type: json + port_ps01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_ps01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json node_templates: ps_server: type: org.openecomp.resource.vfc.nodes.heat.ps_server @@ -82,18 +112,42 @@ topology_template: ps_server_ps01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_ps01_port_exCP_naming + - index_value replacement_policy: get_input: - port_ps01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_ps01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_ps01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_ps01_port_network_role_tag + - index_value mac_requirements: get_input: - port_ps01_port_mac_requirements - index_value + order: + get_input: + - port_ps01_port_order + - index_value + network_role: + get_input: + - port_ps01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_ps01_port_subnetpoolid + - index_value network: get_input: - port_ps01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortType/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortType/out/GlobalSubstitutionTypesServiceTemplate.yaml index 73f2c6fad8..b003fc2638 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortType/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortType/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -34,10 +34,28 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_flavor_name: type: string required: true status: SUPPORTED + port_pd02_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -50,6 +68,12 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_image_name: type: string required: true @@ -66,6 +90,36 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true @@ -78,6 +132,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd02_port_network: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortType/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortType/out/Nested_pd_serverServiceTemplate.yaml index e9da306669..6d0690a78d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortType/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortType/out/Nested_pd_serverServiceTemplate.yaml @@ -33,9 +33,24 @@ topology_template: required: true entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json vm_flavor_name: type: string required: true + port_pd02_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -46,6 +61,11 @@ topology_template: required: true entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json vm_image_name: type: string required: true @@ -59,6 +79,31 @@ topology_template: required: true entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true @@ -69,6 +114,11 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd02_port_network: type: list required: true @@ -102,6 +152,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -114,6 +172,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network @@ -126,6 +196,14 @@ topology_template: pd_server_pd02_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd02_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd02_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd02_port_ip_requirements @@ -138,6 +216,18 @@ topology_template: get_input: - port_pd02_port_mac_requirements - index_value + order: + get_input: + - port_pd02_port_order + - index_value + network_role: + get_input: + - port_pd02_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd02_port_subnetpoolid + - index_value network: get_input: - port_pd02_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/GlobalSubstitutionTypesServiceTemplate.yaml index 33a9362697..cad5199137 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,29 +8,25 @@ node_types: org.openecomp.resource.abstract.nodes.smp: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_port_ip_requirements: + port_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_port_mac_requirements: + port_port_network: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_port_network: + type: string + compute_smp_name: type: list required: true status: SUPPORTED entry_schema: type: string - compute_smp_name: + port_port_subnetpoolid: type: list required: true status: SUPPORTED @@ -50,28 +46,68 @@ node_types: status: SUPPORTED entry_schema: type: string + port_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string vm_flavor_name: type: string required: true status: SUPPORTED - compute_smp_metadata: + compute_smp_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - compute_smp_user_data_format: + port_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string + vm_image_name: + type: string + required: true + status: SUPPORTED + compute_smp_metadata: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_port_replacement_policy: type: list required: true status: SUPPORTED entry_schema: type: string + port_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer compute_smp_scheduler_hints: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/MainServiceTemplate.yaml index 9a471a91a9..6b57e2663d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/MainServiceTemplate.yaml @@ -55,17 +55,9 @@ topology_template: directives: - substitutable properties: - port_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false port_port_mac_requirements: - mac_count_required: is_required: false - vm_image_name: - get_input: image_smp_name port_port_network: - get_input: port_name compute_smp_name: @@ -74,14 +66,22 @@ topology_template: - get_input: availability_zone_0 vm_flavor_name: get_input: flavor_smp_name + compute_smp_user_data_format: + - RAW + port_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: image_smp_name compute_smp_metadata: - jx_vm_role: smp2 vnf_id: get_input: vnf_id jx_lab_name: get_input: lab_name - compute_smp_user_data_format: - - RAW port_port_replacement_policy: - AUTO compute_smp_scheduler_hints: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/Nested_smpServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/Nested_smpServiceTemplate.yaml index 79e0b10db2..77117043d6 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/Nested_smpServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeAndServerGroup/out/Nested_smpServiceTemplate.yaml @@ -11,19 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_port_ip_requirements: - type: list - required: true - entry_schema: - type: json port_port_mac_requirements: type: list required: true entry_schema: type: json - vm_image_name: - type: string - required: true port_port_network: type: list required: true @@ -34,6 +26,11 @@ topology_template: required: true entry_schema: type: string + port_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string index_value: type: integer description: Index value of this substitution service template runtime instance @@ -46,24 +43,57 @@ topology_template: required: true entry_schema: type: string + port_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_port_network_role_tag: + type: list + required: true + entry_schema: + type: string vm_flavor_name: type: string required: true - compute_smp_metadata: + compute_smp_user_data_format: + type: list + required: true + entry_schema: + type: string + port_port_ip_requirements: type: list required: true entry_schema: type: json - compute_smp_user_data_format: + port_port_network_role: type: list required: true entry_schema: type: string + vm_image_name: + type: string + required: true + compute_smp_metadata: + type: list + required: true + entry_schema: + type: json + port_port_exCP_naming: + type: list + required: true + entry_schema: + type: json port_port_replacement_policy: type: list required: true entry_schema: type: string + port_port_order: + type: list + required: true + entry_schema: + type: integer compute_smp_scheduler_hints: type: list required: true @@ -73,18 +103,42 @@ topology_template: smp_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_port_exCP_naming + - index_value replacement_policy: get_input: - port_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_port_vlan_requirements + - index_value ip_requirements: get_input: - port_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_port_network_role_tag + - index_value mac_requirements: get_input: - port_port_mac_requirements - index_value + order: + get_input: + - port_port_order + - index_value + network_role: + get_input: + - port_port_network_role + - index_value + subnetpoolid: + get_input: + - port_port_subnetpoolid + - index_value network: get_input: - port_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index b6c7aa061c..2adc34400a 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,14 +8,6 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 compute_pd_server_availability_zone: type: list required: true @@ -34,12 +26,6 @@ node_types: status: SUPPORTED entry_schema: type: string - port_pd02_port_mac_requirements: - type: list - required: true - status: SUPPORTED - entry_schema: - type: json vm_flavor_name: type: string required: true @@ -66,19 +52,75 @@ node_types: type: string required: true status: SUPPORTED - port_pd02_port_security_groups: + port_pd02_port_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_pd02_port_replacement_policy: + port_pd02_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_ip_requirements: + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + compute_pd_server_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_pd02_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd02_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd02_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd02_port_security_groups: type: list required: true status: SUPPORTED @@ -90,25 +132,43 @@ node_types: status: SUPPORTED entry_schema: type: string - port_pd02_port_ip_requirements: + port_pd01_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd02_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: type: json - port_pd01_port_network_role_tag: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd02_port_network: + port_pd02_port_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_user_data_format: + port_pd02_port_network: type: list required: true status: SUPPORTED diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/MainServiceTemplate.yaml index ea3d41d97c..751466605b 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/MainServiceTemplate.yaml @@ -104,9 +104,6 @@ topology_template: - 0 port_pd01_port_replacement_policy: - AUTO - port_pd02_port_mac_requirements: - - mac_count_required: - is_required: false vm_flavor_name: get_input: pd_flavor_name port_pd01_port_security_groups: @@ -118,8 +115,6 @@ topology_template: is_required: false vm_image_name: get_input: pd_image_name - port_pd02_port_security_groups: - - - jsa_security_group port_pd02_port_replacement_policy: - AUTO port_pd01_port_ip_requirements: @@ -128,6 +123,13 @@ topology_template: is_required: false floating_ip_count_required: is_required: false + compute_pd_server_user_data_format: + - RAW + port_pd02_port_mac_requirements: + - mac_count_required: + is_required: false + port_pd02_port_security_groups: + - - jsa_security_group port_pd01_port_network: - get_input: oam_net_name port_pd02_port_ip_requirements: @@ -140,8 +142,6 @@ topology_template: - oam port_pd02_port_network: - get_input: oam_net_name - compute_pd_server_user_data_format: - - RAW service_template_filter: substitute_service_template: Nested_pd_serverServiceTemplate.yaml count: 1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml index cefeecf3ff..159644651b 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml @@ -11,13 +11,6 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 compute_pd_server_availability_zone: type: list required: true @@ -33,11 +26,6 @@ topology_template: required: true entry_schema: type: string - port_pd02_port_mac_requirements: - type: list - required: true - entry_schema: - type: json vm_flavor_name: type: string required: true @@ -59,17 +47,64 @@ topology_template: vm_image_name: type: string required: true - port_pd02_port_security_groups: + port_pd02_port_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_ip_requirements: type: list required: true entry_schema: type: json - port_pd02_port_replacement_policy: + port_pd02_port_network_role: type: list required: true entry_schema: type: string - port_pd01_port_ip_requirements: + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + compute_pd_server_user_data_format: + type: list + required: true + entry_schema: + type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + port_pd02_port_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd02_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd02_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pd02_port_security_groups: type: list required: true entry_schema: @@ -79,22 +114,37 @@ topology_template: required: true entry_schema: type: string - port_pd02_port_ip_requirements: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd02_port_exCP_naming: type: list required: true entry_schema: type: json - port_pd01_port_network_role_tag: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - port_pd02_port_network: + port_pd02_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - compute_pd_server_user_data_format: + port_pd02_port_network: type: list required: true entry_schema: @@ -126,10 +176,18 @@ topology_template: get_input: - port_pd01_port_security_groups - index_value + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -142,6 +200,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network @@ -158,10 +228,18 @@ topology_template: get_input: - port_pd02_port_security_groups - index_value + exCP_naming: + get_input: + - port_pd02_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd02_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd02_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd02_port_ip_requirements @@ -174,6 +252,18 @@ topology_template: get_input: - port_pd02_port_mac_requirements - index_value + order: + get_input: + - port_pd02_port_order + - index_value + network_role: + get_input: + - port_pd02_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd02_port_subnetpoolid + - index_value network: get_input: - port_pd02_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml index c2a86696e4..d18921cdfa 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,14 +8,6 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 compute_pd_server_availability_zone: type: list required: true @@ -34,16 +26,16 @@ node_types: status: SUPPORTED entry_schema: type: string - port_pd02_port_mac_requirements: - type: list - required: true - status: SUPPORTED - entry_schema: - type: json vm_flavor_name: type: string required: true status: SUPPORTED + port_pd02_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_mac_requirements: type: list required: true @@ -66,25 +58,105 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd02_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + compute_pd_server_user_data_format: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_pd02_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd02_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd02_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_network: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_pd02_port_network: + port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_user_data_format: + port_pd02_port_network: type: list required: true status: SUPPORTED diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/MainServiceTemplate.yaml index 8bc75d63cf..1e714f26c2 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/MainServiceTemplate.yaml @@ -100,9 +100,6 @@ topology_template: - 0 port_pd01_port_replacement_policy: - AUTO - port_pd02_port_mac_requirements: - - mac_count_required: - is_required: false vm_flavor_name: get_input: pd_flavor_name port_pd01_port_mac_requirements: @@ -118,6 +115,11 @@ topology_template: is_required: false floating_ip_count_required: is_required: false + compute_pd_server_user_data_format: + - RAW + port_pd02_port_mac_requirements: + - mac_count_required: + is_required: false port_pd01_port_network: - packet_mirror_network port_pd02_port_ip_requirements: @@ -128,8 +130,6 @@ topology_template: is_required: false port_pd02_port_network: - packet_mirror_network - compute_pd_server_user_data_format: - - RAW service_template_filter: substitute_service_template: Nested_pd_serverServiceTemplate.yaml count: 1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml index 9d86566e4f..64104dc20f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithDiffPortTypeNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml @@ -11,13 +11,6 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 compute_pd_server_availability_zone: type: list required: true @@ -33,14 +26,14 @@ topology_template: required: true entry_schema: type: string - port_pd02_port_mac_requirements: - type: list - required: true - entry_schema: - type: json vm_flavor_name: type: string required: true + port_pd02_port_network_role_tag: + type: list + required: true + entry_schema: + type: string port_pd01_port_mac_requirements: type: list required: true @@ -59,22 +52,89 @@ topology_template: required: true entry_schema: type: json + port_pd02_port_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + compute_pd_server_user_data_format: + type: list + required: true + entry_schema: + type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + port_pd02_port_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd02_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd02_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd01_port_network: type: list required: true entry_schema: type: string + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true entry_schema: type: json - port_pd02_port_network: + port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string - compute_pd_server_user_data_format: + port_pd02_port_network: type: list required: true entry_schema: @@ -102,18 +162,42 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network @@ -126,18 +210,42 @@ topology_template: pd_server_pd02_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd02_port_exCP_naming + - index_value replacement_policy: get_input: - port_pd02_port_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd02_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd02_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd02_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd02_port_mac_requirements - index_value + order: + get_input: + - port_pd02_port_order + - index_value + network_role: + get_input: + - port_pd02_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd02_port_subnetpoolid + - index_value network: get_input: - port_pd02_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index cd7b7cd904..b956d579e3 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -32,26 +32,12 @@ node_types: status: SUPPORTED entry_schema: type: json - port_pd01_port_0_network_role_tag: + port_pd01_port_0_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_1_ip_requirements: - type: list - required: true - status: SUPPORTED - entry_schema: - type: json - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 compute_pd_server_availability_zone: type: list required: true @@ -74,23 +60,35 @@ node_types: type: string required: true status: SUPPORTED - port_pd01_port_1_mac_requirements: + port_pd01_port_1_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string + port_pd01_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string vm_image_name: type: string required: true status: SUPPORTED - port_pd01_port_1_replacement_policy: + port_pd01_port_1_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - port_pd01_port_1_network_role_tag: + port_pd01_port_0_subnetpoolid: type: list required: true status: SUPPORTED @@ -108,6 +106,68 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_0_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_1_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_pd01_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_0_security_groups: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/MainServiceTemplate.yaml index 215f5c0b83..7c295f9e48 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/MainServiceTemplate.yaml @@ -109,14 +109,6 @@ topology_template: is_required: false port_pd01_port_1_security_groups: - - jsa_security_group - port_pd01_port_0_network_role_tag: - - oam - port_pd01_port_1_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false compute_pd_server_availability_zone: - get_input: availabilityzone_name compute_pd_server_name: @@ -127,19 +119,27 @@ topology_template: - AUTO vm_flavor_name: get_input: pd_flavor_name - port_pd01_port_1_mac_requirements: - - mac_count_required: - is_required: false vm_image_name: get_input: pd_image_name - port_pd01_port_1_replacement_policy: - - AUTO port_pd01_port_1_network_role_tag: - oam port_pd01_port_1_network: - get_input: oam_net_name compute_pd_server_user_data_format: - RAW + port_pd01_port_0_network_role_tag: + - oam + port_pd01_port_1_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + port_pd01_port_1_mac_requirements: + - mac_count_required: + is_required: false + port_pd01_port_1_replacement_policy: + - AUTO port_pd01_port_0_security_groups: - - jsa_security_group service_template_filter: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml index cc1724133c..75533f5049 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedIn/out/Nested_pd_serverServiceTemplate.yaml @@ -31,23 +31,11 @@ topology_template: required: true entry_schema: type: json - port_pd01_port_0_network_role_tag: + port_pd01_port_0_network_role: type: list required: true entry_schema: type: string - port_pd01_port_1_ip_requirements: - type: list - required: true - entry_schema: - type: json - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 compute_pd_server_availability_zone: type: list required: true @@ -66,20 +54,30 @@ topology_template: vm_flavor_name: type: string required: true - port_pd01_port_1_mac_requirements: + port_pd01_port_1_network_role: type: list required: true entry_schema: - type: json + type: string + port_pd01_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string vm_image_name: type: string required: true - port_pd01_port_1_replacement_policy: + port_pd01_port_1_network_role_tag: type: list required: true entry_schema: type: string - port_pd01_port_1_network_role_tag: + port_pd01_port_0_subnetpoolid: type: list required: true entry_schema: @@ -94,6 +92,58 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_0_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_1_ip_requirements: + type: list + required: true + entry_schema: + type: json + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + port_pd01_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd01_port_0_security_groups: type: list required: true @@ -126,10 +176,18 @@ topology_template: get_input: - port_pd01_port_1_security_groups - index_value + exCP_naming: + get_input: + - port_pd01_port_1_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_1_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_1_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_1_ip_requirements @@ -142,6 +200,18 @@ topology_template: get_input: - port_pd01_port_1_mac_requirements - index_value + order: + get_input: + - port_pd01_port_1_order + - index_value + network_role: + get_input: + - port_pd01_port_1_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_1_subnetpoolid + - index_value network: get_input: - port_pd01_port_1_network @@ -158,10 +228,18 @@ topology_template: get_input: - port_pd01_port_0_security_groups - index_value + exCP_naming: + get_input: + - port_pd01_port_0_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_0_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_0_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_0_ip_requirements @@ -174,6 +252,18 @@ topology_template: get_input: - port_pd01_port_0_mac_requirements - index_value + order: + get_input: + - port_pd01_port_0_order + - index_value + network_role: + get_input: + - port_pd01_port_0_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_0_subnetpoolid + - index_value network: get_input: - port_pd01_port_0_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml index 00cd6b4b90..dc1dc15aaa 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -26,20 +26,12 @@ node_types: status: SUPPORTED entry_schema: type: json - port_pd01_port_1_ip_requirements: + port_pd01_port_0_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 + type: string compute_pd_server_availability_zone: type: list required: true @@ -62,17 +54,35 @@ node_types: type: string required: true status: SUPPORTED - port_pd01_port_1_mac_requirements: + port_pd01_port_1_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string + port_pd01_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string vm_image_name: type: string required: true status: SUPPORTED - port_pd01_port_1_replacement_policy: + port_pd01_port_1_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_0_subnetpoolid: type: list required: true status: SUPPORTED @@ -90,6 +100,68 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_0_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_1_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_pd01_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_replacement_policy: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json requirements: - dependency_pd_server: capability: tosca.capabilities.Node diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/MainServiceTemplate.yaml index 7a45084d24..17966e0c2f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/MainServiceTemplate.yaml @@ -109,12 +109,6 @@ topology_template: port_pd01_port_0_network: - packet_mirror_network port_pd01_port_0_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - port_pd01_port_1_ip_requirements: - - ip_version: 4 ip_count_required: is_required: false @@ -130,17 +124,23 @@ topology_template: - AUTO vm_flavor_name: get_input: pd_flavor_name - port_pd01_port_1_mac_requirements: - - mac_count_required: - is_required: false vm_image_name: get_input: pd_image_name - port_pd01_port_1_replacement_policy: - - AUTO port_pd01_port_1_network: - packet_internal_network compute_pd_server_user_data_format: - RAW + port_pd01_port_1_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + port_pd01_port_1_mac_requirements: + - mac_count_required: + is_required: false + port_pd01_port_1_replacement_policy: + - AUTO service_template_filter: substitute_service_template: Nested_pd_serverServiceTemplate.yaml count: 1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml index 44d11b66e1..560f18e726 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computeWithSamePortTypeNodeConnectedOut/out/Nested_pd_serverServiceTemplate.yaml @@ -26,18 +26,11 @@ topology_template: required: true entry_schema: type: json - port_pd01_port_1_ip_requirements: + port_pd01_port_0_network_role: type: list required: true entry_schema: - type: json - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 + type: string compute_pd_server_availability_zone: type: list required: true @@ -56,15 +49,30 @@ topology_template: vm_flavor_name: type: string required: true - port_pd01_port_1_mac_requirements: + port_pd01_port_1_network_role: type: list required: true entry_schema: - type: json + type: string + port_pd01_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string vm_image_name: type: string required: true - port_pd01_port_1_replacement_policy: + port_pd01_port_1_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_0_subnetpoolid: type: list required: true entry_schema: @@ -79,6 +87,58 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_0_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_1_ip_requirements: + type: list + required: true + entry_schema: + type: json + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + port_pd01_port_1_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_replacement_policy: + type: list + required: true + entry_schema: + type: string + port_pd01_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json node_templates: pd_server: type: org.openecomp.resource.vfc.nodes.heat.pd_server @@ -102,18 +162,42 @@ topology_template: pd_server_pd01_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_1_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_1_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_1_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_1_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_1_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_1_mac_requirements - index_value + order: + get_input: + - port_pd01_port_1_order + - index_value + network_role: + get_input: + - port_pd01_port_1_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_1_subnetpoolid + - index_value network: get_input: - port_pd01_port_1_network @@ -126,18 +210,42 @@ topology_template: pd_server_pd01_port_0: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_0_exCP_naming + - index_value replacement_policy: get_input: - port_pd01_port_0_replacement_policy - index_value + vlan_requirements: + get_input: + - port_pd01_port_0_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_0_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_0_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_0_mac_requirements - index_value + order: + get_input: + - port_pd01_port_0_order + - index_value + network_role: + get_input: + - port_pd01_port_0_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_0_subnetpoolid + - index_value network: get_input: - port_pd01_port_0_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/GlobalSubstitutionTypesServiceTemplate.yaml index 058fb9d6bd..857c88bd2e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -34,10 +34,28 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_flavor_name: type: string required: true status: SUPPORTED + port_pd02_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -50,6 +68,12 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_image_name: type: string required: true @@ -66,6 +90,36 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true @@ -78,6 +132,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd02_port_network: type: list required: true @@ -507,16 +567,23 @@ node_types: org.openecomp.resource.abstract.nodes.heat.pcm_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pcm_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string availabilityzone_name: type: string description: availabilityzone name required: true status: SUPPORTED - oam_net_gw: - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json pcm_image_name: type: string description: PCRF CM image name @@ -527,6 +594,62 @@ node_types: description: CPS network ip required: true status: SUPPORTED + port_pcm_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + pcm_server_name: + type: string + description: PCRF CM server name + required: true + status: SUPPORTED + cps_net_mask: + type: string + description: CPS network mask + required: true + status: SUPPORTED + port_pcm_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + oam_net_name: + type: string + description: OAM network name + required: true + status: SUPPORTED + port_pcm_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + oam_net_gw: + type: string + description: CPS network gateway + required: true + status: SUPPORTED security_group_name: type: string description: the name of security group @@ -542,6 +665,12 @@ node_types: description: CPS Cluman Cinder Volume required: true status: SUPPORTED + port_pcm_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json pcm_flavor_name: type: string description: flavor name of PCRF CM instance @@ -552,21 +681,11 @@ node_types: description: CPS Cluman Cinder Volume required: true status: SUPPORTED - pcm_server_name: - type: string - description: PCRF CM server name - required: true - status: SUPPORTED cps_net_name: type: string description: CPS network name required: true status: SUPPORTED - cps_net_mask: - type: string - description: CPS network mask - required: true - status: SUPPORTED oam_net_ip: type: string description: OAM network ip @@ -577,11 +696,12 @@ node_types: description: CPS network mask required: true status: SUPPORTED - oam_net_name: - type: string - description: OAM network name + port_pcm_port_1_order: + type: list required: true status: SUPPORTED + entry_schema: + type: integer attributes: server_pcm_id: type: string diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/Nested_pd_serverServiceTemplate.yaml index e9da306669..6d0690a78d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/Nested_pd_serverServiceTemplate.yaml @@ -33,9 +33,24 @@ topology_template: required: true entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json vm_flavor_name: type: string required: true + port_pd02_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -46,6 +61,11 @@ topology_template: required: true entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json vm_image_name: type: string required: true @@ -59,6 +79,31 @@ topology_template: required: true entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true @@ -69,6 +114,11 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd02_port_network: type: list required: true @@ -102,6 +152,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -114,6 +172,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network @@ -126,6 +196,14 @@ topology_template: pd_server_pd02_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd02_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd02_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd02_port_ip_requirements @@ -138,6 +216,18 @@ topology_template: get_input: - port_pd02_port_mac_requirements - index_value + order: + get_input: + - port_pd02_port_order + - index_value + network_role: + get_input: + - port_pd02_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd02_port_subnetpoolid + - index_value network: get_input: - port_pd02_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/nested-pcm_v0.1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/nested-pcm_v0.1ServiceTemplate.yaml index ba350ce357..8d7c6bd66a 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/nested-pcm_v0.1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwodiffporttypesandnested/out/nested-pcm_v0.1ServiceTemplate.yaml @@ -11,18 +11,22 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pcm_port_0_network_role: + type: list + required: true + entry_schema: + type: string availabilityzone_name: label: availabilityzone name hidden: false immutable: false type: string description: availabilityzone name - oam_net_gw: - label: CPS network gateway - hidden: false - immutable: false - type: string - description: CPS network gateway + port_pcm_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_image_name: label: image name hidden: false @@ -35,6 +39,60 @@ topology_template: immutable: false type: string description: CPS network ip + port_pcm_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pcm_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pcm_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + pcm_server_name: + label: PCRF CM server name + hidden: false + immutable: false + type: string + description: PCRF CM server name + cps_net_mask: + label: CPS network mask + hidden: false + immutable: false + type: string + description: CPS network mask + port_pcm_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pcm_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + oam_net_name: + label: OAM network name + hidden: false + immutable: false + type: string + description: OAM network name + port_pcm_port_1_network_role: + type: list + required: true + entry_schema: + type: string + oam_net_gw: + label: CPS network gateway + hidden: false + immutable: false + type: string + description: CPS network gateway security_group_name: label: security group name hidden: false @@ -53,6 +111,11 @@ topology_template: immutable: false type: string description: CPS Cluman Cinder Volume + port_pcm_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json pcm_flavor_name: label: PCRF CM flavor name hidden: false @@ -65,24 +128,12 @@ topology_template: immutable: false type: string description: CPS Cluman Cinder Volume - pcm_server_name: - label: PCRF CM server name - hidden: false - immutable: false - type: string - description: PCRF CM server name cps_net_name: label: CPS network name hidden: false immutable: false type: string description: CPS network name - cps_net_mask: - label: CPS network mask - hidden: false - immutable: false - type: string - description: CPS network mask oam_net_ip: label: OAM network ip hidden: false @@ -95,12 +146,11 @@ topology_template: immutable: false type: string description: CPS network mask - oam_net_name: - label: OAM network name - hidden: false - immutable: false - type: string - description: OAM network name + port_pcm_port_1_order: + type: list + required: true + entry_schema: + type: integer node_templates: pcm_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -113,15 +163,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_1_network_role + - index_value fixed_ips: - ip_address: get_input: oam_net_ip + subnetpoolid: + get_input: + - port_pcm_port_1_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_1_vlan_requirements + - index_value network_role_tag: oam network: get_input: oam_net_name + order: + get_input: + - port_pcm_port_1_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable @@ -151,15 +221,35 @@ topology_template: is_required: false security_groups: - get_input: security_group_name + network_role: + get_input: + - port_pcm_port_0_network_role + - index_value fixed_ips: - ip_address: get_input: cps_net_ip + subnetpoolid: + get_input: + - port_pcm_port_0_subnetpoolid + - index_value mac_requirements: mac_count_required: is_required: false + exCP_naming: + get_input: + - port_pcm_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pcm_port_0_vlan_requirements + - index_value network_role_tag: cps network: get_input: cps_net_name + order: + get_input: + - port_pcm_port_0_order + - index_value requirements: - binding: capability: tosca.capabilities.network.Bindable diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwosameporttypes/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwosameporttypes/out/GlobalSubstitutionTypesServiceTemplate.yaml index af15bfb115..a308e85feb 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwosameporttypes/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwosameporttypes/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -32,6 +32,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_1_ip_requirements: type: list required: true @@ -58,26 +64,80 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer vm_flavor_name: type: string required: true status: SUPPORTED + port_pd01_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_1_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_pd01_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string vm_image_name: type: string required: true status: SUPPORTED + port_pd01_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_1_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_1_network: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwosameporttypes/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwosameporttypes/out/Nested_pd_serverServiceTemplate.yaml index 236dc97e62..e2edfa3db1 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwosameporttypes/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/computewithtwosameporttypes/out/Nested_pd_serverServiceTemplate.yaml @@ -31,6 +31,11 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_0_network_role: + type: list + required: true + entry_schema: + type: string port_pd01_port_1_ip_requirements: type: list required: true @@ -53,22 +58,67 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_1_order: + type: list + required: true + entry_schema: + type: integer vm_flavor_name: type: string required: true + port_pd01_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd01_port_1_mac_requirements: type: list required: true entry_schema: type: json + port_pd01_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string vm_image_name: type: string required: true + port_pd01_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json port_pd01_port_1_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd01_port_1_network: type: list required: true @@ -102,6 +152,14 @@ topology_template: pd_server_pd01_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_1_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_1_ip_requirements @@ -114,6 +172,18 @@ topology_template: get_input: - port_pd01_port_1_mac_requirements - index_value + order: + get_input: + - port_pd01_port_1_order + - index_value + network_role: + get_input: + - port_pd01_port_1_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_1_subnetpoolid + - index_value network: get_input: - port_pd01_port_1_network @@ -126,6 +196,14 @@ topology_template: pd_server_pd01_port_0: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_0_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_0_ip_requirements @@ -138,6 +216,18 @@ topology_template: get_input: - port_pd01_port_0_mac_requirements - index_value + order: + get_input: + - port_pd01_port_0_order + - index_value + network_role: + get_input: + - port_pd01_port_0_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_0_subnetpoolid + - index_value network: get_input: - port_pd01_port_0_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/diffPortTypeAndOutParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/diffPortTypeAndOutParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index 8d72374fc5..f6428554bf 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/diffPortTypeAndOutParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/diffPortTypeAndOutParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -34,10 +34,28 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_flavor_name: type: string required: true status: SUPPORTED + port_pd02_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -50,6 +68,12 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_image_name: type: string required: true @@ -66,6 +90,36 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true @@ -78,6 +132,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd02_port_network: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/diffPortTypeAndOutParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/diffPortTypeAndOutParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml index 073e86d1cb..bd885f9dbe 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/diffPortTypeAndOutParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/diffPortTypeAndOutParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml @@ -33,9 +33,24 @@ topology_template: required: true entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json vm_flavor_name: type: string required: true + port_pd02_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -46,6 +61,11 @@ topology_template: required: true entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json vm_image_name: type: string required: true @@ -59,6 +79,31 @@ topology_template: required: true entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true @@ -69,6 +114,11 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd02_port_network: type: list required: true @@ -102,6 +152,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -114,6 +172,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network @@ -126,6 +196,14 @@ topology_template: pd_server_pd02_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd02_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd02_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd02_port_ip_requirements @@ -138,6 +216,18 @@ topology_template: get_input: - port_pd02_port_mac_requirements - index_value + order: + get_input: + - port_pd02_port_order + - index_value + network_role: + get_input: + - port_pd02_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd02_port_subnetpoolid + - index_value network: get_input: - port_pd02_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/GlobalSubstitutionTypesServiceTemplate.yaml index d1f7bb0857..d53617ed8d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -14,6 +14,112 @@ node_types: status: SUPPORTED entry_schema: type: string + port_FSB2_Internal2_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_FSB_OAM_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + compute_FSB2_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal2_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal1_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal2_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_FSB2_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_mac_address: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal2_mac_address: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_FSB2_Internal2_mac_requirements: type: list required: true @@ -40,41 +146,37 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_FSB2_Internal2_network: + port_FSB_OAM_order: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED - compute_FSB2_availability_zone: + type: integer + port_FSB2_Internal2_network: type: list required: true status: SUPPORTED entry_schema: type: string - port_FSB_OAM_ip_requirements: + port_FSB2_Internal2_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_FSB2_Internal1_ip_requirements: + port_FSB2_Internal1_order: type: list required: true status: SUPPORTED entry_schema: - type: json - compute_FSB2_name: + type: integer + port_FSB2_Internal2_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_FSB2_Internal1_mac_address: + port_FSB2_Internal1_network_role_tag: type: list required: true status: SUPPORTED @@ -92,24 +194,24 @@ node_types: status: SUPPORTED entry_schema: type: json - port_FSB_OAM_network: + port_FSB2_Internal2_order: type: list required: true status: SUPPORTED entry_schema: - type: string - port_FSB2_Internal1_network: + type: integer + port_FSB2_Internal1_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_FSB2_Internal2_mac_address: + port_FSB_OAM_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json requirements: - dependency_FSB2_FSB_OAM: capability: tosca.capabilities.Node @@ -605,12 +707,12 @@ node_types: org.openecomp.resource.abstract.nodes.VLC2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_VLC_SCTP_A_network: + port_VLC_GTP_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json port_VLC_OAM_network_role_tag: type: list required: true @@ -651,24 +753,24 @@ node_types: status: SUPPORTED entry_schema: type: json - port_VLC_OAM_ip_requirements: + port_VLC2_Internal1_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string port_VLC2_Internal2_mac_address: type: list required: true status: SUPPORTED entry_schema: type: string - port_VLC_OAM_fixed_ips: + port_VLC_GTP_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string vm_image_name: type: string required: true @@ -691,12 +793,6 @@ node_types: status: SUPPORTED entry_schema: type: json - port_VLC_SCTP_A_ip_requirements: - type: list - required: true - status: SUPPORTED - entry_schema: - type: json port_VLC_SCTP_B_network: type: list required: true @@ -715,127 +811,343 @@ node_types: status: SUPPORTED entry_schema: type: json - compute_VLC2_name: + port_VLC_GTP_order: type: list required: true status: SUPPORTED entry_schema: - type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + type: integer + port_VLC_OAM_exCP_naming: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - port_VLC_SCTP_B_fixed_ips: + entry_schema: + type: json + port_VLC_SCTP_A_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_GTP_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC_GTP_mac_requirements: + port_VLC_GTP_fixed_ips: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC2_Internal1_network: + port_VLC_OAM_network: type: list required: true status: SUPPORTED entry_schema: type: string - compute_VLC2_availability_zone: + port_VLC2_Internal2_network: type: list required: true status: SUPPORTED entry_schema: type: string - port_VLC_GTP_fixed_ips: + port_VLC_SCTP_A_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_A_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC_OAM_mac_requirements: + port_VLC_SCTP_A_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC_SCTP_B_exCP_naming: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC_OAM_network: + port_VLC_SCTP_A_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_OAM_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_OAM_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_OAM_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC2_Internal1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC_OAM_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_VLC_SCTP_B_mac_requirements: + port_VLC_SCTP_A_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC2_Internal2_network: + port_VLC2_Internal2_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_SCTP_A_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - requirements: - - dependency_VLC2_VLC2_Internal2: - capability: tosca.capabilities.Node - node: tosca.nodes.Root - relationship: tosca.relationships.DependsOn - occurrences: - - 0 - - UNBOUNDED - - link_VLC2_VLC2_Internal2: - capability: tosca.capabilities.network.Linkable - relationship: tosca.relationships.network.LinksTo - occurrences: - - 1 - - 1 - - dependency_VLC2_VLC_OAM: - capability: tosca.capabilities.Node - node: tosca.nodes.Root - relationship: tosca.relationships.DependsOn - occurrences: - - 0 - - UNBOUNDED - - link_VLC2_VLC_OAM: - capability: tosca.capabilities.network.Linkable - relationship: tosca.relationships.network.LinksTo - occurrences: - - 1 - - 1 - - dependency_VLC2_VLC2_Internal1: - capability: tosca.capabilities.Node - node: tosca.nodes.Root - relationship: tosca.relationships.DependsOn - occurrences: - - 0 - - UNBOUNDED - - link_VLC2_VLC2_Internal1: - capability: tosca.capabilities.network.Linkable - relationship: tosca.relationships.network.LinksTo - occurrences: - - 1 - - 1 - - dependency_VLC2_VLC_SCTP_A: - capability: tosca.capabilities.Node - node: tosca.nodes.Root - relationship: tosca.relationships.DependsOn - occurrences: - - 0 - - UNBOUNDED - - link_VLC2_VLC_SCTP_A: - capability: tosca.capabilities.network.Linkable - relationship: tosca.relationships.network.LinksTo - occurrences: - - 1 - - 1 + port_VLC_OAM_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_B_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_VLC2_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_OAM_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC2_Internal1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC2_Internal2_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_VLC_SCTP_B_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC2_Internal2_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_B_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_GTP_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_A_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC2_Internal2_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC_GTP_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC2_Internal1_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_VLC2_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC2_Internal1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_OAM_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC2_Internal1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC2_Internal2_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_B_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC2_Internal2_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_SCTP_B_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC_GTP_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC2_Internal1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_B_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_SCTP_B_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + requirements: + - dependency_VLC2_VLC2_Internal2: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - link_VLC2_VLC2_Internal2: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo + occurrences: + - 1 + - 1 + - dependency_VLC2_VLC_OAM: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - link_VLC2_VLC_OAM: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo + occurrences: + - 1 + - 1 + - dependency_VLC2_VLC2_Internal1: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - link_VLC2_VLC2_Internal1: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo + occurrences: + - 1 + - 1 + - dependency_VLC2_VLC_SCTP_A: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - link_VLC2_VLC_SCTP_A: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo + occurrences: + - 1 + - 1 - dependency_VLC2_VLC_SCTP_B: capability: tosca.capabilities.Node node: tosca.nodes.Root @@ -1512,32 +1824,24 @@ node_types: org.openecomp.resource.abstract.nodes.NCB1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_NCB1_Internal2_mac_address: + port_NCB1_Internal1_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - port_NCB1_Internal1_mac_address: + port_NCB1_Internal2_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_NCB1_Internal1_ip_requirements: + port_NCB1_Internal1_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string vm_flavor_name: type: string required: true @@ -1548,68 +1852,148 @@ node_types: status: SUPPORTED entry_schema: type: string - port_NCB1_Internal1_mac_requirements: + port_NCB1_Internal2_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_NCB1_Internal2_mac_requirements: + vm_image_name: + type: string + required: true + status: SUPPORTED + port_NCB1_Internal2_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_NCB1_Internal2_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_NCB1_Internal1_network: + port_NCB1_Internal1_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_NCB1_availability_zone: + type: json + port_NCB1_Internal1_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string + port_NCB1_Internal2_vlan_requirements: + type: list required: true status: SUPPORTED - port_NCB1_Internal2_ip_requirements: + entry_schema: + type: json + port_NCB1_Internal2_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json - port_NCB1_Internal2_network: + type: string + port_NCB1_Internal2_mac_address: type: list required: true status: SUPPORTED entry_schema: type: string - requirements: - - dependency_NCB1: - capability: tosca.capabilities.Node - node: tosca.nodes.Root - relationship: tosca.relationships.DependsOn - occurrences: - - 0 - - UNBOUNDED - - local_storage_NCB1: - capability: tosca.capabilities.Attachment - node: tosca.nodes.BlockStorage - relationship: tosca.relationships.AttachesTo - occurrences: - - 0 - - UNBOUNDED - - dependency_NCB1_NCB1_Internal1: - capability: tosca.capabilities.Node - node: tosca.nodes.Root - relationship: tosca.relationships.DependsOn - occurrences: - - 0 - - UNBOUNDED + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_NCB1_Internal1_mac_address: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_NCB1_Internal1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_NCB1_Internal2_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_NCB1_Internal1_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_NCB1_Internal1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_NCB1_Internal1_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_NCB1_Internal1_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_NCB1_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_NCB1_Internal2_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_NCB1_Internal2_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + requirements: + - dependency_NCB1: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - local_storage_NCB1: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: + - 0 + - UNBOUNDED + - dependency_NCB1_NCB1_Internal1: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED - link_NCB1_NCB1_Internal1: capability: tosca.capabilities.network.Linkable relationship: tosca.relationships.network.LinksTo @@ -2005,6 +2389,62 @@ node_types: org.openecomp.resource.abstract.nodes.NCB2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + compute_NCB2_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_NCB2_Internal2_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_NCB2_Internal1_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_NCB2_Internal1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_NCB2_Internal2_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_NCB2_Internal1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_NCB2_Internal1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_NCB2_Internal2_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string index_value: type: integer description: Index value of this substitution service template runtime instance @@ -2019,62 +2459,78 @@ node_types: status: SUPPORTED entry_schema: type: string - compute_NCB2_availability_zone: + port_NCB2_Internal2_ip_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string - port_NCB2_Internal2_ip_requirements: + type: json + port_NCB2_Internal2_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_flavor_name: - type: string + type: string + port_NCB2_Internal2_network: + type: list required: true status: SUPPORTED - port_NCB2_Internal2_mac_requirements: + entry_schema: + type: string + port_NCB2_Internal2_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_NCB2_Internal2_network: + port_NCB2_Internal1_mac_address: type: list required: true status: SUPPORTED entry_schema: type: string - port_NCB2_Internal1_mac_requirements: + port_NCB2_Internal2_mac_address: type: list required: true status: SUPPORTED entry_schema: - type: json - port_NCB2_Internal1_mac_address: + type: string + port_NCB2_Internal1_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_NCB2_Internal2_mac_address: + port_NCB2_Internal1_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string + port_NCB2_Internal2_order: + type: list required: true status: SUPPORTED + entry_schema: + type: integer compute_NCB2_name: type: list required: true status: SUPPORTED entry_schema: type: string + port_NCB2_Internal1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_NCB2_Internal2_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_NCB2_Internal1_ip_requirements: type: list required: true @@ -2498,6 +2954,74 @@ node_types: org.openecomp.resource.abstract.nodes.GPB2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_GPB2_Internal2_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB2_Internal2_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_GPB2_Internal1_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB2_Internal1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_GPB2_Internal2_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED + port_GPB2_Internal2_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_GPB2_Internal1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_GPB2_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB2_Internal1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB2_Internal2_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_GPB2_Internal2_mac_address: type: list required: true @@ -2516,7 +3040,7 @@ node_types: status: SUPPORTED entry_schema: type: json - port_GPB2_Internal1_network: + port_GPB2_Internal2_network_role: type: list required: true status: SUPPORTED @@ -2536,27 +3060,31 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_GPB2_Internal2_exCP_naming: + type: list required: true status: SUPPORTED - port_GPB2_Internal1_mac_requirements: + entry_schema: + type: json + port_GPB2_Internal1_order: type: list required: true status: SUPPORTED entry_schema: - type: json - port_GPB2_Internal2_ip_requirements: + type: integer + port_GPB2_Internal1_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - vm_image_name: - type: string + port_GPB2_Internal1_exCP_naming: + type: list required: true status: SUPPORTED - compute_GPB2_name: + entry_schema: + type: json + port_GPB2_Internal1_network_role_tag: type: list required: true status: SUPPORTED @@ -2997,36 +3525,42 @@ node_types: status: SUPPORTED entry_schema: type: string - port_VLC1_Internal1_network: + port_VLC_GTP_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - port_VLC_SCTP_A_network: + type: json + port_VLC_OAM_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - port_VLC_OAM_network_role_tag: + port_VLC1_Internal1_mac_address: type: list required: true status: SUPPORTED entry_schema: type: string - port_VLC1_Internal1_mac_address: + port_VLC_GTP_ip_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string - port_VLC_GTP_ip_requirements: + type: json + port_VLC1_Internal2_exCP_naming: type: list required: true status: SUPPORTED entry_schema: type: json + port_VLC1_Internal2_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_VLC_SCTP_A_mac_requirements: type: list required: true @@ -3055,6 +3589,160 @@ node_types: status: SUPPORTED entry_schema: type: json + port_VLC1_Internal2_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_GTP_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_image_name: + type: string + required: true + status: SUPPORTED + port_VLC1_Internal1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_B_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC1_Internal1_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_GTP_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_GTP_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC_OAM_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC1_Internal1_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC1_Internal1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC1_Internal1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC_SCTP_A_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_GTP_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_GTP_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_OAM_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_VLC1_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC1_Internal2_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC1_Internal1_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_A_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_A_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC1_Internal1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_A_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC_SCTP_B_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_SCTP_A_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_OAM_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_VLC_OAM_ip_requirements: type: list required: true @@ -3067,40 +3755,72 @@ node_types: status: SUPPORTED entry_schema: type: json - port_VLC_OAM_fixed_ips: + port_VLC_OAM_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC1_Internal2_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_OAM_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC1_Internal2_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC1_Internal2_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_A_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_VLC_SCTP_A_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json - vm_image_name: - type: string - required: true - status: SUPPORTED - port_VLC_SCTP_A_ip_requirements: + type: string + compute_VLC1_availability_zone: type: list required: true status: SUPPORTED entry_schema: - type: json - port_VLC_SCTP_B_network: + type: string + port_VLC_OAM_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_VLC_GTP_network: + port_VLC_SCTP_B_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string - compute_VLC1_availability_zone: + port_VLC_OAM_order: type: list required: true status: SUPPORTED entry_schema: - type: string + type: integer index_value: type: integer description: Index value of this substitution service template runtime instance @@ -3109,66 +3829,84 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_VLC1_Internal1_mac_requirements: + port_VLC1_Internal2_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC1_Internal2_mac_requirements: + port_VLC_SCTP_B_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string port_VLC_SCTP_B_fixed_ips: type: list required: true status: SUPPORTED entry_schema: type: json + port_VLC_GTP_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_VLC_SCTP_A_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_VLC_GTP_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC_GTP_fixed_ips: + port_VLC_OAM_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC_OAM_mac_requirements: + port_VLC1_Internal1_exCP_naming: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC_OAM_network: + port_VLC_SCTP_B_mac_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_VLC1_name: + type: json + port_VLC_SCTP_B_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_VLC_GTP_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_VLC_SCTP_B_mac_requirements: + port_VLC_SCTP_B_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_VLC1_Internal2_ip_requirements: + port_VLC_SCTP_B_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string requirements: - dependency_VLC1_VLC_SCTP_B: capability: tosca.capabilities.Node @@ -3916,6 +4654,94 @@ node_types: status: SUPPORTED entry_schema: type: string + port_FSB1_Internal1_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_FSB_OAM_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal2_mac_address: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal2_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal1_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal1_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB_OAM_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal2_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal1_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_FSB_OAM_mac_requirements: type: list required: true @@ -3928,6 +4754,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_FSB1_Internal1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -3936,28 +4768,24 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_FSB1_Internal1_network: + port_FSB_OAM_order: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED - port_FSB1_Internal2_mac_address: + type: integer + port_FSB1_Internal1_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - port_FSB_OAM_ip_requirements: + port_FSB1_Internal2_network_role_tag: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string port_FSB1_Internal2_mac_requirements: type: list required: true @@ -3970,36 +4798,48 @@ node_types: status: SUPPORTED entry_schema: type: json + port_FSB1_Internal2_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer port_FSB_OAM_fixed_ips: type: list required: true status: SUPPORTED entry_schema: type: json - compute_FSB1_name: + port_FSB1_Internal1_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - port_FSB1_Internal1_mac_requirements: + type: json + port_FSB_OAM_exCP_naming: type: list required: true status: SUPPORTED entry_schema: type: json - port_FSB1_Internal1_ip_requirements: + compute_FSB1_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal2_exCP_naming: type: list required: true status: SUPPORTED entry_schema: type: json - port_FSB_OAM_network: + port_FSB1_Internal2_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json requirements: - dependency_FSB1_FSB1_Internal2: capability: tosca.capabilities.Node @@ -4495,21 +5335,13 @@ node_types: org.openecomp.resource.abstract.nodes.GPB1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_GPB1_Internal2_network: + port_GPB1_Internal1_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - port_GPB1_Internal1_network: + port_GPB1_Internal2_network_role: type: list required: true status: SUPPORTED @@ -4525,29 +5357,29 @@ node_types: type: string required: true status: SUPPORTED - port_GPB1_Internal2_mac_requirements: - type: list - required: true - status: SUPPORTED - entry_schema: - type: json - port_GPB1_Internal1_mac_address: + port_GPB1_Internal2_mac_address: type: list required: true status: SUPPORTED entry_schema: type: string - port_GPB1_Internal2_mac_address: + port_GPB1_Internal1_order: type: list required: true status: SUPPORTED entry_schema: - type: string + type: integer vm_image_name: type: string required: true status: SUPPORTED - port_GPB1_Internal1_ip_requirements: + port_GPB1_Internal1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_GPB1_Internal2_exCP_naming: type: list required: true status: SUPPORTED @@ -4565,12 +5397,92 @@ node_types: status: SUPPORTED entry_schema: type: string + port_GPB1_Internal1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_GPB1_Internal2_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_GPB1_Internal2_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_GPB1_Internal1_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB1_Internal2_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_GPB1_Internal1_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB1_Internal2_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_GPB1_Internal1_mac_address: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB1_Internal1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB1_Internal2_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB1_Internal2_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_GPB1_Internal1_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_GPB1_Internal2_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer requirements: - dependency_GPB1: capability: tosca.capabilities.Node diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/MainServiceTemplate.yaml index 8e78b6635d..8ae59dca18 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/MainServiceTemplate.yaml @@ -627,8 +627,6 @@ topology_template: directives: - substitutable properties: - port_VLC_SCTP_A_network: - - epc-sctp-a-net port_VLC_OAM_network_role_tag: - oam port_VLC_GTP_ip_requirements: @@ -657,17 +655,8 @@ topology_template: port_VLC_SCTP_A_fixed_ips: - - ip_address: get_input: vlc2-sctp-a-ip - port_VLC_OAM_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: true - floating_ip_count_required: - is_required: false port_VLC2_Internal2_mac_address: - get_input: vlc2-Internal2-mac - port_VLC_OAM_fixed_ips: - - - ip_address: - get_input: vlc2-oam-ip vm_image_name: get_input: pxe-image port_VLC2_Internal1_mac_address: @@ -678,12 +667,6 @@ topology_template: port_VLC2_Internal1_mac_requirements: - mac_count_required: is_required: true - port_VLC_SCTP_A_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: true - floating_ip_count_required: - is_required: false port_VLC_SCTP_B_network: - epc-sctp-b-net port_VLC_GTP_network: @@ -694,6 +677,30 @@ topology_template: is_required: false floating_ip_count_required: is_required: false + port_VLC_GTP_fixed_ips: + - - ip_address: + get_input: vlc2-gtp-ip + port_VLC_OAM_network: + - get_input: oam_net_id + port_VLC2_Internal2_network: + - Internal2-net + port_VLC_SCTP_A_network: + - epc-sctp-a-net + port_VLC_OAM_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false + port_VLC_OAM_fixed_ips: + - - ip_address: + get_input: vlc2-oam-ip + port_VLC_SCTP_A_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: true + floating_ip_count_required: + is_required: false compute_VLC2_name: - get_input: vlc2-name port_VLC_SCTP_B_fixed_ips: @@ -706,19 +713,12 @@ topology_template: - Internal1-net compute_VLC2_availability_zone: - get_input: vlc_zone - port_VLC_GTP_fixed_ips: - - - ip_address: - get_input: vlc2-gtp-ip port_VLC_OAM_mac_requirements: - mac_count_required: is_required: false - port_VLC_OAM_network: - - get_input: oam_net_id port_VLC_SCTP_B_mac_requirements: - mac_count_required: is_required: false - port_VLC2_Internal2_network: - - Internal2-net service_template_filter: substitute_service_template: Nested_VLC2ServiceTemplate.yaml count: 1 @@ -755,10 +755,6 @@ topology_template: properties: port_VLC1_Internal2_mac_address: - get_input: vlc1-Internal2-mac - port_VLC1_Internal1_network: - - Internal1-net - port_VLC_SCTP_A_network: - - epc-sctp-a-net port_VLC_OAM_network_role_tag: - oam port_VLC1_Internal1_mac_address: @@ -785,6 +781,32 @@ topology_template: port_VLC_SCTP_A_fixed_ips: - - ip_address: get_input: vlc1-sctp-a-ip + vm_image_name: + get_input: pxe-image + port_VLC_SCTP_B_network: + - epc-sctp-b-net + port_VLC_GTP_network: + - epc-gtp-net + port_VLC1_Internal1_mac_requirements: + - mac_count_required: + is_required: true + port_VLC_GTP_fixed_ips: + - - ip_address: + get_input: vlc1-gtp-ip + port_VLC_OAM_network: + - get_input: oam_net_id + compute_VLC1_name: + - get_input: vlc1-name + port_VLC1_Internal2_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + port_VLC1_Internal1_network: + - Internal1-net + port_VLC_SCTP_A_network: + - epc-sctp-a-net port_VLC_OAM_ip_requirements: - - ip_version: 4 ip_count_required: @@ -800,23 +822,14 @@ topology_template: port_VLC_OAM_fixed_ips: - - ip_address: get_input: vlc1-oam-ip - vm_image_name: - get_input: pxe-image port_VLC_SCTP_A_ip_requirements: - - ip_version: 4 ip_count_required: is_required: true floating_ip_count_required: is_required: false - port_VLC_SCTP_B_network: - - epc-sctp-b-net - port_VLC_GTP_network: - - epc-gtp-net compute_VLC1_availability_zone: - get_input: vlc_zone - port_VLC1_Internal1_mac_requirements: - - mac_count_required: - is_required: true port_VLC1_Internal2_mac_requirements: - mac_count_required: is_required: true @@ -826,25 +839,12 @@ topology_template: port_VLC_GTP_mac_requirements: - mac_count_required: is_required: false - port_VLC_GTP_fixed_ips: - - - ip_address: - get_input: vlc1-gtp-ip port_VLC_OAM_mac_requirements: - mac_count_required: is_required: false - port_VLC_OAM_network: - - get_input: oam_net_id - compute_VLC1_name: - - get_input: vlc1-name port_VLC_SCTP_B_mac_requirements: - mac_count_required: is_required: false - port_VLC1_Internal2_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false service_template_filter: substitute_service_template: Nested_VLC1ServiceTemplate.yaml count: 1 @@ -900,35 +900,35 @@ topology_template: directives: - substitutable properties: - port_GPB1_Internal2_network: - - Internal2-net - port_GPB1_Internal1_network: - - Internal1-net compute_GPB1_name: - get_input: gpb1-name vm_flavor_name: get_input: gpb-flavor - port_GPB1_Internal2_mac_requirements: - - mac_count_required: - is_required: true - port_GPB1_Internal1_mac_address: - - get_input: gpb1-Internal1-mac port_GPB1_Internal2_mac_address: - get_input: gpb1-Internal2-mac vm_image_name: get_input: pxe-image - port_GPB1_Internal1_ip_requirements: + port_GPB1_Internal1_mac_requirements: + - mac_count_required: + is_required: true + compute_GPB1_availability_zone: + - get_input: gpb_zone + port_GPB1_Internal2_ip_requirements: - - ip_version: 4 ip_count_required: is_required: false floating_ip_count_required: is_required: false - port_GPB1_Internal1_mac_requirements: + port_GPB1_Internal2_network: + - Internal2-net + port_GPB1_Internal1_network: + - Internal1-net + port_GPB1_Internal2_mac_requirements: - mac_count_required: is_required: true - compute_GPB1_availability_zone: - - get_input: gpb_zone - port_GPB1_Internal2_ip_requirements: + port_GPB1_Internal1_mac_address: + - get_input: gpb1-Internal1-mac + port_GPB1_Internal1_ip_requirements: - - ip_version: 4 ip_count_required: is_required: false @@ -956,6 +956,20 @@ topology_template: directives: - substitutable properties: + port_GPB2_Internal1_network: + - Internal1-net + vm_flavor_name: + get_input: gpb-flavor + port_GPB2_Internal2_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + vm_image_name: + get_input: pxe-image + compute_GPB2_name: + - get_input: gpb2-name port_GPB2_Internal2_mac_address: - get_input: gpb2-Internal2-mac port_GPB2_Internal2_mac_requirements: @@ -967,25 +981,11 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - port_GPB2_Internal1_network: - - Internal1-net compute_GPB2_availability_zone: - get_input: gpb_zone - vm_flavor_name: - get_input: gpb-flavor port_GPB2_Internal1_mac_requirements: - mac_count_required: is_required: true - port_GPB2_Internal2_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - vm_image_name: - get_input: pxe-image - compute_GPB2_name: - - get_input: gpb2-name port_GPB2_Internal1_mac_address: - get_input: gpb2-Internal1-mac port_GPB2_Internal2_network: @@ -1051,6 +1051,21 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_input: ncb-flavor + compute_NCB1_name: + - get_input: ncb1-name + port_NCB1_Internal2_mac_requirements: + - mac_count_required: + is_required: true + vm_image_name: + get_input: pxe-image + port_NCB1_Internal2_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false port_NCB1_Internal2_mac_address: - get_input: ncb1-Internal2-mac port_NCB1_Internal1_mac_address: @@ -1061,28 +1076,13 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - vm_flavor_name: - get_input: ncb-flavor - compute_NCB1_name: - - get_input: ncb1-name port_NCB1_Internal1_mac_requirements: - - mac_count_required: - is_required: true - port_NCB1_Internal2_mac_requirements: - mac_count_required: is_required: true port_NCB1_Internal1_network: - Internal1-net compute_NCB1_availability_zone: - get_input: ncb_zone - vm_image_name: - get_input: pxe-image - port_NCB1_Internal2_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false port_NCB1_Internal2_network: - Internal2-net service_template_filter: @@ -1107,32 +1107,32 @@ topology_template: directives: - substitutable properties: - port_NCB2_Internal1_network: - - Internal1-net compute_NCB2_availability_zone: - get_input: ncb_zone - port_NCB2_Internal2_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false vm_flavor_name: get_input: ncb-flavor port_NCB2_Internal2_mac_requirements: - mac_count_required: is_required: true - port_NCB2_Internal2_network: - - Internal2-net port_NCB2_Internal1_mac_requirements: - mac_count_required: is_required: true + vm_image_name: + get_input: pxe-image + port_NCB2_Internal1_network: + - Internal1-net + port_NCB2_Internal2_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + port_NCB2_Internal2_network: + - Internal2-net port_NCB2_Internal1_mac_address: - get_input: ncb2-Internal1-mac port_NCB2_Internal2_mac_address: - get_input: ncb2-Internal2-mac - vm_image_name: - get_input: pxe-image compute_NCB2_name: - get_input: ncb2-name port_NCB2_Internal1_ip_requirements: @@ -1187,11 +1187,6 @@ topology_template: - oam port_FSB1_Internal2_network: - Internal2-net - port_FSB_OAM_mac_requirements: - - mac_count_required: - is_required: false - compute_FSB1_availability_zone: - - get_input: fsb_zone port_FSB1_Internal1_network: - Internal1-net vm_flavor_name: @@ -1204,31 +1199,36 @@ topology_template: is_required: true floating_ip_count_required: is_required: false - port_FSB1_Internal2_mac_requirements: + port_FSB1_Internal1_mac_requirements: - mac_count_required: is_required: true - port_FSB1_Internal2_ip_requirements: + port_FSB1_Internal1_ip_requirements: - - ip_version: 4 ip_count_required: is_required: false floating_ip_count_required: is_required: false - port_FSB_OAM_fixed_ips: - - - ip_address: - get_input: fsb1-oam-ip - compute_FSB1_name: - - get_input: fsb1-name - port_FSB1_Internal1_mac_requirements: + port_FSB_OAM_network: + - get_input: oam_net_id + port_FSB_OAM_mac_requirements: + - mac_count_required: + is_required: false + compute_FSB1_availability_zone: + - get_input: fsb_zone + port_FSB1_Internal2_mac_requirements: - mac_count_required: is_required: true - port_FSB1_Internal1_ip_requirements: + port_FSB1_Internal2_ip_requirements: - - ip_version: 4 ip_count_required: is_required: false floating_ip_count_required: is_required: false - port_FSB_OAM_network: - - get_input: oam_net_id + port_FSB_OAM_fixed_ips: + - - ip_address: + get_input: fsb1-oam-ip + compute_FSB1_name: + - get_input: fsb1-name service_template_filter: substitute_service_template: Nested_FSB1ServiceTemplate.yaml count: 1 @@ -1253,20 +1253,6 @@ topology_template: properties: port_FSB_OAM_network_role_tag: - oam - port_FSB2_Internal2_mac_requirements: - - mac_count_required: - is_required: true - port_FSB_OAM_mac_requirements: - - mac_count_required: - is_required: false - port_FSB2_Internal2_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - port_FSB2_Internal2_network: - - Internal2-net vm_flavor_name: get_input: fsb2-flavor compute_FSB2_availability_zone: @@ -1287,18 +1273,32 @@ topology_template: - get_input: fsb2-name port_FSB2_Internal1_mac_address: - get_input: fsb2-Internal1-mac - port_FSB_OAM_fixed_ips: - - - ip_address: - get_input: fsb2-oam-ip - port_FSB2_Internal1_mac_requirements: - - mac_count_required: - is_required: true port_FSB_OAM_network: - get_input: oam_net_id port_FSB2_Internal1_network: - Internal1-net port_FSB2_Internal2_mac_address: - get_input: fsb2-Internal2-mac + port_FSB2_Internal2_mac_requirements: + - mac_count_required: + is_required: true + port_FSB_OAM_mac_requirements: + - mac_count_required: + is_required: false + port_FSB2_Internal2_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + port_FSB2_Internal2_network: + - Internal2-net + port_FSB_OAM_fixed_ips: + - - ip_address: + get_input: fsb2-oam-ip + port_FSB2_Internal1_mac_requirements: + - mac_count_required: + is_required: true service_template_filter: substitute_service_template: Nested_FSB2ServiceTemplate.yaml count: 1 diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_FSB1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_FSB1ServiceTemplate.yaml index 4331ecaa03..42ba1a647f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_FSB1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_FSB1ServiceTemplate.yaml @@ -26,6 +26,79 @@ topology_template: required: true entry_schema: type: string + port_FSB1_Internal1_network: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_FSB_OAM_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal2_mac_address: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal2_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal1_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal1_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal1_order: + type: list + required: true + entry_schema: + type: integer + port_FSB_OAM_network: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal2_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal1_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_FSB_OAM_mac_requirements: type: list required: true @@ -36,6 +109,11 @@ topology_template: required: true entry_schema: type: string + port_FSB1_Internal1_vlan_requirements: + type: list + required: true + entry_schema: + type: json index_value: type: integer description: Index value of this substitution service template runtime instance @@ -43,24 +121,21 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_FSB1_Internal1_network: + port_FSB_OAM_order: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true - port_FSB1_Internal2_mac_address: + type: integer + port_FSB1_Internal1_network_role: type: list required: true entry_schema: type: string - port_FSB_OAM_ip_requirements: + port_FSB1_Internal2_network_role_tag: type: list required: true entry_schema: - type: json + type: string port_FSB1_Internal2_mac_requirements: type: list required: true @@ -71,43 +146,77 @@ topology_template: required: true entry_schema: type: json + port_FSB1_Internal2_order: + type: list + required: true + entry_schema: + type: integer port_FSB_OAM_fixed_ips: type: list required: true entry_schema: type: json - compute_FSB1_name: + port_FSB1_Internal1_exCP_naming: type: list required: true entry_schema: - type: string - port_FSB1_Internal1_mac_requirements: + type: json + port_FSB_OAM_exCP_naming: type: list required: true entry_schema: type: json - port_FSB1_Internal1_ip_requirements: + compute_FSB1_name: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal2_exCP_naming: type: list required: true entry_schema: type: json - port_FSB_OAM_network: + port_FSB1_Internal2_vlan_requirements: type: list required: true entry_schema: - type: string + type: json node_templates: FSB1_FSB1_Internal2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB1_Internal2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB1_Internal2_vlan_requirements + - index_value ip_requirements: get_input: - port_FSB1_Internal2_ip_requirements - index_value + network_role_tag: + get_input: + - port_FSB1_Internal2_network_role_tag + - index_value mac_requirements: get_input: - port_FSB1_Internal2_mac_requirements - index_value + order: + get_input: + - port_FSB1_Internal2_order + - index_value + network_role: + get_input: + - port_FSB1_Internal2_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB1_Internal2_subnetpoolid + - index_value network: get_input: - port_FSB1_Internal2_network @@ -124,14 +233,38 @@ topology_template: FSB1_FSB1_Internal1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB1_Internal1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB1_Internal1_vlan_requirements + - index_value ip_requirements: get_input: - port_FSB1_Internal1_ip_requirements - index_value + network_role_tag: + get_input: + - port_FSB1_Internal1_network_role_tag + - index_value mac_requirements: get_input: - port_FSB1_Internal1_mac_requirements - index_value + order: + get_input: + - port_FSB1_Internal1_order + - index_value + network_role: + get_input: + - port_FSB1_Internal1_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB1_Internal1_subnetpoolid + - index_value network: get_input: - port_FSB1_Internal1_network @@ -148,6 +281,14 @@ topology_template: FSB1_FSB_OAM: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB_OAM_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB_OAM_vlan_requirements + - index_value ip_requirements: get_input: - port_FSB_OAM_ip_requirements @@ -160,6 +301,18 @@ topology_template: get_input: - port_FSB_OAM_mac_requirements - index_value + order: + get_input: + - port_FSB_OAM_order + - index_value + network_role: + get_input: + - port_FSB_OAM_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB_OAM_subnetpoolid + - index_value fixed_ips: get_input: - port_FSB_OAM_fixed_ips diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_FSB2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_FSB2ServiceTemplate.yaml index a4d2f79275..a71818c237 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_FSB2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_FSB2ServiceTemplate.yaml @@ -16,6 +16,94 @@ topology_template: required: true entry_schema: type: string + port_FSB2_Internal2_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_FSB_OAM_vlan_requirements: + type: list + required: true + entry_schema: + type: json + compute_FSB2_availability_zone: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal2_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal1_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal1_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal2_network_role: + type: list + required: true + entry_schema: + type: string + compute_FSB2_name: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_mac_address: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_network: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal2_mac_address: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_FSB2_Internal2_mac_requirements: type: list required: true @@ -38,35 +126,32 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_FSB2_Internal2_network: + port_FSB_OAM_order: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string - required: true - compute_FSB2_availability_zone: + type: integer + port_FSB2_Internal2_network: type: list required: true entry_schema: type: string - port_FSB_OAM_ip_requirements: + port_FSB2_Internal2_vlan_requirements: type: list required: true entry_schema: type: json - port_FSB2_Internal1_ip_requirements: + port_FSB2_Internal1_order: type: list required: true entry_schema: - type: json - compute_FSB2_name: + type: integer + port_FSB2_Internal2_subnetpoolid: type: list required: true entry_schema: type: string - port_FSB2_Internal1_mac_address: + port_FSB2_Internal1_network_role_tag: type: list required: true entry_schema: @@ -81,25 +166,33 @@ topology_template: required: true entry_schema: type: json - port_FSB_OAM_network: + port_FSB2_Internal2_order: type: list required: true entry_schema: - type: string - port_FSB2_Internal1_network: + type: integer + port_FSB2_Internal1_subnetpoolid: type: list required: true entry_schema: type: string - port_FSB2_Internal2_mac_address: + port_FSB_OAM_exCP_naming: type: list required: true entry_schema: - type: string + type: json node_templates: FSB2_FSB_OAM: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB_OAM_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB_OAM_vlan_requirements + - index_value ip_requirements: get_input: - port_FSB_OAM_ip_requirements @@ -112,6 +205,18 @@ topology_template: get_input: - port_FSB_OAM_mac_requirements - index_value + order: + get_input: + - port_FSB_OAM_order + - index_value + network_role: + get_input: + - port_FSB_OAM_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB_OAM_subnetpoolid + - index_value fixed_ips: get_input: - port_FSB_OAM_fixed_ips @@ -141,14 +246,38 @@ topology_template: FSB2_FSB2_Internal2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB2_Internal2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB2_Internal2_vlan_requirements + - index_value ip_requirements: get_input: - port_FSB2_Internal2_ip_requirements - index_value + network_role_tag: + get_input: + - port_FSB2_Internal2_network_role_tag + - index_value mac_requirements: get_input: - port_FSB2_Internal2_mac_requirements - index_value + order: + get_input: + - port_FSB2_Internal2_order + - index_value + network_role: + get_input: + - port_FSB2_Internal2_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB2_Internal2_subnetpoolid + - index_value network: get_input: - port_FSB2_Internal2_network @@ -165,14 +294,38 @@ topology_template: FSB2_FSB2_Internal1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB2_Internal1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB2_Internal1_vlan_requirements + - index_value ip_requirements: get_input: - port_FSB2_Internal1_ip_requirements - index_value + network_role_tag: + get_input: + - port_FSB2_Internal1_network_role_tag + - index_value mac_requirements: get_input: - port_FSB2_Internal1_mac_requirements - index_value + order: + get_input: + - port_FSB2_Internal1_order + - index_value + network_role: + get_input: + - port_FSB2_Internal1_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB2_Internal1_subnetpoolid + - index_value network: get_input: - port_FSB2_Internal1_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_GPB1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_GPB1ServiceTemplate.yaml index b8e6141f9b..04066334b2 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_GPB1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_GPB1ServiceTemplate.yaml @@ -11,19 +11,12 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_GPB1_Internal2_network: + port_GPB1_Internal1_network_role: type: list required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - port_GPB1_Internal1_network: + port_GPB1_Internal2_network_role: type: list required: true entry_schema: @@ -36,25 +29,25 @@ topology_template: vm_flavor_name: type: string required: true - port_GPB1_Internal2_mac_requirements: - type: list - required: true - entry_schema: - type: json - port_GPB1_Internal1_mac_address: + port_GPB1_Internal2_mac_address: type: list required: true entry_schema: type: string - port_GPB1_Internal2_mac_address: + port_GPB1_Internal1_order: type: list required: true entry_schema: - type: string + type: integer vm_image_name: type: string required: true - port_GPB1_Internal1_ip_requirements: + port_GPB1_Internal1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_GPB1_Internal2_exCP_naming: type: list required: true entry_schema: @@ -69,11 +62,78 @@ topology_template: required: true entry_schema: type: string + port_GPB1_Internal1_exCP_naming: + type: list + required: true + entry_schema: + type: json port_GPB1_Internal2_ip_requirements: type: list required: true entry_schema: type: json + port_GPB1_Internal2_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_GPB1_Internal1_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_GPB1_Internal2_network: + type: list + required: true + entry_schema: + type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + port_GPB1_Internal1_network: + type: list + required: true + entry_schema: + type: string + port_GPB1_Internal2_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_GPB1_Internal1_mac_address: + type: list + required: true + entry_schema: + type: string + port_GPB1_Internal1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_GPB1_Internal2_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_GPB1_Internal2_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_GPB1_Internal1_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_GPB1_Internal2_order: + type: list + required: true + entry_schema: + type: integer node_templates: GPB1: type: org.openecomp.resource.vfc.nodes.heat.GPB1 @@ -93,14 +153,38 @@ topology_template: GPB1_GPB1_Internal1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_GPB1_Internal1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_GPB1_Internal1_vlan_requirements + - index_value ip_requirements: get_input: - port_GPB1_Internal1_ip_requirements - index_value + network_role_tag: + get_input: + - port_GPB1_Internal1_network_role_tag + - index_value mac_requirements: get_input: - port_GPB1_Internal1_mac_requirements - index_value + order: + get_input: + - port_GPB1_Internal1_order + - index_value + network_role: + get_input: + - port_GPB1_Internal1_network_role + - index_value + subnetpoolid: + get_input: + - port_GPB1_Internal1_subnetpoolid + - index_value network: get_input: - port_GPB1_Internal1_network @@ -117,14 +201,38 @@ topology_template: GPB1_GPB1_Internal2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_GPB1_Internal2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_GPB1_Internal2_vlan_requirements + - index_value ip_requirements: get_input: - port_GPB1_Internal2_ip_requirements - index_value + network_role_tag: + get_input: + - port_GPB1_Internal2_network_role_tag + - index_value mac_requirements: get_input: - port_GPB1_Internal2_mac_requirements - index_value + order: + get_input: + - port_GPB1_Internal2_order + - index_value + network_role: + get_input: + - port_GPB1_Internal2_network_role + - index_value + subnetpoolid: + get_input: + - port_GPB1_Internal2_subnetpoolid + - index_value network: get_input: - port_GPB1_Internal2_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_GPB2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_GPB2ServiceTemplate.yaml index 3598778212..64a239a2a5 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_GPB2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_GPB2ServiceTemplate.yaml @@ -11,6 +11,62 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_GPB2_Internal2_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_GPB2_Internal2_order: + type: list + required: true + entry_schema: + type: integer + port_GPB2_Internal1_network: + type: list + required: true + entry_schema: + type: string + port_GPB2_Internal1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_GPB2_Internal2_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_GPB2_Internal2_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_GPB2_Internal1_network_role: + type: list + required: true + entry_schema: + type: string + compute_GPB2_name: + type: list + required: true + entry_schema: + type: string + port_GPB2_Internal1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_GPB2_Internal2_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_GPB2_Internal2_mac_address: type: list required: true @@ -26,7 +82,7 @@ topology_template: required: true entry_schema: type: json - port_GPB2_Internal1_network: + port_GPB2_Internal2_network_role: type: list required: true entry_schema: @@ -43,23 +99,27 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string + port_GPB2_Internal2_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_GPB2_Internal1_order: + type: list required: true + entry_schema: + type: integer port_GPB2_Internal1_mac_requirements: type: list required: true entry_schema: type: json - port_GPB2_Internal2_ip_requirements: + port_GPB2_Internal1_exCP_naming: type: list required: true entry_schema: type: json - vm_image_name: - type: string - required: true - compute_GPB2_name: + port_GPB2_Internal1_network_role_tag: type: list required: true entry_schema: @@ -78,14 +138,38 @@ topology_template: GPB2_GPB2_Internal2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_GPB2_Internal2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_GPB2_Internal2_vlan_requirements + - index_value ip_requirements: get_input: - port_GPB2_Internal2_ip_requirements - index_value + network_role_tag: + get_input: + - port_GPB2_Internal2_network_role_tag + - index_value mac_requirements: get_input: - port_GPB2_Internal2_mac_requirements - index_value + order: + get_input: + - port_GPB2_Internal2_order + - index_value + network_role: + get_input: + - port_GPB2_Internal2_network_role + - index_value + subnetpoolid: + get_input: + - port_GPB2_Internal2_subnetpoolid + - index_value network: get_input: - port_GPB2_Internal2_network @@ -102,14 +186,38 @@ topology_template: GPB2_GPB2_Internal1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_GPB2_Internal1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_GPB2_Internal1_vlan_requirements + - index_value ip_requirements: get_input: - port_GPB2_Internal1_ip_requirements - index_value + network_role_tag: + get_input: + - port_GPB2_Internal1_network_role_tag + - index_value mac_requirements: get_input: - port_GPB2_Internal1_mac_requirements - index_value + order: + get_input: + - port_GPB2_Internal1_order + - index_value + network_role: + get_input: + - port_GPB2_Internal1_network_role + - index_value + subnetpoolid: + get_input: + - port_GPB2_Internal1_subnetpoolid + - index_value network: get_input: - port_GPB2_Internal1_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_NCB1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_NCB1ServiceTemplate.yaml index f0a3aaf507..c41603b6bd 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_NCB1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_NCB1ServiceTemplate.yaml @@ -11,6 +11,67 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_NCB1_Internal1_network_role: + type: list + required: true + entry_schema: + type: string + port_NCB1_Internal2_network_role: + type: list + required: true + entry_schema: + type: string + port_NCB1_Internal1_network_role_tag: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + compute_NCB1_name: + type: list + required: true + entry_schema: + type: string + port_NCB1_Internal2_mac_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_NCB1_Internal2_order: + type: list + required: true + entry_schema: + type: integer + port_NCB1_Internal2_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_NCB1_Internal1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_NCB1_Internal1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_NCB1_Internal2_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_NCB1_Internal2_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_NCB1_Internal2_mac_address: type: list required: true @@ -28,25 +89,27 @@ topology_template: required: true entry_schema: type: string - port_NCB1_Internal1_ip_requirements: + port_NCB1_Internal1_order: type: list required: true entry_schema: - type: json - vm_flavor_name: - type: string + type: integer + port_NCB1_Internal2_exCP_naming: + type: list required: true - compute_NCB1_name: + entry_schema: + type: json + port_NCB1_Internal1_ip_requirements: type: list required: true entry_schema: - type: string - port_NCB1_Internal1_mac_requirements: + type: json + port_NCB1_Internal1_vlan_requirements: type: list required: true entry_schema: type: json - port_NCB1_Internal2_mac_requirements: + port_NCB1_Internal1_mac_requirements: type: list required: true entry_schema: @@ -61,14 +124,11 @@ topology_template: required: true entry_schema: type: string - vm_image_name: - type: string - required: true - port_NCB1_Internal2_ip_requirements: + port_NCB1_Internal2_network_role_tag: type: list required: true entry_schema: - type: json + type: string port_NCB1_Internal2_network: type: list required: true @@ -93,14 +153,38 @@ topology_template: NCB1_NCB1_Internal1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_NCB1_Internal1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_NCB1_Internal1_vlan_requirements + - index_value ip_requirements: get_input: - port_NCB1_Internal1_ip_requirements - index_value + network_role_tag: + get_input: + - port_NCB1_Internal1_network_role_tag + - index_value mac_requirements: get_input: - port_NCB1_Internal1_mac_requirements - index_value + order: + get_input: + - port_NCB1_Internal1_order + - index_value + network_role: + get_input: + - port_NCB1_Internal1_network_role + - index_value + subnetpoolid: + get_input: + - port_NCB1_Internal1_subnetpoolid + - index_value network: get_input: - port_NCB1_Internal1_network @@ -117,14 +201,38 @@ topology_template: NCB1_NCB1_Internal2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_NCB1_Internal2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_NCB1_Internal2_vlan_requirements + - index_value ip_requirements: get_input: - port_NCB1_Internal2_ip_requirements - index_value + network_role_tag: + get_input: + - port_NCB1_Internal2_network_role_tag + - index_value mac_requirements: get_input: - port_NCB1_Internal2_mac_requirements - index_value + order: + get_input: + - port_NCB1_Internal2_order + - index_value + network_role: + get_input: + - port_NCB1_Internal2_network_role + - index_value + subnetpoolid: + get_input: + - port_NCB1_Internal2_subnetpoolid + - index_value network: get_input: - port_NCB1_Internal2_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_NCB2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_NCB2ServiceTemplate.yaml index 7cfca623fa..3ff3a61c8e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_NCB2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_NCB2ServiceTemplate.yaml @@ -11,6 +11,52 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + compute_NCB2_availability_zone: + type: list + required: true + entry_schema: + type: string + vm_flavor_name: + type: string + required: true + port_NCB2_Internal2_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_NCB2_Internal1_mac_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_NCB2_Internal1_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_NCB2_Internal2_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_NCB2_Internal1_order: + type: list + required: true + entry_schema: + type: integer + port_NCB2_Internal1_network_role: + type: list + required: true + entry_schema: + type: string + port_NCB2_Internal2_network_role: + type: list + required: true + entry_schema: + type: string index_value: type: integer description: Index value of this substitution service template runtime instance @@ -23,30 +69,22 @@ topology_template: required: true entry_schema: type: string - compute_NCB2_availability_zone: - type: list - required: true - entry_schema: - type: string port_NCB2_Internal2_ip_requirements: type: list required: true entry_schema: type: json - vm_flavor_name: - type: string - required: true - port_NCB2_Internal2_mac_requirements: + port_NCB2_Internal2_network_role_tag: type: list required: true entry_schema: - type: json + type: string port_NCB2_Internal2_network: type: list required: true entry_schema: type: string - port_NCB2_Internal1_mac_requirements: + port_NCB2_Internal2_vlan_requirements: type: list required: true entry_schema: @@ -61,14 +99,36 @@ topology_template: required: true entry_schema: type: string - vm_image_name: - type: string + port_NCB2_Internal1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_NCB2_Internal1_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_NCB2_Internal2_order: + type: list required: true + entry_schema: + type: integer compute_NCB2_name: type: list required: true entry_schema: type: string + port_NCB2_Internal1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_NCB2_Internal2_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_NCB2_Internal1_ip_requirements: type: list required: true @@ -93,14 +153,38 @@ topology_template: NCB2_NCB2_Internal1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_NCB2_Internal1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_NCB2_Internal1_vlan_requirements + - index_value ip_requirements: get_input: - port_NCB2_Internal1_ip_requirements - index_value + network_role_tag: + get_input: + - port_NCB2_Internal1_network_role_tag + - index_value mac_requirements: get_input: - port_NCB2_Internal1_mac_requirements - index_value + order: + get_input: + - port_NCB2_Internal1_order + - index_value + network_role: + get_input: + - port_NCB2_Internal1_network_role + - index_value + subnetpoolid: + get_input: + - port_NCB2_Internal1_subnetpoolid + - index_value network: get_input: - port_NCB2_Internal1_network @@ -117,14 +201,38 @@ topology_template: NCB2_NCB2_Internal2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_NCB2_Internal2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_NCB2_Internal2_vlan_requirements + - index_value ip_requirements: get_input: - port_NCB2_Internal2_ip_requirements - index_value + network_role_tag: + get_input: + - port_NCB2_Internal2_network_role_tag + - index_value mac_requirements: get_input: - port_NCB2_Internal2_mac_requirements - index_value + order: + get_input: + - port_NCB2_Internal2_order + - index_value + network_role: + get_input: + - port_NCB2_Internal2_network_role + - index_value + subnetpoolid: + get_input: + - port_NCB2_Internal2_subnetpoolid + - index_value network: get_input: - port_NCB2_Internal2_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_VLC1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_VLC1ServiceTemplate.yaml index 3fbc173efe..d1f52d6035 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_VLC1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_VLC1ServiceTemplate.yaml @@ -16,16 +16,11 @@ topology_template: required: true entry_schema: type: string - port_VLC1_Internal1_network: - type: list - required: true - entry_schema: - type: string - port_VLC_SCTP_A_network: + port_VLC_GTP_exCP_naming: type: list required: true entry_schema: - type: string + type: json port_VLC_OAM_network_role_tag: type: list required: true @@ -41,6 +36,16 @@ topology_template: required: true entry_schema: type: json + port_VLC1_Internal2_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_VLC1_Internal2_network_role: + type: list + required: true + entry_schema: + type: string port_VLC_SCTP_A_mac_requirements: type: list required: true @@ -64,6 +69,134 @@ topology_template: required: true entry_schema: type: json + port_VLC1_Internal2_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_VLC_GTP_network_role_tag: + type: list + required: true + entry_schema: + type: string + vm_image_name: + type: string + required: true + port_VLC1_Internal1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_B_network: + type: list + required: true + entry_schema: + type: string + port_VLC1_Internal1_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_VLC_GTP_network: + type: list + required: true + entry_schema: + type: string + port_VLC_GTP_order: + type: list + required: true + entry_schema: + type: integer + port_VLC_OAM_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_VLC1_Internal1_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC1_Internal1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC1_Internal1_order: + type: list + required: true + entry_schema: + type: integer + port_VLC_SCTP_A_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_VLC_GTP_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC_GTP_fixed_ips: + type: list + required: true + entry_schema: + type: json + port_VLC_OAM_network: + type: list + required: true + entry_schema: + type: string + compute_VLC1_name: + type: list + required: true + entry_schema: + type: string + port_VLC1_Internal2_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC1_Internal1_network: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_A_network: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_A_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC1_Internal1_network_role: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_A_order: + type: list + required: true + entry_schema: + type: integer + port_VLC_SCTP_B_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_VLC_SCTP_A_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_VLC_OAM_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_VLC_OAM_ip_requirements: type: list required: true @@ -79,29 +212,56 @@ topology_template: required: true entry_schema: type: json - vm_image_name: - type: string + port_VLC1_Internal2_vlan_requirements: + type: list required: true + entry_schema: + type: json + port_VLC_OAM_network_role: + type: list + required: true + entry_schema: + type: string + port_VLC1_Internal2_order: + type: list + required: true + entry_schema: + type: integer + port_VLC1_Internal2_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_VLC_SCTP_A_ip_requirements: type: list required: true entry_schema: type: json - port_VLC_SCTP_B_network: + port_VLC_SCTP_A_subnetpoolid: type: list required: true entry_schema: type: string - port_VLC_GTP_network: + compute_VLC1_availability_zone: type: list required: true entry_schema: type: string - compute_VLC1_availability_zone: + port_VLC_OAM_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_B_network_role_tag: type: list required: true entry_schema: type: string + port_VLC_OAM_order: + type: list + required: true + entry_schema: + type: integer index_value: type: integer description: Index value of this substitution service template runtime instance @@ -109,68 +269,107 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_VLC1_Internal1_mac_requirements: + port_VLC1_Internal2_mac_requirements: type: list required: true entry_schema: type: json - port_VLC1_Internal2_mac_requirements: + port_VLC_SCTP_B_subnetpoolid: type: list required: true entry_schema: - type: json + type: string port_VLC_SCTP_B_fixed_ips: type: list required: true entry_schema: type: json + port_VLC_GTP_network_role: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_A_network_role: + type: list + required: true + entry_schema: + type: string port_VLC_GTP_mac_requirements: type: list required: true entry_schema: type: json - port_VLC_GTP_fixed_ips: + port_VLC_OAM_mac_requirements: type: list required: true entry_schema: type: json - port_VLC_OAM_mac_requirements: + port_VLC1_Internal1_exCP_naming: type: list required: true entry_schema: type: json - port_VLC_OAM_network: + port_VLC_SCTP_B_mac_requirements: type: list required: true entry_schema: - type: string - compute_VLC1_name: + type: json + port_VLC_SCTP_B_order: + type: list + required: true + entry_schema: + type: integer + port_VLC_GTP_subnetpoolid: type: list required: true entry_schema: type: string - port_VLC_SCTP_B_mac_requirements: + port_VLC_SCTP_B_vlan_requirements: type: list required: true entry_schema: type: json - port_VLC1_Internal2_ip_requirements: + port_VLC_SCTP_B_network_role: type: list required: true entry_schema: - type: json + type: string node_templates: VLC1_VLC_SCTP_B: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC_SCTP_B_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC_SCTP_B_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC_SCTP_B_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC_SCTP_B_network_role_tag + - index_value mac_requirements: get_input: - port_VLC_SCTP_B_mac_requirements - index_value + order: + get_input: + - port_VLC_SCTP_B_order + - index_value + network_role: + get_input: + - port_VLC_SCTP_B_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC_SCTP_B_subnetpoolid + - index_value fixed_ips: get_input: - port_VLC_SCTP_B_fixed_ips @@ -187,14 +386,38 @@ topology_template: VLC1_VLC1_Internal2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC1_Internal2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC1_Internal2_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC1_Internal2_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC1_Internal2_network_role_tag + - index_value mac_requirements: get_input: - port_VLC1_Internal2_mac_requirements - index_value + order: + get_input: + - port_VLC1_Internal2_order + - index_value + network_role: + get_input: + - port_VLC1_Internal2_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC1_Internal2_subnetpoolid + - index_value network: get_input: - port_VLC1_Internal2_network @@ -211,14 +434,38 @@ topology_template: VLC1_VLC1_Internal1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC1_Internal1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC1_Internal1_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC1_Internal1_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC1_Internal1_network_role_tag + - index_value mac_requirements: get_input: - port_VLC1_Internal1_mac_requirements - index_value + order: + get_input: + - port_VLC1_Internal1_order + - index_value + network_role: + get_input: + - port_VLC1_Internal1_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC1_Internal1_subnetpoolid + - index_value network: get_input: - port_VLC1_Internal1_network @@ -235,6 +482,14 @@ topology_template: VLC1_VLC_OAM: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC_OAM_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC_OAM_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC_OAM_ip_requirements @@ -247,6 +502,18 @@ topology_template: get_input: - port_VLC_OAM_mac_requirements - index_value + order: + get_input: + - port_VLC_OAM_order + - index_value + network_role: + get_input: + - port_VLC_OAM_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC_OAM_subnetpoolid + - index_value fixed_ips: get_input: - port_VLC_OAM_fixed_ips @@ -263,14 +530,38 @@ topology_template: VLC1_VLC_SCTP_A: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC_SCTP_A_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC_SCTP_A_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC_SCTP_A_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC_SCTP_A_network_role_tag + - index_value mac_requirements: get_input: - port_VLC_SCTP_A_mac_requirements - index_value + order: + get_input: + - port_VLC_SCTP_A_order + - index_value + network_role: + get_input: + - port_VLC_SCTP_A_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC_SCTP_A_subnetpoolid + - index_value fixed_ips: get_input: - port_VLC_SCTP_A_fixed_ips @@ -302,14 +593,38 @@ topology_template: VLC1_VLC_GTP: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC_GTP_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC_GTP_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC_GTP_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC_GTP_network_role_tag + - index_value mac_requirements: get_input: - port_VLC_GTP_mac_requirements - index_value + order: + get_input: + - port_VLC_GTP_order + - index_value + network_role: + get_input: + - port_VLC_GTP_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC_GTP_subnetpoolid + - index_value fixed_ips: get_input: - port_VLC_GTP_fixed_ips diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_VLC2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_VLC2ServiceTemplate.yaml index cb60cfcff3..75b8246a49 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_VLC2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/generalVf/out/Nested_VLC2ServiceTemplate.yaml @@ -11,11 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_VLC_SCTP_A_network: + port_VLC_GTP_exCP_naming: type: list required: true entry_schema: - type: string + type: json port_VLC_OAM_network_role_tag: type: list required: true @@ -49,21 +49,21 @@ topology_template: required: true entry_schema: type: json - port_VLC_OAM_ip_requirements: + port_VLC2_Internal1_network_role_tag: type: list required: true entry_schema: - type: json + type: string port_VLC2_Internal2_mac_address: type: list required: true entry_schema: type: string - port_VLC_OAM_fixed_ips: + port_VLC_GTP_network_role_tag: type: list required: true entry_schema: - type: json + type: string vm_image_name: type: string required: true @@ -82,31 +82,151 @@ topology_template: required: true entry_schema: type: json - port_VLC_SCTP_A_ip_requirements: + port_VLC_SCTP_B_network: + type: list + required: true + entry_schema: + type: string + port_VLC_GTP_network: + type: list + required: true + entry_schema: + type: string + port_VLC2_Internal1_ip_requirements: type: list required: true entry_schema: type: json - port_VLC_SCTP_B_network: + port_VLC_GTP_order: + type: list + required: true + entry_schema: + type: integer + port_VLC_OAM_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_VLC_SCTP_A_network_role_tag: type: list required: true entry_schema: type: string - port_VLC_GTP_network: + port_VLC_GTP_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC_GTP_fixed_ips: + type: list + required: true + entry_schema: + type: json + port_VLC_OAM_network: type: list required: true entry_schema: type: string - port_VLC2_Internal1_ip_requirements: + port_VLC2_Internal2_network: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_A_network: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_A_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC_SCTP_A_order: + type: list + required: true + entry_schema: + type: integer + port_VLC_SCTP_B_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_VLC_SCTP_A_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_VLC_OAM_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC_OAM_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC_OAM_fixed_ips: type: list required: true entry_schema: type: json + port_VLC2_Internal1_order: + type: list + required: true + entry_schema: + type: integer + port_VLC_OAM_network_role: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_A_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC2_Internal2_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC_SCTP_A_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_VLC_OAM_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_B_network_role_tag: + type: list + required: true + entry_schema: + type: string compute_VLC2_name: type: list required: true entry_schema: type: string + port_VLC_OAM_order: + type: list + required: true + entry_schema: + type: integer + port_VLC2_Internal1_network_role: + type: list + required: true + entry_schema: + type: string + port_VLC2_Internal2_network_role: + type: list + required: true + entry_schema: + type: string index_value: type: integer description: Index value of this substitution service template runtime instance @@ -114,11 +234,36 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_VLC_SCTP_B_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_VLC2_Internal2_network_role_tag: + type: list + required: true + entry_schema: + type: string port_VLC_SCTP_B_fixed_ips: type: list required: true entry_schema: type: json + port_VLC_GTP_network_role: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_A_network_role: + type: list + required: true + entry_schema: + type: string + port_VLC2_Internal2_order: + type: list + required: true + entry_schema: + type: integer port_VLC_GTP_mac_requirements: type: list required: true @@ -134,7 +279,7 @@ topology_template: required: true entry_schema: type: string - port_VLC_GTP_fixed_ips: + port_VLC2_Internal1_exCP_naming: type: list required: true entry_schema: @@ -144,7 +289,12 @@ topology_template: required: true entry_schema: type: json - port_VLC_OAM_network: + port_VLC2_Internal1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC2_Internal2_subnetpoolid: type: list required: true entry_schema: @@ -154,7 +304,32 @@ topology_template: required: true entry_schema: type: json - port_VLC2_Internal2_network: + port_VLC2_Internal2_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_VLC_SCTP_B_order: + type: list + required: true + entry_schema: + type: integer + port_VLC_GTP_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_VLC2_Internal1_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_VLC_SCTP_B_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_VLC_SCTP_B_network_role: type: list required: true entry_schema: @@ -163,14 +338,38 @@ topology_template: VLC2_VLC2_Internal2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC2_Internal2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC2_Internal2_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC2_Internal2_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC2_Internal2_network_role_tag + - index_value mac_requirements: get_input: - port_VLC2_Internal2_mac_requirements - index_value + order: + get_input: + - port_VLC2_Internal2_order + - index_value + network_role: + get_input: + - port_VLC2_Internal2_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC2_Internal2_subnetpoolid + - index_value network: get_input: - port_VLC2_Internal2_network @@ -187,6 +386,14 @@ topology_template: VLC2_VLC_OAM: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC_OAM_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC_OAM_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC_OAM_ip_requirements @@ -199,6 +406,18 @@ topology_template: get_input: - port_VLC_OAM_mac_requirements - index_value + order: + get_input: + - port_VLC_OAM_order + - index_value + network_role: + get_input: + - port_VLC_OAM_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC_OAM_subnetpoolid + - index_value fixed_ips: get_input: - port_VLC_OAM_fixed_ips @@ -215,14 +434,38 @@ topology_template: VLC2_VLC2_Internal1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC2_Internal1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC2_Internal1_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC2_Internal1_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC2_Internal1_network_role_tag + - index_value mac_requirements: get_input: - port_VLC2_Internal1_mac_requirements - index_value + order: + get_input: + - port_VLC2_Internal1_order + - index_value + network_role: + get_input: + - port_VLC2_Internal1_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC2_Internal1_subnetpoolid + - index_value network: get_input: - port_VLC2_Internal1_network @@ -239,14 +482,38 @@ topology_template: VLC2_VLC_SCTP_A: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC_SCTP_A_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC_SCTP_A_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC_SCTP_A_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC_SCTP_A_network_role_tag + - index_value mac_requirements: get_input: - port_VLC_SCTP_A_mac_requirements - index_value + order: + get_input: + - port_VLC_SCTP_A_order + - index_value + network_role: + get_input: + - port_VLC_SCTP_A_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC_SCTP_A_subnetpoolid + - index_value fixed_ips: get_input: - port_VLC_SCTP_A_fixed_ips @@ -263,14 +530,38 @@ topology_template: VLC2_VLC_SCTP_B: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC_SCTP_B_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC_SCTP_B_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC_SCTP_B_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC_SCTP_B_network_role_tag + - index_value mac_requirements: get_input: - port_VLC_SCTP_B_mac_requirements - index_value + order: + get_input: + - port_VLC_SCTP_B_order + - index_value + network_role: + get_input: + - port_VLC_SCTP_B_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC_SCTP_B_subnetpoolid + - index_value fixed_ips: get_input: - port_VLC_SCTP_B_fixed_ips @@ -287,14 +578,38 @@ topology_template: VLC2_VLC_GTP: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_VLC_GTP_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_VLC_GTP_vlan_requirements + - index_value ip_requirements: get_input: - port_VLC_GTP_ip_requirements - index_value + network_role_tag: + get_input: + - port_VLC_GTP_network_role_tag + - index_value mac_requirements: get_input: - port_VLC_GTP_mac_requirements - index_value + order: + get_input: + - port_VLC_GTP_order + - index_value + network_role: + get_input: + - port_VLC_GTP_network_role + - index_value + subnetpoolid: + get_input: + - port_VLC_GTP_subnetpoolid + - index_value fixed_ips: get_input: - port_VLC_GTP_fixed_ips diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index 07792bad3d..b9579e65a7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -34,10 +34,28 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_flavor_name: type: string required: true status: SUPPORTED + port_pd02_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -50,6 +68,12 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_image_name: type: string required: true @@ -66,6 +90,36 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true @@ -78,6 +132,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd02_port_network: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttIn/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttIn/out/Nested_pd_serverServiceTemplate.yaml index 2dc08c62ba..3dce505771 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttIn/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttIn/out/Nested_pd_serverServiceTemplate.yaml @@ -33,9 +33,24 @@ topology_template: required: true entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json vm_flavor_name: type: string required: true + port_pd02_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -46,6 +61,11 @@ topology_template: required: true entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json vm_image_name: type: string required: true @@ -59,6 +79,31 @@ topology_template: required: true entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true @@ -69,6 +114,11 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd02_port_network: type: list required: true @@ -102,6 +152,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -114,6 +172,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network @@ -126,6 +196,14 @@ topology_template: pd_server_pd02_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd02_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd02_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd02_port_ip_requirements @@ -138,6 +216,18 @@ topology_template: get_input: - port_pd02_port_mac_requirements - index_value + order: + get_input: + - port_pd02_port_order + - index_value + network_role: + get_input: + - port_pd02_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd02_port_subnetpoolid + - index_value network: get_input: - port_pd02_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttOut/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttOut/out/GlobalSubstitutionTypesServiceTemplate.yaml index 57acfc92a7..b003fc2638 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttOut/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttOut/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -34,10 +34,28 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_flavor_name: type: string required: true status: SUPPORTED + port_pd02_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -50,6 +68,12 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json vm_image_name: type: string required: true @@ -66,12 +90,54 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_pd01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd02_port_network: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttOut/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttOut/out/Nested_pd_serverServiceTemplate.yaml index e9f880a804..6d0690a78d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttOut/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeDiffPortTypesAndGetAttOut/out/Nested_pd_serverServiceTemplate.yaml @@ -33,9 +33,24 @@ topology_template: required: true entry_schema: type: json + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json vm_flavor_name: type: string required: true + port_pd02_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd02_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd02_port_network_role_tag: type: list required: true @@ -46,6 +61,11 @@ topology_template: required: true entry_schema: type: json + port_pd02_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json vm_image_name: type: string required: true @@ -59,11 +79,46 @@ topology_template: required: true entry_schema: type: string + port_pd02_port_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd02_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_network_role: + type: list + required: true + entry_schema: + type: string port_pd02_port_ip_requirements: type: list required: true entry_schema: type: json + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd02_port_network: type: list required: true @@ -97,14 +152,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network @@ -117,6 +196,14 @@ topology_template: pd_server_pd02_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd02_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd02_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd02_port_ip_requirements @@ -129,6 +216,18 @@ topology_template: get_input: - port_pd02_port_mac_requirements - index_value + order: + get_input: + - port_pd02_port_order + - index_value + network_role: + get_input: + - port_pd02_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd02_port_subnetpoolid + - index_value network: get_input: - port_pd02_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortTypesAndGetAttOut/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortTypesAndGetAttOut/out/GlobalSubstitutionTypesServiceTemplate.yaml index 49604b2074..a308e85feb 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortTypesAndGetAttOut/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortTypesAndGetAttOut/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -26,6 +26,18 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd01_port_0_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_1_ip_requirements: type: list required: true @@ -52,26 +64,80 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer vm_flavor_name: type: string required: true status: SUPPORTED + port_pd01_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_1_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_pd01_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string vm_image_name: type: string required: true status: SUPPORTED + port_pd01_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_1_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_1_network: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortTypesAndGetAttOut/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortTypesAndGetAttOut/out/Nested_pd_serverServiceTemplate.yaml index 96061d140c..e2edfa3db1 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortTypesAndGetAttOut/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortTypesAndGetAttOut/out/Nested_pd_serverServiceTemplate.yaml @@ -26,6 +26,16 @@ topology_template: required: true entry_schema: type: json + port_pd01_port_0_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_0_network_role: + type: list + required: true + entry_schema: + type: string port_pd01_port_1_ip_requirements: type: list required: true @@ -48,22 +58,67 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_1_order: + type: list + required: true + entry_schema: + type: integer vm_flavor_name: type: string required: true + port_pd01_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd01_port_1_mac_requirements: type: list required: true entry_schema: type: json + port_pd01_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string vm_image_name: type: string required: true + port_pd01_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json port_pd01_port_1_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd01_port_1_network: type: list required: true @@ -97,6 +152,14 @@ topology_template: pd_server_pd01_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_1_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_1_ip_requirements @@ -109,6 +172,18 @@ topology_template: get_input: - port_pd01_port_1_mac_requirements - index_value + order: + get_input: + - port_pd01_port_1_order + - index_value + network_role: + get_input: + - port_pd01_port_1_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_1_subnetpoolid + - index_value network: get_input: - port_pd01_port_1_network @@ -121,14 +196,38 @@ topology_template: pd_server_pd01_port_0: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_0_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_0_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_0_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_0_mac_requirements - index_value + order: + get_input: + - port_pd01_port_0_order + - index_value + network_role: + get_input: + - port_pd01_port_0_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_0_subnetpoolid + - index_value network: get_input: - port_pd01_port_0_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortsAndGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortsAndGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index f6ae733527..c9e53c828b 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortsAndGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortsAndGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -32,6 +32,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_1_ip_requirements: type: list required: true @@ -58,26 +64,80 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer vm_flavor_name: type: string required: true status: SUPPORTED + port_pd01_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_1_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_pd01_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string vm_image_name: type: string required: true status: SUPPORTED + port_pd01_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_1_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_1_network: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortsAndGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortsAndGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml index 88138e2374..9103bf7fa2 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortsAndGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/oneComputeSamePortsAndGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml @@ -31,6 +31,11 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_0_network_role: + type: list + required: true + entry_schema: + type: string port_pd01_port_1_ip_requirements: type: list required: true @@ -53,22 +58,67 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_1_order: + type: list + required: true + entry_schema: + type: integer vm_flavor_name: type: string required: true + port_pd01_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd01_port_1_mac_requirements: type: list required: true entry_schema: type: json + port_pd01_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string vm_image_name: type: string required: true + port_pd01_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json port_pd01_port_1_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd01_port_1_network: type: list required: true @@ -102,6 +152,14 @@ topology_template: pd_server_pd01_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_1_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_1_ip_requirements @@ -114,6 +172,18 @@ topology_template: get_input: - port_pd01_port_1_mac_requirements - index_value + order: + get_input: + - port_pd01_port_1_order + - index_value + network_role: + get_input: + - port_pd01_port_1_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_1_subnetpoolid + - index_value network: get_input: - port_pd01_port_1_network @@ -126,6 +196,14 @@ topology_template: pd_server_pd01_port_0: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_0_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_0_ip_requirements @@ -138,6 +216,18 @@ topology_template: get_input: - port_pd01_port_0_mac_requirements - index_value + order: + get_input: + - port_pd01_port_0_order + - index_value + network_role: + get_input: + - port_pd01_port_0_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_0_subnetpoolid + - index_value network: get_input: - port_pd01_port_0_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/samePortTypeAndOutParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/samePortTypeAndOutParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml index 380f7bb1dc..2ad9165c79 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/samePortTypeAndOutParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/samePortTypeAndOutParamGetAttrIn/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -32,6 +32,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_0_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_1_ip_requirements: type: list required: true @@ -58,26 +64,80 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer vm_flavor_name: type: string required: true status: SUPPORTED + port_pd01_port_0_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_0_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_1_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_pd01_port_1_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string vm_image_name: type: string required: true status: SUPPORTED + port_pd01_port_1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_1_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_0_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_0_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_1_network: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/samePortTypeAndOutParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/samePortTypeAndOutParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml index d9d82c2f68..0554f63c37 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/samePortTypeAndOutParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/samePortTypeAndOutParamGetAttrIn/out/Nested_pd_serverServiceTemplate.yaml @@ -31,6 +31,11 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_0_network_role: + type: list + required: true + entry_schema: + type: string port_pd01_port_1_ip_requirements: type: list required: true @@ -53,22 +58,67 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_1_order: + type: list + required: true + entry_schema: + type: integer vm_flavor_name: type: string required: true + port_pd01_port_0_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_pd01_port_1_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_0_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_1_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd01_port_1_mac_requirements: type: list required: true entry_schema: type: json + port_pd01_port_1_subnetpoolid: + type: list + required: true + entry_schema: + type: string vm_image_name: type: string required: true + port_pd01_port_1_exCP_naming: + type: list + required: true + entry_schema: + type: json port_pd01_port_1_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_0_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_0_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd01_port_1_network: type: list required: true @@ -102,6 +152,14 @@ topology_template: pd_server_pd01_port_1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_1_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_1_ip_requirements @@ -114,6 +172,18 @@ topology_template: get_input: - port_pd01_port_1_mac_requirements - index_value + order: + get_input: + - port_pd01_port_1_order + - index_value + network_role: + get_input: + - port_pd01_port_1_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_1_subnetpoolid + - index_value network: get_input: - port_pd01_port_1_network @@ -126,6 +196,14 @@ topology_template: pd_server_pd01_port_0: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_0_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_0_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_0_ip_requirements @@ -138,6 +216,18 @@ topology_template: get_input: - port_pd01_port_0_mac_requirements - index_value + order: + get_input: + - port_pd01_port_0_order + - index_value + network_role: + get_input: + - port_pd01_port_0_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_0_subnetpoolid + - index_value network: get_input: - port_pd01_port_0_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/GlobalSubstitutionTypesServiceTemplate.yaml index 7c9866a5f0..7d05b9ccc7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,13 +8,49 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_pd01_port_mac_requirements: + compute_pd_server_scheduler_hints: type: list required: true status: SUPPORTED entry_schema: type: json - compute_pd_server_scheduler_hints: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_pd01_port_security_groups: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_mac_requirements: type: list required: true status: SUPPORTED @@ -36,42 +72,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string - required: true - status: SUPPORTED - port_pd01_port_security_groups: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -428,6 +458,30 @@ node_types: org.openecomp.resource.abstract.nodes.oam_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_pd01_port_security_groups: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_mac_requirements: type: list required: true @@ -456,18 +510,18 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - vm_flavor_name: - type: string + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list required: true status: SUPPORTED + entry_schema: + type: string compute_oam_server_user_data_format: type: list required: true @@ -480,18 +534,24 @@ node_types: status: SUPPORTED entry_schema: type: string - port_pd01_port_security_groups: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: - type: json + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_oam_server_scheduler_hints: type: list required: true @@ -843,22 +903,12 @@ node_types: org.openecomp.resource.abstract.nodes.ps_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_pd01_port_mac_requirements: - type: list - required: true - status: SUPPORTED - entry_schema: - type: json compute_ps_server_name: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string - required: true - status: SUPPORTED compute_ps_server_availability_zone: type: list required: true @@ -877,6 +927,40 @@ node_types: status: SUPPORTED entry_schema: type: json + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_pd01_port_security_groups: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_pd01_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED port_pd01_port_ip_requirements: type: list required: true @@ -889,19 +973,31 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - vm_flavor_name: - type: string + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list required: true status: SUPPORTED - port_pd01_port_security_groups: + entry_schema: + type: string + port_pd01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: type: list required: true status: SUPPORTED diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/MainServiceTemplate.yaml index 104d72f82a..21a0a374de 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/MainServiceTemplate.yaml @@ -202,21 +202,8 @@ topology_template: directives: - substitutable properties: - port_pd01_port_mac_requirements: - - mac_count_required: - is_required: false compute_pd_server_scheduler_hints: - group: BE_Affinity_group - vm_image_name: - get_input: pd_image_name - port_pd01_port_ip_requirements: - - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - port_pd01_port_network: - - get_input: oam_net_name compute_pd_server_availability_zone: - get_input: availabilityzone_name compute_pd_server_name: @@ -229,6 +216,19 @@ topology_template: - name port_pd01_port_security_groups: - - jsa_security_group + port_pd01_port_mac_requirements: + - mac_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name + port_pd01_port_ip_requirements: + - - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + port_pd01_port_network: + - get_input: oam_net_name port_pd01_port_network_role_tag: - oam compute_pd_server_user_data_format: @@ -251,21 +251,27 @@ topology_template: directives: - substitutable properties: - port_pd01_port_mac_requirements: - - mac_count_required: - is_required: false compute_ps_server_name: - get_input: - ps_server_names - 0 - vm_image_name: - get_input: pd_image_name compute_ps_server_availability_zone: - get_input: availabilityzone_name compute_ps_server_user_data_format: - RAW compute_ps_server_scheduler_hints: - group: BE_Affinity_group + vm_flavor_name: + get_attribute: + - network_policy_server + - name + port_pd01_port_security_groups: + - - jsa_security_group + port_pd01_port_mac_requirements: + - mac_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name port_pd01_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -276,12 +282,6 @@ topology_template: - get_attribute: - network_policy_server - name - vm_flavor_name: - get_attribute: - - network_policy_server - - name - port_pd01_port_security_groups: - - - jsa_security_group service_template_filter: substitute_service_template: Nested_ps_serverServiceTemplate.yaml count: 1 @@ -300,6 +300,12 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_attribute: + - network_policy_server + - name + port_pd01_port_security_groups: + - - jsa_security_group port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -315,18 +321,12 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - vm_flavor_name: - get_attribute: - - network_policy_server - - name compute_oam_server_user_data_format: - RAW compute_oam_server_name: - get_input: - oam_server_names - 0 - port_pd01_port_security_groups: - - - jsa_security_group port_pd01_port_network_role_tag: - oam compute_oam_server_scheduler_hints: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_oam_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_oam_serverServiceTemplate.yaml index e9f9aee10e..4e1b24e7f0 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_oam_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_oam_serverServiceTemplate.yaml @@ -11,6 +11,26 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_pd01_port_security_groups: + type: list + required: true + entry_schema: + type: json port_pd01_port_mac_requirements: type: list required: true @@ -34,16 +54,16 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - vm_flavor_name: - type: string + port_pd01_port_order: + type: list required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string compute_oam_server_user_data_format: type: list required: true @@ -54,16 +74,21 @@ topology_template: required: true entry_schema: type: string - port_pd01_port_security_groups: + port_pd01_port_network_role: type: list required: true entry_schema: - type: json + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_oam_server_scheduler_hints: type: list required: true @@ -77,6 +102,14 @@ topology_template: get_input: - port_pd01_port_security_groups - index_value + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -89,6 +122,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_pd_serverServiceTemplate.yaml index c79dd4cc64..1356fb8878 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_pd_serverServiceTemplate.yaml @@ -11,12 +11,42 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_pd01_port_mac_requirements: + compute_pd_server_scheduler_hints: type: list required: true entry_schema: type: json - compute_pd_server_scheduler_hints: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_pd01_port_security_groups: + type: list + required: true + entry_schema: + type: json + port_pd01_port_mac_requirements: type: list required: true entry_schema: @@ -34,36 +64,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string - required: true - port_pd01_port_security_groups: + port_pd01_port_network_role: type: list required: true entry_schema: - type: json + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -100,6 +125,14 @@ topology_template: get_input: - port_pd01_port_security_groups - index_value + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -112,6 +145,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_ps_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_ps_serverServiceTemplate.yaml index b2c48a9534..f408bad2cc 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_ps_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithAllConnectivities/out/Nested_ps_serverServiceTemplate.yaml @@ -11,19 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_pd01_port_mac_requirements: - type: list - required: true - entry_schema: - type: json compute_ps_server_name: type: list required: true entry_schema: type: string - vm_image_name: - type: string - required: true compute_ps_server_availability_zone: type: list required: true @@ -39,16 +31,6 @@ topology_template: required: true entry_schema: type: json - port_pd01_port_ip_requirements: - type: list - required: true - entry_schema: - type: json - port_pd01_port_network: - type: list - required: true - entry_schema: - type: string index_value: type: integer description: Index value of this substitution service template runtime instance @@ -56,6 +38,11 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json vm_flavor_name: type: string required: true @@ -64,6 +51,49 @@ topology_template: required: true entry_schema: type: json + port_pd01_port_mac_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true + port_pd01_port_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_pd01_port_network: + type: list + required: true + entry_schema: + type: string + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd01_port_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json node_templates: ps_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port @@ -72,14 +102,38 @@ topology_template: get_input: - port_pd01_port_security_groups - index_value + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/GlobalSubstitutionTypesServiceTemplate.yaml index d4a4f2e671..85ccd9d77a 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +60,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -405,6 +435,24 @@ node_types: org.openecomp.resource.abstract.nodes.oam_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -433,18 +481,18 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - vm_flavor_name: - type: string + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list required: true status: SUPPORTED + entry_schema: + type: string compute_oam_server_user_data_format: type: list required: true @@ -457,12 +505,24 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json requirements: - dependency_oam_server_pd01_port: capability: tosca.capabilities.Node @@ -802,34 +862,52 @@ node_types: org.openecomp.resource.abstract.nodes.ps_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_pd01_port_mac_requirements: + compute_ps_server_name: type: list required: true status: SUPPORTED entry_schema: - type: json - compute_ps_server_name: + type: string + compute_ps_server_availability_zone: type: list required: true status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string + compute_ps_server_user_data_format: + type: list required: true status: SUPPORTED - compute_ps_server_availability_zone: + entry_schema: + type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + port_pd01_port_exCP_naming: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_ps_server_user_data_format: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_pd01_port_mac_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string + type: json + vm_image_name: + type: string + required: true + status: SUPPORTED port_pd01_port_ip_requirements: type: list required: true @@ -842,18 +920,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - vm_flavor_name: - type: string + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string + port_pd01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json requirements: - dependency_ps_server_pd01_port: capability: tosca.capabilities.Node diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/MainServiceTemplate.yaml index 1e96f5cadd..4a0ccad45d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/MainServiceTemplate.yaml @@ -175,6 +175,16 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 0 + vm_flavor_name: + get_attribute: + - network_policy_server + - name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -188,16 +198,6 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 0 - vm_flavor_name: - get_attribute: - - network_policy_server - - name port_pd01_port_network_role_tag: - oam compute_pd_server_user_data_format: @@ -215,19 +215,23 @@ topology_template: directives: - substitutable properties: - port_pd01_port_mac_requirements: - - mac_count_required: - is_required: false compute_ps_server_name: - get_input: - ps_server_names - 0 - vm_image_name: - get_input: pd_image_name compute_ps_server_availability_zone: - get_input: availabilityzone_name compute_ps_server_user_data_format: - RAW + vm_flavor_name: + get_attribute: + - network_policy_server + - name + port_pd01_port_mac_requirements: + - mac_count_required: + is_required: false + vm_image_name: + get_input: pd_image_name port_pd01_port_ip_requirements: - - ip_version: 4 ip_count_required: @@ -238,10 +242,6 @@ topology_template: - get_attribute: - network_policy_server - name - vm_flavor_name: - get_attribute: - - network_policy_server - - name service_template_filter: substitute_service_template: Nested_ps_serverServiceTemplate.yaml count: 1 @@ -255,6 +255,10 @@ topology_template: directives: - substitutable properties: + vm_flavor_name: + get_attribute: + - network_policy_server + - name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -270,10 +274,6 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - vm_flavor_name: - get_attribute: - - network_policy_server - - name compute_oam_server_user_data_format: - RAW compute_oam_server_name: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_oam_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_oam_serverServiceTemplate.yaml index 999882d584..9a034c3803 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_oam_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_oam_serverServiceTemplate.yaml @@ -11,6 +11,21 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -34,16 +49,16 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - vm_flavor_name: - type: string + port_pd01_port_order: + type: list required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string compute_oam_server_user_data_format: type: list required: true @@ -54,15 +69,33 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_network_role: + type: list + required: true + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json node_templates: oam_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -75,6 +108,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_pd_serverServiceTemplate.yaml index 74044a11c2..dd358a5dd2 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,6 +107,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_ps_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_ps_serverServiceTemplate.yaml index 9b747c547e..8ccfbad0a7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_ps_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeDiffComputesWithPorts/out/Nested_ps_serverServiceTemplate.yaml @@ -11,19 +11,11 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_pd01_port_mac_requirements: - type: list - required: true - entry_schema: - type: json compute_ps_server_name: type: list required: true entry_schema: type: string - vm_image_name: - type: string - required: true compute_ps_server_availability_zone: type: list required: true @@ -34,6 +26,29 @@ topology_template: required: true entry_schema: type: string + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_pd01_port_mac_requirements: + type: list + required: true + entry_schema: + type: json + vm_image_name: + type: string + required: true port_pd01_port_ip_requirements: type: list required: true @@ -44,28 +59,67 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - vm_flavor_name: - type: string + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_pd01_port_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json node_templates: ps_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/GlobalSubstitutionTypesServiceTemplate.yaml index 1bf05aa17e..13e08cc899 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -24,30 +54,36 @@ node_types: status: SUPPORTED entry_schema: type: json - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list required: true status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -393,6 +429,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -409,30 +475,36 @@ node_types: status: SUPPORTED entry_schema: type: json - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list required: true status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -778,6 +850,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -800,36 +902,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/MainServiceTemplate.yaml index 3fab6b6130..6eec7d894d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/MainServiceTemplate.yaml @@ -190,6 +190,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 2 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -203,14 +211,6 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 2 - vm_flavor_name: - get_input: pd_flavor_name port_pd01_port_network_role_tag: - oam compute_pd_server_user_data_format: @@ -233,6 +233,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -244,14 +252,6 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW service_template_filter: @@ -267,6 +267,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -278,14 +286,6 @@ topology_template: is_required: false floating_ip_count_required: is_required: false - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 0 - vm_flavor_name: - get_input: pd_flavor_name compute_pd_server_user_data_format: - RAW service_template_filter: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_0ServiceTemplate.yaml index a0614d3393..2ca7b3c25f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_0ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -24,26 +49,31 @@ topology_template: required: true entry_schema: type: json - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -72,14 +102,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_attribute: - pd_server diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_1ServiceTemplate.yaml index c32b489666..445fc6df88 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_1ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -24,26 +49,31 @@ topology_template: required: true entry_schema: type: json - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -72,14 +102,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_attribute: - pd_server diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_2ServiceTemplate.yaml index 1b487934d1..08e5895c0e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeNovaSameTypeWithGetAttrFromPort/out/Nested_pd_server_2ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,6 +107,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml index 4f96bcd484..c5923cc46b 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_0: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +60,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -405,6 +435,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -427,30 +487,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 + port_pd01_port_order: + type: list + required: true status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -796,6 +862,24 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server_2: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + port_pd01_port_2_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_pd01_port_3_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_3_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer index_value: type: integer description: Index value of this substitution service template runtime instance @@ -804,6 +888,12 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 + port_pd01_port_2_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_availability_zone: type: list required: true @@ -844,22 +934,52 @@ node_types: status: SUPPORTED entry_schema: type: string + port_pd01_port_2_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_2_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string vm_image_name: type: string required: true status: SUPPORTED + port_pd01_port_3_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_pd01_port_2_network: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_3_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_2_mac_requirements: type: list required: true status: SUPPORTED entry_schema: type: json + port_pd01_port_2_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_pd01_port_3_network_role_tag: type: list required: true @@ -878,6 +998,12 @@ node_types: status: SUPPORTED entry_schema: type: json + port_pd01_port_3_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json requirements: - dependency_pd_server: capability: tosca.capabilities.Node diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/MainServiceTemplate.yaml index 393fbdc37a..873c04ebec 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/MainServiceTemplate.yaml @@ -233,6 +233,16 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 1 + vm_flavor_name: + get_attribute: + - network_policy_server + - name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -246,16 +256,6 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 1 - vm_flavor_name: - get_attribute: - - network_policy_server - - name port_pd01_port_network_role_tag: - oam compute_pd_server_user_data_format: @@ -273,6 +273,16 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 0 + vm_flavor_name: + get_attribute: + - network_policy_server + - name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -288,16 +298,6 @@ topology_template: - get_attribute: - network_policy_server - name - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 0 - vm_flavor_name: - get_attribute: - - network_policy_server - - name compute_pd_server_user_data_format: - RAW service_template_filter: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_0ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_0ServiceTemplate.yaml index b6c4036c6d..6a96d70747 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_0ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_0ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,6 +107,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_1ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_1ServiceTemplate.yaml index a0da89fcd1..1efd8dcca0 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_1ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_1ServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,26 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - compute_pd_server_name: + port_pd01_port_network_role: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_pd01_port_vlan_requirements: + type: list required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -77,14 +107,38 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements - index_value + network_role_tag: + get_input: + - port_pd01_port_network_role_tag + - index_value mac_requirements: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_2ServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_2ServiceTemplate.yaml index f9becc9b4a..fd95fdc3fe 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_2ServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/threeSameComputesNoConsolidation/out/Nested_pd_server_2ServiceTemplate.yaml @@ -11,6 +11,21 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + port_pd01_port_2_order: + type: list + required: true + entry_schema: + type: integer + port_pd01_port_3_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_3_order: + type: list + required: true + entry_schema: + type: integer index_value: type: integer description: Index value of this substitution service template runtime instance @@ -18,6 +33,11 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_pd01_port_2_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_availability_zone: type: list required: true @@ -51,19 +71,44 @@ topology_template: required: true entry_schema: type: string + port_pd01_port_2_network_role: + type: list + required: true + entry_schema: + type: string + port_pd01_port_2_subnetpoolid: + type: list + required: true + entry_schema: + type: string vm_image_name: type: string required: true + port_pd01_port_3_subnetpoolid: + type: list + required: true + entry_schema: + type: string port_pd01_port_2_network: type: list required: true entry_schema: type: string + port_pd01_port_3_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_pd01_port_2_mac_requirements: type: list required: true entry_schema: type: json + port_pd01_port_2_exCP_naming: + type: list + required: true + entry_schema: + type: json port_pd01_port_3_network_role_tag: type: list required: true @@ -79,6 +124,11 @@ topology_template: required: true entry_schema: type: json + port_pd01_port_3_exCP_naming: + type: list + required: true + entry_schema: + type: json node_templates: pd_server: type: org.openecomp.resource.vfc.nodes.heat.pd_server @@ -102,6 +152,14 @@ topology_template: pd_server_pd01_port_2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_2_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_2_ip_requirements @@ -114,6 +172,18 @@ topology_template: get_input: - port_pd01_port_2_mac_requirements - index_value + order: + get_input: + - port_pd01_port_2_order + - index_value + network_role: + get_input: + - port_pd01_port_2_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_2_subnetpoolid + - index_value network: get_input: - port_pd01_port_2_network @@ -126,6 +196,14 @@ topology_template: pd_server_pd01_port_3: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_3_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_3_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_3_ip_requirements @@ -138,6 +216,18 @@ topology_template: get_input: - port_pd01_port_3_mac_requirements - index_value + order: + get_input: + - port_pd01_port_3_order + - index_value + network_role: + get_input: + - port_pd01_port_3_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_3_subnetpoolid + - index_value network: get_input: - port_pd01_port_3_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/GlobalSubstitutionTypesServiceTemplate.yaml index 63f9c558e7..fb56d43c41 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +60,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -417,10 +447,12 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string + port_ps01_port_subnetpoolid: + type: list required: true status: SUPPORTED + entry_schema: + type: string compute_ps_server_availability_zone: type: list required: true @@ -441,22 +473,44 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_ps01_port_mac_requirements: + port_ps01_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_ps01_port_network: + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_ps01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: + type: integer + vm_image_name: type: string required: true status: SUPPORTED + port_ps01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_ps01_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_ps01_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_ps01_port_ip_requirements: type: list required: true @@ -469,6 +523,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_ps01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json attributes: ps_server_accessIPv4: type: list diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/MainServiceTemplate.yaml index 2848946b96..f8c0769307 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/MainServiceTemplate.yaml @@ -355,6 +355,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -370,14 +378,6 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 0 - vm_flavor_name: - get_input: pd_flavor_name port_pd01_port_network_role_tag: - oam compute_pd_server_user_data_format: @@ -399,21 +399,21 @@ topology_template: - get_input: - ps_server_names - 0 - vm_image_name: - get_attribute: - - abstract_pd_server - - pd_server_accessIPv4 compute_ps_server_availability_zone: - get_input: availabilityzone_name compute_ps_server_user_data_format: - RAW + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_attribute: + - abstract_pd_server + - pd_server_accessIPv4 port_ps01_port_mac_requirements: - mac_count_required: is_required: false port_ps01_port_network: - get_input: oam_net_name - vm_flavor_name: - get_input: pd_flavor_name port_ps01_port_ip_requirements: - - ip_version: 4 ip_count_required: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/Nested_pd_serverServiceTemplate.yaml index 245fee1136..ad0a81d4dc 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,6 +107,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/Nested_ps_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/Nested_ps_serverServiceTemplate.yaml index f889b1a55b..d92309c5c3 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/Nested_ps_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoComputesWithGetAttrBetweenThem/out/Nested_ps_serverServiceTemplate.yaml @@ -16,9 +16,11 @@ topology_template: required: true entry_schema: type: string - vm_image_name: - type: string + port_ps01_port_subnetpoolid: + type: list required: true + entry_schema: + type: string compute_ps_server_availability_zone: type: list required: true @@ -36,6 +38,27 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_ps01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_ps01_port_order: + type: list + required: true + entry_schema: + type: integer + vm_image_name: + type: string + required: true + port_ps01_port_network_role: + type: list + required: true + entry_schema: + type: string port_ps01_port_mac_requirements: type: list required: true @@ -46,9 +69,6 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string - required: true port_ps01_port_ip_requirements: type: list required: true @@ -59,6 +79,11 @@ topology_template: required: true entry_schema: type: string + port_ps01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json node_templates: ps_server: type: org.openecomp.resource.vfc.nodes.heat.ps_server @@ -82,6 +107,14 @@ topology_template: ps_server_ps01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_ps01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_ps01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_ps01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_ps01_port_mac_requirements - index_value + order: + get_input: + - port_ps01_port_order + - index_value + network_role: + get_input: + - port_ps01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_ps01_port_subnetpoolid + - index_value network: get_input: - port_ps01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/GlobalSubstitutionTypesServiceTemplate.yaml index a674d6bf46..2ef83fec70 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,6 +8,36 @@ node_types: org.openecomp.resource.abstract.nodes.pd_server: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + status: SUPPORTED + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED port_pd01_port_mac_requirements: type: list required: true @@ -30,36 +60,36 @@ node_types: status: SUPPORTED entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - status: SUPPORTED - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true status: SUPPORTED + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true status: SUPPORTED entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -411,10 +441,12 @@ node_types: status: SUPPORTED entry_schema: type: string - vm_image_name: - type: string + port_ps01_port_subnetpoolid: + type: list required: true status: SUPPORTED + entry_schema: + type: string compute_ps_server_availability_zone: type: list required: true @@ -435,22 +467,44 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_ps01_port_mac_requirements: + port_ps01_port_vlan_requirements: type: list required: true status: SUPPORTED entry_schema: type: json - port_ps01_port_network: + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_ps01_port_order: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: + type: integer + vm_image_name: type: string required: true status: SUPPORTED + port_ps01_port_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_ps01_port_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_ps01_port_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string port_ps01_port_ip_requirements: type: list required: true @@ -463,6 +517,12 @@ node_types: status: SUPPORTED entry_schema: type: string + port_ps01_port_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json requirements: - dependency_ps_server: capability: tosca.capabilities.Node diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/MainServiceTemplate.yaml index bbbd7dadd3..645929f408 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/MainServiceTemplate.yaml @@ -355,6 +355,14 @@ topology_template: directives: - substitutable properties: + compute_pd_server_availability_zone: + - get_input: availabilityzone_name + compute_pd_server_name: + - get_input: + - pd_server_names + - 0 + vm_flavor_name: + get_input: pd_flavor_name port_pd01_port_mac_requirements: - mac_count_required: is_required: false @@ -368,14 +376,6 @@ topology_template: is_required: false port_pd01_port_network: - get_input: oam_net_name - compute_pd_server_availability_zone: - - get_input: availabilityzone_name - compute_pd_server_name: - - get_input: - - pd_server_names - - 0 - vm_flavor_name: - get_input: pd_flavor_name port_pd01_port_network_role_tag: - oam compute_pd_server_user_data_format: @@ -397,19 +397,19 @@ topology_template: - get_input: - ps_server_names - 0 - vm_image_name: - get_input: pd_image_name compute_ps_server_availability_zone: - get_input: availabilityzone_name compute_ps_server_user_data_format: - RAW + vm_flavor_name: + get_input: pd_flavor_name + vm_image_name: + get_input: pd_image_name port_ps01_port_mac_requirements: - mac_count_required: is_required: false port_ps01_port_network: - get_input: oam_net_name - vm_flavor_name: - get_input: pd_flavor_name port_ps01_port_ip_requirements: - - ip_version: 4 ip_count_required: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/Nested_pd_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/Nested_pd_serverServiceTemplate.yaml index 74044a11c2..dd358a5dd2 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/Nested_pd_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/Nested_pd_serverServiceTemplate.yaml @@ -11,6 +11,31 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: + index_value: + type: integer + description: Index value of this substitution service template runtime instance + required: false + default: 0 + constraints: + - greater_or_equal: 0 + compute_pd_server_availability_zone: + type: list + required: true + entry_schema: + type: string + compute_pd_server_name: + type: list + required: true + entry_schema: + type: string + port_pd01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true port_pd01_port_mac_requirements: type: list required: true @@ -29,31 +54,31 @@ topology_template: required: true entry_schema: type: string - index_value: - type: integer - description: Index value of this substitution service template runtime instance - required: false - default: 0 - constraints: - - greater_or_equal: 0 - compute_pd_server_availability_zone: + port_pd01_port_order: type: list required: true entry_schema: - type: string - compute_pd_server_name: + type: integer + port_pd01_port_subnetpoolid: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_pd01_port_network_role: + type: list required: true + entry_schema: + type: string port_pd01_port_network_role_tag: type: list required: true entry_schema: type: string + port_pd01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json compute_pd_server_user_data_format: type: list required: true @@ -82,6 +107,14 @@ topology_template: pd_server_pd01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_pd01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_pd01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_pd01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_pd01_port_mac_requirements - index_value + order: + get_input: + - port_pd01_port_order + - index_value + network_role: + get_input: + - port_pd01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_pd01_port_subnetpoolid + - index_value network: get_input: - port_pd01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/Nested_ps_serverServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/Nested_ps_serverServiceTemplate.yaml index 5baa4a45ff..c16b51c98d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/Nested_ps_serverServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/fulltest/singleSubstitution/twoSetsOfSingle/out/Nested_ps_serverServiceTemplate.yaml @@ -16,9 +16,11 @@ topology_template: required: true entry_schema: type: string - vm_image_name: - type: string + port_ps01_port_subnetpoolid: + type: list required: true + entry_schema: + type: string compute_ps_server_availability_zone: type: list required: true @@ -36,6 +38,27 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_ps01_port_vlan_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_ps01_port_order: + type: list + required: true + entry_schema: + type: integer + vm_image_name: + type: string + required: true + port_ps01_port_network_role: + type: list + required: true + entry_schema: + type: string port_ps01_port_mac_requirements: type: list required: true @@ -46,9 +69,6 @@ topology_template: required: true entry_schema: type: string - vm_flavor_name: - type: string - required: true port_ps01_port_ip_requirements: type: list required: true @@ -59,6 +79,11 @@ topology_template: required: true entry_schema: type: string + port_ps01_port_exCP_naming: + type: list + required: true + entry_schema: + type: json node_templates: ps_server: type: org.openecomp.resource.vfc.nodes.heat.ps_server @@ -82,6 +107,14 @@ topology_template: ps_server_ps01_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_ps01_port_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_ps01_port_vlan_requirements + - index_value ip_requirements: get_input: - port_ps01_port_ip_requirements @@ -94,6 +127,18 @@ topology_template: get_input: - port_ps01_port_mac_requirements - index_value + order: + get_input: + - port_ps01_port_order + - index_value + network_role: + get_input: + - port_ps01_port_network_role + - index_value + subnetpoolid: + get_input: + - port_ps01_port_subnetpoolid + - index_value network: get_input: - port_ps01_port_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/getAttr/getAttrOnlyResourceName/expectedoutputfiles/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/getAttr/getAttrOnlyResourceName/expectedoutputfiles/MainServiceTemplate.yaml index 5d5f46e5fe..ec7134b1e0 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/getAttr/getAttrOnlyResourceName/expectedoutputfiles/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/getAttr/getAttrOnlyResourceName/expectedoutputfiles/MainServiceTemplate.yaml @@ -326,7 +326,6 @@ topology_template: - sub_interface_vlan_tag - mac - port_tuple_refs - - virtual_machine_intefrace_mac_addresses - ip_prefix - address_mode - mac_address @@ -337,6 +336,7 @@ topology_template: - virtual_network_refs - virtual_machine_interface_properties - virtual_machine_interface_allowed_address_pairs + - virtual_machine_interface_mac_addresses groups: ep-jsa_net_group: type: org.openecomp.groups.heat.HeatStack diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/inputfiles/FEAdd_On_Module_QRouterTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/inputfiles/FEAdd_On_Module_QRouterTemplate.yaml index aae1455919..758276fe18 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/inputfiles/FEAdd_On_Module_QRouterTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/inputfiles/FEAdd_On_Module_QRouterTemplate.yaml @@ -62,7 +62,7 @@ parameters: vnf_id: type: string resources: - QRouter: + QRouter1: properties: availability_zone: get_param: availability_zone_0 @@ -178,7 +178,7 @@ resources: qrouter_volume_0_att: properties: instance_uuid: - get_resource: QRouter + get_resource: QRouter1 volume_id: get_resource: qrouter_volume_0 type: OS::Cinder::VolumeAttachment @@ -194,7 +194,7 @@ resources: qrouter_volume_1_att: properties: instance_uuid: - get_resource: QRouter + get_resource: QRouter1 volume_id: get_resource: qrouter_volume_1 type: OS::Cinder::VolumeAttachment @@ -210,7 +210,7 @@ resources: qrouter_volume_2_att: properties: instance_uuid: - get_resource: QRouter + get_resource: QRouter1 volume_id: get_resource: qrouter_volume_2 type: OS::Cinder::VolumeAttachment \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/inputfiles/FEBase_Module.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/inputfiles/FEBase_Module.yaml index 5d0a5457ca..331737e599 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/inputfiles/FEBase_Module.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/inputfiles/FEBase_Module.yaml @@ -269,7 +269,7 @@ parameters: description: Windows servers' domain type: string resources: - QRouter: + QRouter0: depends_on: - security_group - packet_mirror_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/FEAdd_On_Module_QRouterTemplateServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/FEAdd_On_Module_QRouterTemplateServiceTemplate.yaml index ce5bddcbb4..ca861cbfc0 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/FEAdd_On_Module_QRouterTemplateServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/FEAdd_On_Module_QRouterTemplateServiceTemplate.yaml @@ -134,7 +134,52 @@ topology_template: immutable: false type: string node_templates: - QRouter: + qrouter_volume_1: + type: org.openecomp.resource.vfc.nodes.heat.cinder.Volume + properties: + volume_type: + get_input: qrouter_volume_type_1 + size: '(get_input : qrouter_volume_size_1) * 1024' + description: + get_input: qrouter_volume_name_1 + qrouter_volume_0: + type: org.openecomp.resource.vfc.nodes.heat.cinder.Volume + properties: + volume_type: + get_input: qrouter_volume_type_0 + size: '(get_input : qrouter_volume_size_0) * 1024' + description: + get_input: qrouter_volume_name_0 + cdr_network_port: + type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port + properties: + ip_requirements: + - ip_version: 4 + ip_count_required: + is_required: false + floating_ip_count_required: + is_required: false + security_groups: + - get_input: security_group + mac_requirements: + mac_count_required: + is_required: false + network: + get_input: cdr_network + requirements: + - binding: + capability: tosca.capabilities.network.Bindable + node: QRouter1 + relationship: tosca.relationships.network.BindsTo + qrouter_volume_2: + type: org.openecomp.resource.vfc.nodes.heat.cinder.Volume + properties: + volume_type: + get_input: qrouter_volume_type_2 + size: '(get_input : qrouter_volume_size_2) * 1024' + description: + get_input: qrouter_volume_name_2 + QRouter1: type: org.openecomp.resource.vfc.nodes.heat.qrouter properties: flavor: @@ -230,51 +275,6 @@ topology_template: register_status: type: tosca.artifacts.Deployment file: ../Artifacts/register_status.py - qrouter_volume_1: - type: org.openecomp.resource.vfc.nodes.heat.cinder.Volume - properties: - volume_type: - get_input: qrouter_volume_type_1 - size: '(get_input : qrouter_volume_size_1) * 1024' - description: - get_input: qrouter_volume_name_1 - qrouter_volume_0: - type: org.openecomp.resource.vfc.nodes.heat.cinder.Volume - properties: - volume_type: - get_input: qrouter_volume_type_0 - size: '(get_input : qrouter_volume_size_0) * 1024' - description: - get_input: qrouter_volume_name_0 - cdr_network_port: - type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port - properties: - ip_requirements: - - ip_version: 4 - ip_count_required: - is_required: false - floating_ip_count_required: - is_required: false - security_groups: - - get_input: security_group - mac_requirements: - mac_count_required: - is_required: false - network: - get_input: cdr_network - requirements: - - binding: - capability: tosca.capabilities.network.Bindable - node: QRouter - relationship: tosca.relationships.network.BindsTo - qrouter_volume_2: - type: org.openecomp.resource.vfc.nodes.heat.cinder.Volume - properties: - volume_type: - get_input: qrouter_volume_type_2 - size: '(get_input : qrouter_volume_size_2) * 1024' - description: - get_input: qrouter_volume_name_2 oam_private_net_network_port: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: @@ -295,78 +295,66 @@ topology_template: requirements: - binding: capability: tosca.capabilities.network.Bindable - node: QRouter + node: QRouter1 relationship: tosca.relationships.network.BindsTo relationship_templates: qrouter_volume_0_att: type: org.openecomp.relationships.VolumeAttachesTo properties: volume_id: qrouter_volume_0 - instance_uuid: QRouter + instance_uuid: QRouter1 qrouter_volume_2_att: type: org.openecomp.relationships.VolumeAttachesTo properties: volume_id: qrouter_volume_2 - instance_uuid: QRouter + instance_uuid: QRouter1 qrouter_volume_1_att: type: org.openecomp.relationships.VolumeAttachesTo properties: volume_id: qrouter_volume_1 - instance_uuid: QRouter + instance_uuid: QRouter1 groups: FEAdd_On_Module_QRouterTemplate_group: type: org.openecomp.groups.heat.HeatStack properties: heat_file: ../Artifacts/FEAdd_On_Module_QRouterTemplate.yaml members: - - QRouter - qrouter_volume_1 - qrouter_volume_0 - cdr_network_port - qrouter_volume_2 + - QRouter1 - oam_private_net_network_port substitution_mappings: node_type: org.openecomp.resource.abstract.nodes.heat.FEAdd_On_Module_QRouterTemplate capabilities: - disk.usage_QRouter: - - QRouter - - disk.usage network.outgoing.bytes_cdr_network_port: - cdr_network_port - network.outgoing.bytes - disk.write.bytes_QRouter: - - QRouter - - disk.write.bytes + binding_QRouter1: + - QRouter1 + - binding attachment_oam_private_net_network_port: - oam_private_net_network_port - attachment feature_qrouter_volume_1: - qrouter_volume_1 - feature - disk.device.write.bytes_QRouter: - - QRouter - - disk.device.write.bytes feature_qrouter_volume_2: - qrouter_volume_2 - feature - endpoint_QRouter: - - QRouter - - endpoint feature_qrouter_volume_0: - qrouter_volume_0 - feature attachment_qrouter_volume_2: - qrouter_volume_2 - attachment - disk.capacity_QRouter: - - QRouter - - disk.capacity + cpu_util_QRouter1: + - QRouter1 + - cpu_util attachment_qrouter_volume_0: - qrouter_volume_0 - attachment - disk.read.bytes.rate_QRouter: - - QRouter - - disk.read.bytes.rate attachment_qrouter_volume_1: - qrouter_volume_1 - attachment @@ -376,172 +364,181 @@ topology_template: network.incoming.packets_cdr_network_port: - cdr_network_port - network.incoming.packets + disk.device.read.bytes.rate_QRouter1: + - QRouter1 + - disk.device.read.bytes.rate network.outgoing.bytes.rate_oam_private_net_network_port: - oam_private_net_network_port - network.outgoing.bytes.rate - instance_QRouter: - - QRouter - - instance - disk.device.latency_QRouter: - - QRouter - - disk.device.latency - disk.device.usage_QRouter: - - QRouter - - disk.device.usage - disk.ephemeral.size_QRouter: - - QRouter - - disk.ephemeral.size - disk.device.iops_QRouter: - - QRouter - - disk.device.iops + disk.device.read.bytes_QRouter1: + - QRouter1 + - disk.device.read.bytes network.outpoing.packets_oam_private_net_network_port: - oam_private_net_network_port - network.outpoing.packets network.outpoing.packets_cdr_network_port: - cdr_network_port - network.outpoing.packets - disk.device.read.bytes_QRouter: - - QRouter - - disk.device.read.bytes - disk.iops_QRouter: - - QRouter - - disk.iops + memory.resident_QRouter1: + - QRouter1 + - memory.resident + disk.device.latency_QRouter1: + - QRouter1 + - disk.device.latency + host_QRouter1: + - QRouter1 + - host feature_cdr_network_port: - cdr_network_port - feature - disk.device.read.requests.rate_QRouter: - - QRouter - - disk.device.read.requests.rate - disk.read.bytes_QRouter: - - QRouter - - disk.read.bytes - memory.resident_QRouter: - - QRouter - - memory.resident - host_QRouter: - - QRouter - - host + disk.device.write.bytes.rate_QRouter1: + - QRouter1 + - disk.device.write.bytes.rate + disk.device.usage_QRouter1: + - QRouter1 + - disk.device.usage network.incoming.bytes_cdr_network_port: - cdr_network_port - network.incoming.bytes - memory_QRouter: - - QRouter - - memory - disk.device.read.requests_QRouter: - - QRouter - - disk.device.read.requests - scalable_QRouter: - - QRouter - - scalable - os_QRouter: - - QRouter - - os + instance_QRouter1: + - QRouter1 + - instance + disk.root.size_QRouter1: + - QRouter1 + - disk.root.size + vcpus_QRouter1: + - QRouter1 + - vcpus network.incoming.bytes_oam_private_net_network_port: - oam_private_net_network_port - network.incoming.bytes - disk.write.bytes.rate_QRouter: - - QRouter - - disk.write.bytes.rate feature_oam_private_net_network_port: - oam_private_net_network_port - feature - cpu_util_QRouter: - - QRouter - - cpu_util + cpu.delta_QRouter1: + - QRouter1 + - cpu.delta + disk.capacity_QRouter1: + - QRouter1 + - disk.capacity + memory.usage_QRouter1: + - QRouter1 + - memory.usage + disk.write.requests.rate_QRouter1: + - QRouter1 + - disk.write.requests.rate + disk.read.requests_QRouter1: + - QRouter1 + - disk.read.requests + feature_QRouter1: + - QRouter1 + - feature network.incoming.bytes.rate_oam_private_net_network_port: - oam_private_net_network_port - network.incoming.bytes.rate - disk.device.write.requests_QRouter: - - QRouter - - disk.device.write.requests - disk.device.read.bytes.rate_QRouter: - - QRouter - - disk.device.read.bytes.rate + disk.ephemeral.size_QRouter1: + - QRouter1 + - disk.ephemeral.size + disk.latency_QRouter1: + - QRouter1 + - disk.latency + disk.device.capacity_QRouter1: + - QRouter1 + - disk.device.capacity network.incoming.bytes.rate_cdr_network_port: - cdr_network_port - network.incoming.bytes.rate - disk.device.allocation_QRouter: - - QRouter - - disk.device.allocation network.outgoing.bytes_oam_private_net_network_port: - oam_private_net_network_port - network.outgoing.bytes - disk.device.capacity_QRouter: - - QRouter - - disk.device.capacity - feature_QRouter: - - QRouter - - feature - disk.read.requests_QRouter: - - QRouter - - disk.read.requests - disk.device.write.bytes.rate_QRouter: - - QRouter - - disk.device.write.bytes.rate - disk.write.requests_QRouter: - - QRouter - - disk.write.requests - disk.root.size_QRouter: - - QRouter - - disk.root.size - memory.usage_QRouter: - - QRouter - - memory.usage + disk.iops_QRouter1: + - QRouter1 + - disk.iops + disk.device.write.requests_QRouter1: + - QRouter1 + - disk.device.write.requests + disk.device.write.requests.rate_QRouter1: + - QRouter1 + - disk.device.write.requests.rate + disk.device.allocation_QRouter1: + - QRouter1 + - disk.device.allocation + memory_QRouter1: + - QRouter1 + - memory + disk.usage_QRouter1: + - QRouter1 + - disk.usage + scalable_QRouter1: + - QRouter1 + - scalable network.outgoing.bytes.rate_cdr_network_port: - cdr_network_port - network.outgoing.bytes.rate binding_oam_private_net_network_port: - oam_private_net_network_port - binding - cpu_QRouter: - - QRouter - - cpu - vcpus_QRouter: - - QRouter - - vcpus - disk.allocation_QRouter: - - QRouter - - disk.allocation network.incoming.packets.rate_cdr_network_port: - cdr_network_port - network.incoming.packets.rate + disk.write.bytes_QRouter1: + - QRouter1 + - disk.write.bytes + disk.write.requests_QRouter1: + - QRouter1 + - disk.write.requests network.incoming.packets_oam_private_net_network_port: - oam_private_net_network_port - network.incoming.packets + cpu_QRouter1: + - QRouter1 + - cpu + os_QRouter1: + - QRouter1 + - os + disk.device.read.requests.rate_QRouter1: + - QRouter1 + - disk.device.read.requests.rate network.incoming.packets.rate_oam_private_net_network_port: - oam_private_net_network_port - network.incoming.packets.rate - disk.device.write.requests.rate_QRouter: - - QRouter - - disk.device.write.requests.rate - cpu.delta_QRouter: - - QRouter - - cpu.delta - binding_QRouter: - - QRouter - - binding + disk.read.bytes_QRouter1: + - QRouter1 + - disk.read.bytes binding_cdr_network_port: - cdr_network_port - binding + disk.write.bytes.rate_QRouter1: + - QRouter1 + - disk.write.bytes.rate + disk.device.write.bytes_QRouter1: + - QRouter1 + - disk.device.write.bytes network.outgoing.packets.rate_cdr_network_port: - cdr_network_port - network.outgoing.packets.rate - disk.latency_QRouter: - - QRouter - - disk.latency - disk.write.requests.rate_QRouter: - - QRouter - - disk.write.requests.rate + disk.device.iops_QRouter1: + - QRouter1 + - disk.device.iops + disk.read.bytes.rate_QRouter1: + - QRouter1 + - disk.read.bytes.rate + endpoint_QRouter1: + - QRouter1 + - endpoint + disk.allocation_QRouter1: + - QRouter1 + - disk.allocation + disk.device.read.requests_QRouter1: + - QRouter1 + - disk.device.read.requests network.outgoing.packets.rate_oam_private_net_network_port: - oam_private_net_network_port - network.outgoing.packets.rate requirements: - local_storage_QRouter: - - QRouter + local_storage_QRouter1: + - QRouter1 - local_storage - dependency_QRouter: - - QRouter - - dependency dependency_qrouter_volume_1: - qrouter_volume_1 - dependency @@ -562,4 +559,7 @@ topology_template: - dependency link_cdr_network_port: - cdr_network_port - - link \ No newline at end of file + - link + dependency_QRouter1: + - QRouter1 + - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/GlobalSubstitutionTypesServiceTemplate.yaml index 4d7aa4f012..86de04a96c 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -131,20 +131,6 @@ node_types: required: true status: SUPPORTED requirements: - - dependency_QRouter: - capability: tosca.capabilities.Node - node: tosca.nodes.Root - relationship: tosca.relationships.DependsOn - occurrences: - - 0 - - UNBOUNDED - - local_storage_QRouter: - capability: tosca.capabilities.Attachment - node: tosca.nodes.BlockStorage - relationship: tosca.relationships.AttachesTo - occurrences: - - 0 - - UNBOUNDED - dependency_qrouter_volume_1: capability: tosca.capabilities.Node node: tosca.nodes.Root @@ -179,6 +165,20 @@ node_types: occurrences: - 0 - UNBOUNDED + - dependency_QRouter1: + capability: tosca.capabilities.Node + node: tosca.nodes.Root + relationship: tosca.relationships.DependsOn + occurrences: + - 0 + - UNBOUNDED + - local_storage_QRouter1: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: + - 0 + - UNBOUNDED - dependency_oam_private_net_network_port: capability: tosca.capabilities.Node node: tosca.nodes.Root @@ -193,21 +193,14 @@ node_types: - 1 - 1 capabilities: - disk.usage_QRouter: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED network.outgoing.bytes_cdr_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.bytes_QRouter: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + binding_QRouter1: + type: tosca.capabilities.network.Bindable occurrences: - 1 - UNBOUNDED @@ -221,22 +214,11 @@ node_types: occurrences: - 1 - UNBOUNDED - disk.device.write.bytes_QRouter: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED feature_qrouter_volume_2: type: tosca.capabilities.Node occurrences: - 1 - UNBOUNDED - endpoint_QRouter: - type: tosca.capabilities.Endpoint.Admin - occurrences: - - 1 - - UNBOUNDED feature_qrouter_volume_0: type: tosca.capabilities.Node occurrences: @@ -247,7 +229,7 @@ node_types: occurrences: - 1 - UNBOUNDED - disk.capacity_QRouter: + cpu_util_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -258,12 +240,6 @@ node_types: occurrences: - 1 - UNBOUNDED - disk.read.bytes.rate_QRouter: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. - occurrences: - - 1 - - UNBOUNDED attachment_qrouter_volume_1: type: tosca.capabilities.Attachment occurrences: @@ -280,160 +256,161 @@ node_types: occurrences: - 1 - UNBOUNDED - network.outgoing.bytes.rate_oam_private_net_network_port: + disk.device.read.bytes.rate_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - instance_QRouter: + network.outgoing.bytes.rate_oam_private_net_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.latency_QRouter: + disk.device.read.bytes_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.usage_QRouter: + network.outpoing.packets_oam_private_net_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.ephemeral.size_QRouter: + network.outpoing.packets_cdr_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.iops_QRouter: + memory.resident_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.outpoing.packets_oam_private_net_network_port: + disk.device.latency_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.outpoing.packets_cdr_network_port: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + host_QRouter1: + type: tosca.capabilities.Container + valid_source_types: + - tosca.nodes.SoftwareComponent occurrences: - 1 - UNBOUNDED - disk.device.read.bytes_QRouter: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + feature_cdr_network_port: + type: tosca.capabilities.Node occurrences: - 1 - UNBOUNDED - disk.iops_QRouter: + disk.device.write.bytes.rate_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - feature_cdr_network_port: - type: tosca.capabilities.Node + disk.device.usage_QRouter1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.requests.rate_QRouter: + network.incoming.bytes_cdr_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.read.bytes_QRouter: + instance_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - memory.resident_QRouter: + disk.root.size_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - host_QRouter: - type: tosca.capabilities.Container - valid_source_types: - - tosca.nodes.SoftwareComponent + vcpus_QRouter1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.bytes_cdr_network_port: + network.incoming.bytes_oam_private_net_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - memory_QRouter: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + feature_oam_private_net_network_port: + type: tosca.capabilities.Node occurrences: - 1 - UNBOUNDED - disk.device.read.requests_QRouter: + cpu.delta_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - scalable_QRouter: - type: tosca.capabilities.Scalable + disk.capacity_QRouter1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - os_QRouter: - type: tosca.capabilities.OperatingSystem + memory.usage_QRouter1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.bytes_oam_private_net_network_port: + disk.write.requests.rate_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.bytes.rate_QRouter: + disk.read.requests_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - feature_oam_private_net_network_port: + feature_QRouter1: type: tosca.capabilities.Node occurrences: - 1 - UNBOUNDED - cpu_util_QRouter: + network.incoming.bytes.rate_oam_private_net_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.bytes.rate_oam_private_net_network_port: + disk.ephemeral.size_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.write.requests_QRouter: + disk.latency_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.bytes.rate_QRouter: + disk.device.capacity_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -445,56 +422,50 @@ node_types: occurrences: - 1 - UNBOUNDED - disk.device.allocation_QRouter: + network.outgoing.bytes_oam_private_net_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.outgoing.bytes_oam_private_net_network_port: + disk.iops_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.capacity_QRouter: + disk.device.write.requests_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - feature_QRouter: - type: tosca.capabilities.Node - occurrences: - - 1 - - UNBOUNDED - disk.read.requests_QRouter: + disk.device.write.requests.rate_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.write.bytes.rate_QRouter: + disk.device.allocation_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.requests_QRouter: + memory_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.root.size_QRouter: + disk.usage_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - memory.usage_QRouter: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + scalable_QRouter1: + type: tosca.capabilities.Scalable occurrences: - 1 - UNBOUNDED @@ -511,56 +482,56 @@ node_types: occurrences: - 0 - UNBOUNDED - cpu_QRouter: + network.incoming.packets.rate_cdr_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - vcpus_QRouter: + disk.write.bytes_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.allocation_QRouter: + disk.write.requests_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.packets.rate_cdr_network_port: + network.incoming.packets_oam_private_net_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.packets_oam_private_net_network_port: + cpu_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.packets.rate_oam_private_net_network_port: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + os_QRouter1: + type: tosca.capabilities.OperatingSystem occurrences: - 1 - UNBOUNDED - disk.device.write.requests.rate_QRouter: + disk.device.read.requests.rate_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - cpu.delta_QRouter: + network.incoming.packets.rate_oam_private_net_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - binding_QRouter: - type: tosca.capabilities.network.Bindable + disk.read.bytes_QRouter1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED @@ -571,19 +542,48 @@ node_types: occurrences: - 0 - UNBOUNDED + disk.write.bytes.rate_QRouter1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.device.write.bytes_QRouter1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED network.outgoing.packets.rate_cdr_network_port: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.latency_QRouter: + disk.device.iops_QRouter1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + disk.read.bytes.rate_QRouter1: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + occurrences: + - 1 + - UNBOUNDED + endpoint_QRouter1: + type: tosca.capabilities.Endpoint.Admin + occurrences: + - 1 + - UNBOUNDED + disk.allocation_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.requests.rate_QRouter: + disk.device.read.requests_QRouter1: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/MainServiceTemplate.yaml index b6e1ec9cd6..7d2364e084 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/securityrulestoportconnection/securityRulesToPortGetResource/out/MainServiceTemplate.yaml @@ -733,91 +733,6 @@ topology_template: capability: tosca.capabilities.Node node: packet_internal_network relationship: tosca.relationships.DependsOn - QRouter: - type: org.openecomp.resource.abstract.nodes.heat.FEAdd_On_Module_QRouterTemplate - directives: - - substitutable - properties: - vf_module_id: - get_input: vf_module_id - qrouter_cluster_name: - get_input: qrouter_cluster_name - oam_private_net_name: - get_input: oam_private_net_name - qrouter_flavor_name: - get_input: qrouter_flavor_name - version_number: - get_input: version_number - vf_module_name: - get_input: vf_module_name - service_template_filter: - substitute_service_template: FEAdd_On_Module_QRouterTemplateServiceTemplate.yaml - domain_name: - get_input: domain_name - ntp_timezone: - get_input: ntp_timezone - vnf_id: - get_input: vnf_id - availability_zone_0: - get_input: availability_zone_0 - region_name: - get_input: region_name - manager_name_0: - get_input: manager_name_0 - qrouter_names: - get_input: qrouter_names - tenant_name: - get_input: tenant_name - security_group: security_group - cdr_network: - get_input: cdr_network - qrouter_image_name: - get_input: base_image_name - qrouter_volume_type_1: - get_input: qrouter_volume_type_1 - qrouter_volume_type_2: - get_input: qrouter_volume_type_2 - qrouter_node_count: - get_input: qrouter_node_count - qrouter_volume_name_2: - get_input: qrouter_volume_name_2 - qrouter_volume_name_1: - get_input: qrouter_volume_name_1 - qrouter_volume_name_0: - get_input: qrouter_volume_name_0 - qrouter_volume_type_0: - get_input: qrouter_volume_type_0 - qrouter_volume_size_0: - get_input: qrouter_volume_size_0 - qrouter_volume_size_1: - get_input: qrouter_volume_size_1 - manager_oam_direct_ip_0: - get_input: manager_oam_direct_ip_0 - qrouter_volume_size_2: - get_input: qrouter_volume_size_2 - rpmrepository_ip_0: - get_input: rpmrepository_ip_0 - requirements: - - dependency: - capability: tosca.capabilities.Node - node: security_group - relationship: tosca.relationships.DependsOn - - dependency: - capability: tosca.capabilities.Node - node: packet_mirror_network - relationship: tosca.relationships.DependsOn - - dependency: - capability: tosca.capabilities.Node - node: packet_mirror_network - relationship: tosca.relationships.DependsOn - - dependency: - capability: tosca.capabilities.Node - node: packet_internal_network - relationship: tosca.relationships.DependsOn - - dependency: - capability: tosca.capabilities.Node - node: packet_internal_network - relationship: tosca.relationships.DependsOn packet_mirror_network: type: org.openecomp.resource.vl.nodes.heat.network.neutron.Net properties: @@ -915,11 +830,11 @@ topology_template: requirements: - port: capability: attachment_oam_private_net_network_port - node: QRouter + node: QRouter0 relationship: org.openecomp.relationships.AttachesTo - port: capability: attachment_cdr_network_port - node: QRouter + node: QRouter0 relationship: org.openecomp.relationships.AttachesTo - port: capability: attachment_oam_private_net_network_port @@ -957,6 +872,91 @@ topology_template: capability: attachment_packet_internal_network_port node: vProbe relationship: org.openecomp.relationships.AttachesTo + QRouter0: + type: org.openecomp.resource.abstract.nodes.heat.FEAdd_On_Module_QRouterTemplate + directives: + - substitutable + properties: + vf_module_id: + get_input: vf_module_id + qrouter_cluster_name: + get_input: qrouter_cluster_name + oam_private_net_name: + get_input: oam_private_net_name + qrouter_flavor_name: + get_input: qrouter_flavor_name + version_number: + get_input: version_number + vf_module_name: + get_input: vf_module_name + service_template_filter: + substitute_service_template: FEAdd_On_Module_QRouterTemplateServiceTemplate.yaml + domain_name: + get_input: domain_name + ntp_timezone: + get_input: ntp_timezone + vnf_id: + get_input: vnf_id + availability_zone_0: + get_input: availability_zone_0 + region_name: + get_input: region_name + manager_name_0: + get_input: manager_name_0 + qrouter_names: + get_input: qrouter_names + tenant_name: + get_input: tenant_name + security_group: security_group + cdr_network: + get_input: cdr_network + qrouter_image_name: + get_input: base_image_name + qrouter_volume_type_1: + get_input: qrouter_volume_type_1 + qrouter_volume_type_2: + get_input: qrouter_volume_type_2 + qrouter_node_count: + get_input: qrouter_node_count + qrouter_volume_name_2: + get_input: qrouter_volume_name_2 + qrouter_volume_name_1: + get_input: qrouter_volume_name_1 + qrouter_volume_name_0: + get_input: qrouter_volume_name_0 + qrouter_volume_type_0: + get_input: qrouter_volume_type_0 + qrouter_volume_size_0: + get_input: qrouter_volume_size_0 + qrouter_volume_size_1: + get_input: qrouter_volume_size_1 + manager_oam_direct_ip_0: + get_input: manager_oam_direct_ip_0 + qrouter_volume_size_2: + get_input: qrouter_volume_size_2 + rpmrepository_ip_0: + get_input: rpmrepository_ip_0 + requirements: + - dependency: + capability: tosca.capabilities.Node + node: security_group + relationship: tosca.relationships.DependsOn + - dependency: + capability: tosca.capabilities.Node + node: packet_mirror_network + relationship: tosca.relationships.DependsOn + - dependency: + capability: tosca.capabilities.Node + node: packet_mirror_network + relationship: tosca.relationships.DependsOn + - dependency: + capability: tosca.capabilities.Node + node: packet_internal_network + relationship: tosca.relationships.DependsOn + - dependency: + capability: tosca.capabilities.Node + node: packet_internal_network + relationship: tosca.relationships.DependsOn vLB: type: org.openecomp.resource.abstract.nodes.heat.FEAdd_On_Module_vLBTemplate directives: @@ -1062,8 +1062,8 @@ topology_template: members: - vLBAgent - vProbe - - QRouter - packet_mirror_network - packet_internal_network - security_group + - QRouter0 - vLB \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoOutParamDuplicatePortType/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoOutParamDuplicatePortType/out/GlobalSubstitutionTypesServiceTemplate.yaml index 9159c8b742..13cccd38b7 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoOutParamDuplicatePortType/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoOutParamDuplicatePortType/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -14,12 +14,166 @@ node_types: status: SUPPORTED entry_schema: type: string + port_FSB_OAM_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string compute_FSB1_metadata: type: list required: true status: SUPPORTED entry_schema: type: json + port_FSB2_Internal2_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_FSB_OAM_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal2_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal2_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal1_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_mac_address: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal2_mac_address: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal2_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal2_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_FSB1_availability_zone: type: list required: true @@ -40,47 +194,85 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 + port_FSB_OAM_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer port_FSB2_Internal2_network: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_FSB2_Internal2_vlan_requirements: + type: list required: true status: SUPPORTED - port_FSB2_Internal1_mac_address: + entry_schema: + type: json + port_FSB2_Internal1_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB2_Internal2_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string + port_FSB1_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB2_Internal1_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal1_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_FSB_OAM_fixed_ips: type: list required: true status: SUPPORTED entry_schema: type: json - compute_FSB1_name: + port_FSB2_Internal2_order: type: list required: true status: SUPPORTED entry_schema: - type: string - port_FSB_OAM_network: + type: integer + port_FSB2_Internal1_subnetpoolid: type: list required: true status: SUPPORTED entry_schema: type: string - port_FSB2_Internal1_network: + port_FSB1_Internal_mac_requirements: type: list required: true status: SUPPORTED entry_schema: - type: string - port_FSB2_Internal2_mac_address: + type: json + port_FSB_OAM_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + compute_FSB1_name: type: list required: true status: SUPPORTED @@ -655,4 +847,4 @@ node_types: description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - - UNBOUNDED + - UNBOUNDED \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoOutParamDuplicatePortType/out/SubstitutionServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoOutParamDuplicatePortType/out/SubstitutionServiceTemplate.yaml index 3fd981df0e..ac5e7b1360 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoOutParamDuplicatePortType/out/SubstitutionServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoOutParamDuplicatePortType/out/SubstitutionServiceTemplate.yaml @@ -16,11 +16,139 @@ topology_template: required: true entry_schema: type: string + port_FSB_OAM_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string compute_FSB1_metadata: type: list required: true entry_schema: type: json + port_FSB2_Internal2_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_exCP_naming: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_FSB_OAM_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal2_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal2_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal1_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_mac_address: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_network: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal2_mac_address: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal2_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal2_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_mac_requirements: + type: list + required: true + entry_schema: + type: json compute_FSB1_availability_zone: type: list required: true @@ -38,40 +166,72 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_FSB_OAM_order: + type: list + required: true + entry_schema: + type: integer port_FSB2_Internal2_network: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_FSB2_Internal2_vlan_requirements: + type: list required: true - port_FSB2_Internal1_mac_address: + entry_schema: + type: json + port_FSB2_Internal1_order: + type: list + required: true + entry_schema: + type: integer + port_FSB2_Internal2_subnetpoolid: type: list required: true entry_schema: type: string + port_FSB1_Internal_order: + type: list + required: true + entry_schema: + type: integer + port_FSB2_Internal1_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal1_mac_requirements: + type: list + required: true + entry_schema: + type: json port_FSB_OAM_fixed_ips: type: list required: true entry_schema: type: json - compute_FSB1_name: + port_FSB2_Internal2_order: type: list required: true entry_schema: - type: string - port_FSB_OAM_network: + type: integer + port_FSB2_Internal1_subnetpoolid: type: list required: true entry_schema: type: string - port_FSB2_Internal1_network: + port_FSB1_Internal_mac_requirements: type: list required: true entry_schema: - type: string - port_FSB2_Internal2_mac_address: + type: json + port_FSB_OAM_exCP_naming: + type: list + required: true + entry_schema: + type: json + compute_FSB1_name: type: list required: true entry_schema: @@ -80,6 +240,38 @@ topology_template: FSB1_FSB1_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB1_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB1_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB1_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB1_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB1_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB1_Internal_order + - index_value + network_role: + get_input: + - port_FSB1_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB1_Internal_subnetpoolid + - index_value network: get_input: - port_FSB1_Internal_network @@ -96,6 +288,38 @@ topology_template: FSB1_FSB_OAM: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB_OAM_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB_OAM_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB_OAM_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB_OAM_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB_OAM_mac_requirements + - index_value + order: + get_input: + - port_FSB_OAM_order + - index_value + network_role: + get_input: + - port_FSB_OAM_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB_OAM_subnetpoolid + - index_value fixed_ips: get_input: - port_FSB_OAM_fixed_ips @@ -112,6 +336,38 @@ topology_template: FSB1_FSB2_Internal2: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB2_Internal2_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB2_Internal2_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB2_Internal2_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB2_Internal2_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB2_Internal2_mac_requirements + - index_value + order: + get_input: + - port_FSB2_Internal2_order + - index_value + network_role: + get_input: + - port_FSB2_Internal2_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB2_Internal2_subnetpoolid + - index_value network: get_input: - port_FSB2_Internal2_network @@ -152,6 +408,38 @@ topology_template: FSB1_FSB2_Internal1: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB2_Internal1_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB2_Internal1_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB2_Internal1_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB2_Internal1_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB2_Internal1_mac_requirements + - index_value + order: + get_input: + - port_FSB2_Internal1_order + - index_value + network_role: + get_input: + - port_FSB2_Internal1_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB2_Internal1_subnetpoolid + - index_value network: get_input: - port_FSB2_Internal1_network diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoPorts/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoPorts/out/GlobalSubstitutionTypesServiceTemplate.yaml index 916359eb88..78f448ce6f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoPorts/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoPorts/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -295,4 +295,4 @@ node_types: description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - - UNBOUNDED + - UNBOUNDED \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoPorts/out/SubstitutionServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoPorts/out/SubstitutionServiceTemplate.yaml index 7c322d53fd..96a3a66c4e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoPorts/out/SubstitutionServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/NoPorts/out/SubstitutionServiceTemplate.yaml @@ -193,4 +193,4 @@ topology_template: - dependency local_storage_FSB1: - FSB1 - - local_storage + - local_storage \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithIndex/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithIndex/out/GlobalSubstitutionTypesServiceTemplate.yaml index d570a37afb..dda1f4295d 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithIndex/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithIndex/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -14,13 +14,119 @@ node_types: status: SUPPORTED entry_schema: type: string + port_FSB_OAM_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string compute_FSB1_metadata: type: list required: true status: SUPPORTED entry_schema: type: json - port_FSB_OAM_fixed_ips: + port_FSB2_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB2_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_FSB_OAM_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_mac_requirements: type: list required: true status: SUPPORTED @@ -46,29 +152,67 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_FSB2_Internal_network: + port_FSB_OAM_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB2_Internal_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_mac_address: type: list required: true status: SUPPORTED entry_schema: type: string - compute_FSB1_name: + port_FSB2_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB_OAM_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_network: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_FSB1_Internal_mac_requirements: + type: list required: true status: SUPPORTED - port_FSB2_Internal_mac_address: + entry_schema: + type: json + port_FSB_OAM_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + compute_FSB1_name: type: list required: true status: SUPPORTED entry_schema: type: string - port_FSB_OAM_network: + port_FSB2_Internal_network_role_tag: type: list required: true status: SUPPORTED @@ -565,4 +709,4 @@ node_types: description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - - UNBOUNDED + - UNBOUNDED \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithIndex/out/SubstitutionServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithIndex/out/SubstitutionServiceTemplate.yaml index 58ea943973..76dbaad388 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithIndex/out/SubstitutionServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithIndex/out/SubstitutionServiceTemplate.yaml @@ -16,12 +16,100 @@ topology_template: required: true entry_schema: type: string + port_FSB_OAM_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string compute_FSB1_metadata: type: list required: true entry_schema: type: json - port_FSB_OAM_fixed_ips: + port_FSB2_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + entry_schema: + type: integer + port_FSB2_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_FSB_OAM_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_mac_requirements: type: list required: true entry_schema: @@ -43,25 +131,57 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_FSB2_Internal_network: + port_FSB_OAM_order: + type: list + required: true + entry_schema: + type: integer + port_FSB2_Internal_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_mac_address: type: list required: true entry_schema: type: string - compute_FSB1_name: + port_FSB2_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_order: + type: list + required: true + entry_schema: + type: integer + port_FSB_OAM_fixed_ips: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_network: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_FSB1_Internal_mac_requirements: + type: list required: true - port_FSB2_Internal_mac_address: + entry_schema: + type: json + port_FSB_OAM_exCP_naming: + type: list + required: true + entry_schema: + type: json + compute_FSB1_name: type: list required: true entry_schema: type: string - port_FSB_OAM_network: + port_FSB2_Internal_network_role_tag: type: list required: true entry_schema: @@ -70,6 +190,38 @@ topology_template: FSB1_FSB1_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB1_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB1_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB1_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB1_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB1_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB1_Internal_order + - index_value + network_role: + get_input: + - port_FSB1_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB1_Internal_subnetpoolid + - index_value network: get_input: - port_FSB1_Internal_network @@ -86,6 +238,38 @@ topology_template: FSB1_FSB2_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB2_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB2_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB2_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB2_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB2_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB2_Internal_order + - index_value + network_role: + get_input: + - port_FSB2_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB2_Internal_subnetpoolid + - index_value network: get_input: - port_FSB2_Internal_network @@ -102,6 +286,38 @@ topology_template: FSB1_FSB_OAM: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB_OAM_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB_OAM_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB_OAM_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB_OAM_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB_OAM_mac_requirements + - index_value + order: + get_input: + - port_FSB_OAM_order + - index_value + network_role: + get_input: + - port_FSB_OAM_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB_OAM_subnetpoolid + - index_value fixed_ips: get_input: - port_FSB_OAM_fixed_ips @@ -388,4 +604,4 @@ topology_template: - link dependency_FSB1_FSB2_Internal: - FSB1_FSB2_Internal - - dependency + - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/consolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/consolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml index 6183e8703e..e2581559d2 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/consolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/consolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -14,12 +14,82 @@ node_types: status: SUPPORTED entry_schema: type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string compute_FSB1_metadata: type: list required: true status: SUPPORTED entry_schema: type: json + port_FSB2_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB2_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_FSB2_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string compute_FSB1_availability_zone: type: list required: true @@ -40,23 +110,49 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_FSB2_Internal_network: + port_FSB2_Internal_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_mac_address: type: list required: true status: SUPPORTED entry_schema: type: string - compute_FSB1_name: + port_FSB2_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB2_Internal_network: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_FSB1_Internal_mac_requirements: + type: list required: true status: SUPPORTED - port_FSB2_Internal_mac_address: + entry_schema: + type: json + compute_FSB1_name: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal_network_role_tag: type: list required: true status: SUPPORTED @@ -516,4 +612,4 @@ node_types: description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - - UNBOUNDED + - UNBOUNDED \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/consolidation/out/SubstitutionServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/consolidation/out/SubstitutionServiceTemplate.yaml index 07c6c2528b..adc80eaf7a 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/consolidation/out/SubstitutionServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/consolidation/out/SubstitutionServiceTemplate.yaml @@ -16,11 +16,69 @@ topology_template: required: true entry_schema: type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string compute_FSB1_metadata: type: list required: true entry_schema: type: json + port_FSB2_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + entry_schema: + type: integer + port_FSB2_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_FSB2_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_network_role: + type: list + required: true + entry_schema: + type: string compute_FSB1_availability_zone: type: list required: true @@ -38,20 +96,42 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_FSB2_Internal_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_mac_address: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_order: + type: list + required: true + entry_schema: + type: integer port_FSB2_Internal_network: type: list required: true entry_schema: type: string + port_FSB1_Internal_mac_requirements: + type: list + required: true + entry_schema: + type: json compute_FSB1_name: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string - required: true - port_FSB2_Internal_mac_address: + port_FSB2_Internal_network_role_tag: type: list required: true entry_schema: @@ -60,6 +140,38 @@ topology_template: FSB1_FSB1_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB1_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB1_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB1_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB1_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB1_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB1_Internal_order + - index_value + network_role: + get_input: + - port_FSB1_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB1_Internal_subnetpoolid + - index_value network: get_input: - port_FSB1_Internal_network @@ -76,6 +188,38 @@ topology_template: FSB1_FSB2_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB2_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB2_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB2_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB2_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB2_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB2_Internal_order + - index_value + network_role: + get_input: + - port_FSB2_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB2_Internal_subnetpoolid + - index_value network: get_input: - port_FSB2_Internal_network @@ -388,4 +532,4 @@ topology_template: - local_storage dependency_FSB1_FSB2_Internal: - FSB1_FSB2_Internal - - dependency + - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/noConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/noConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml index bf0af32231..40048e44db 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/noConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/noConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -14,13 +14,119 @@ node_types: status: SUPPORTED entry_schema: type: string + port_FSB_OAM_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string compute_FSB1_metadata: type: list required: true status: SUPPORTED entry_schema: type: json - port_FSB_OAM_fixed_ips: + port_FSB2_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB2_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_FSB_OAM_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_mac_requirements: type: list required: true status: SUPPORTED @@ -46,29 +152,67 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_FSB2_Internal_network: + port_FSB_OAM_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB2_Internal_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_mac_address: type: list required: true status: SUPPORTED entry_schema: type: string - compute_FSB1_name: + port_FSB2_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB_OAM_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_network: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_FSB1_Internal_mac_requirements: + type: list required: true status: SUPPORTED - port_FSB2_Internal_mac_address: + entry_schema: + type: json + port_FSB_OAM_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + compute_FSB1_name: type: list required: true status: SUPPORTED entry_schema: type: string - port_FSB_OAM_network: + port_FSB2_Internal_network_role_tag: type: list required: true status: SUPPORTED @@ -601,4 +745,4 @@ node_types: description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - - UNBOUNDED + - UNBOUNDED \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/noConsolidation/out/SubstitutionServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/noConsolidation/out/SubstitutionServiceTemplate.yaml index b20af41093..4faca73a16 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/noConsolidation/out/SubstitutionServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/WithOutputParameters/noConsolidation/out/SubstitutionServiceTemplate.yaml @@ -16,12 +16,100 @@ topology_template: required: true entry_schema: type: string + port_FSB_OAM_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string compute_FSB1_metadata: type: list required: true entry_schema: type: json - port_FSB_OAM_fixed_ips: + port_FSB2_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + entry_schema: + type: integer + port_FSB2_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_FSB_OAM_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_mac_requirements: type: list required: true entry_schema: @@ -43,25 +131,57 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_FSB2_Internal_network: + port_FSB_OAM_order: + type: list + required: true + entry_schema: + type: integer + port_FSB2_Internal_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_mac_address: type: list required: true entry_schema: type: string - compute_FSB1_name: + port_FSB2_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_order: + type: list + required: true + entry_schema: + type: integer + port_FSB_OAM_fixed_ips: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_network: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_FSB1_Internal_mac_requirements: + type: list required: true - port_FSB2_Internal_mac_address: + entry_schema: + type: json + port_FSB_OAM_exCP_naming: + type: list + required: true + entry_schema: + type: json + compute_FSB1_name: type: list required: true entry_schema: type: string - port_FSB_OAM_network: + port_FSB2_Internal_network_role_tag: type: list required: true entry_schema: @@ -70,6 +190,38 @@ topology_template: FSB1_FSB1_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB1_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB1_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB1_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB1_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB1_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB1_Internal_order + - index_value + network_role: + get_input: + - port_FSB1_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB1_Internal_subnetpoolid + - index_value network: get_input: - port_FSB1_Internal_network @@ -86,6 +238,38 @@ topology_template: FSB1_FSB2_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB2_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB2_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB2_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB2_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB2_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB2_Internal_order + - index_value + network_role: + get_input: + - port_FSB2_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB2_Internal_subnetpoolid + - index_value network: get_input: - port_FSB2_Internal_network @@ -102,6 +286,38 @@ topology_template: FSB1_FSB_OAM: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB_OAM_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB_OAM_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB_OAM_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB_OAM_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB_OAM_mac_requirements + - index_value + order: + get_input: + - port_FSB_OAM_order + - index_value + network_role: + get_input: + - port_FSB_OAM_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB_OAM_subnetpoolid + - index_value fixed_ips: get_input: - port_FSB_OAM_fixed_ips @@ -445,4 +661,4 @@ topology_template: - link dependency_FSB1_FSB2_Internal: - FSB1_FSB2_Internal - - dependency + - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/consolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/consolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml index 6772f8c594..84bab83d19 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/consolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/consolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -14,12 +14,36 @@ node_types: status: SUPPORTED entry_schema: type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string compute_FSB1_metadata: type: list required: true status: SUPPORTED entry_schema: type: json + port_FSB2_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer compute_FSB1_availability_zone: type: list required: true @@ -34,23 +58,95 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 + port_FSB2_Internal_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_FSB2_Internal_mac_address: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB1_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json port_FSB2_Internal_network: type: list required: true status: SUPPORTED entry_schema: type: string + port_FSB2_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json compute_FSB1_name: type: list required: true status: SUPPORTED entry_schema: type: string - vm_flavor_name: - type: string + port_FSB1_Internal_exCP_naming: + type: list required: true status: SUPPORTED - port_FSB2_Internal_mac_address: + entry_schema: + type: json + port_FSB1_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal_network_role_tag: type: list required: true status: SUPPORTED @@ -510,4 +606,4 @@ node_types: description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - - UNBOUNDED + - UNBOUNDED \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/consolidation/out/SubstitutionServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/consolidation/out/SubstitutionServiceTemplate.yaml index 4c5d4ae924..cb7a4127a1 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/consolidation/out/SubstitutionServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/consolidation/out/SubstitutionServiceTemplate.yaml @@ -16,11 +16,31 @@ topology_template: required: true entry_schema: type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string compute_FSB1_metadata: type: list required: true entry_schema: type: json + port_FSB2_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + entry_schema: + type: integer compute_FSB1_availability_zone: type: list required: true @@ -33,20 +53,80 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 + port_FSB2_Internal_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_FSB2_Internal_mac_address: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_order: + type: list + required: true + entry_schema: + type: integer + port_FSB1_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json port_FSB2_Internal_network: type: list required: true entry_schema: type: string + port_FSB2_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_mac_requirements: + type: list + required: true + entry_schema: + type: json compute_FSB1_name: type: list required: true entry_schema: type: string - vm_flavor_name: - type: string + port_FSB1_Internal_exCP_naming: + type: list required: true - port_FSB2_Internal_mac_address: + entry_schema: + type: json + port_FSB1_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal_network_role_tag: type: list required: true entry_schema: @@ -55,6 +135,38 @@ topology_template: FSB1_FSB1_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB1_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB1_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB1_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB1_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB1_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB1_Internal_order + - index_value + network_role: + get_input: + - port_FSB1_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB1_Internal_subnetpoolid + - index_value network: get_attribute: - FSB1_FSB2_Internal @@ -71,6 +183,38 @@ topology_template: FSB1_FSB2_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB2_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB2_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB2_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB2_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB2_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB2_Internal_order + - index_value + network_role: + get_input: + - port_FSB2_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB2_Internal_subnetpoolid + - index_value device_id: get_attribute: - FSB1 @@ -387,4 +531,4 @@ topology_template: - local_storage dependency_FSB1_FSB2_Internal: - FSB1_FSB2_Internal - - dependency + - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/noConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/noConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml index f1d1182772..b9a448541a 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/noConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/noConsolidation/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -8,7 +8,113 @@ node_types: org.openecomp.resource.abstract.nodes.FSB1: derived_from: org.openecomp.resource.abstract.nodes.VFC properties: - port_FSB_OAM_fixed_ips: + port_FSB_OAM_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB2_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB2_Internal_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + status: SUPPORTED + port_FSB_OAM_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_vlan_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_network_role: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB_OAM_mac_requirements: type: list required: true status: SUPPORTED @@ -28,23 +134,61 @@ node_types: status: SUPPORTED constraints: - greater_or_equal: 0 - port_FSB2_Internal_network: + port_FSB_OAM_order: type: list required: true status: SUPPORTED entry_schema: - type: string - vm_flavor_name: - type: string + type: integer + port_FSB2_Internal_mac_requirements: + type: list required: true status: SUPPORTED + entry_schema: + type: json port_FSB2_Internal_mac_address: type: list required: true status: SUPPORTED entry_schema: type: string - port_FSB_OAM_network: + port_FSB2_Internal_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB1_Internal_order: + type: list + required: true + status: SUPPORTED + entry_schema: + type: integer + port_FSB_OAM_fixed_ips: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_network: + type: list + required: true + status: SUPPORTED + entry_schema: + type: string + port_FSB1_Internal_mac_requirements: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB_OAM_exCP_naming: + type: list + required: true + status: SUPPORTED + entry_schema: + type: json + port_FSB2_Internal_network_role_tag: type: list required: true status: SUPPORTED @@ -577,4 +721,4 @@ node_types: description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - - UNBOUNDED + - UNBOUNDED \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/noConsolidation/out/SubstitutionServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/noConsolidation/out/SubstitutionServiceTemplate.yaml index 3ef8780d7e..6cd3625e82 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/noConsolidation/out/SubstitutionServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/creSubstitutionServiceTemplate/updNodesGetAttrInFromInnerNodes/noConsolidation/out/SubstitutionServiceTemplate.yaml @@ -11,7 +11,95 @@ node_types: derived_from: org.openecomp.resource.vfc.nodes.heat.nova.Server topology_template: inputs: - port_FSB_OAM_fixed_ips: + port_FSB_OAM_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB2_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_order: + type: list + required: true + entry_schema: + type: integer + port_FSB2_Internal_ip_requirements: + type: list + required: true + entry_schema: + type: json + vm_flavor_name: + type: string + required: true + port_FSB_OAM_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_ip_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_network_role_tag: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_vlan_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_network: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_network_role: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_subnetpoolid: + type: list + required: true + entry_schema: + type: string + port_FSB_OAM_mac_requirements: type: list required: true entry_schema: @@ -28,20 +116,52 @@ topology_template: default: 0 constraints: - greater_or_equal: 0 - port_FSB2_Internal_network: + port_FSB_OAM_order: type: list required: true entry_schema: - type: string - vm_flavor_name: - type: string + type: integer + port_FSB2_Internal_mac_requirements: + type: list required: true + entry_schema: + type: json port_FSB2_Internal_mac_address: type: list required: true entry_schema: type: string - port_FSB_OAM_network: + port_FSB2_Internal_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB1_Internal_order: + type: list + required: true + entry_schema: + type: integer + port_FSB_OAM_fixed_ips: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_network: + type: list + required: true + entry_schema: + type: string + port_FSB1_Internal_mac_requirements: + type: list + required: true + entry_schema: + type: json + port_FSB_OAM_exCP_naming: + type: list + required: true + entry_schema: + type: json + port_FSB2_Internal_network_role_tag: type: list required: true entry_schema: @@ -50,6 +170,38 @@ topology_template: FSB1_FSB1_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB1_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB1_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB1_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB1_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB1_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB1_Internal_order + - index_value + network_role: + get_input: + - port_FSB1_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB1_Internal_subnetpoolid + - index_value network: get_input: - port_FSB1_Internal_network @@ -66,6 +218,38 @@ topology_template: FSB1_FSB2_Internal: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB2_Internal_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB2_Internal_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB2_Internal_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB2_Internal_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB2_Internal_mac_requirements + - index_value + order: + get_input: + - port_FSB2_Internal_order + - index_value + network_role: + get_input: + - port_FSB2_Internal_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB2_Internal_subnetpoolid + - index_value network: get_input: - port_FSB2_Internal_network @@ -82,6 +266,38 @@ topology_template: FSB1_FSB_OAM: type: org.openecomp.resource.cp.nodes.heat.network.neutron.Port properties: + exCP_naming: + get_input: + - port_FSB_OAM_exCP_naming + - index_value + vlan_requirements: + get_input: + - port_FSB_OAM_vlan_requirements + - index_value + ip_requirements: + get_input: + - port_FSB_OAM_ip_requirements + - index_value + network_role_tag: + get_input: + - port_FSB_OAM_network_role_tag + - index_value + mac_requirements: + get_input: + - port_FSB_OAM_mac_requirements + - index_value + order: + get_input: + - port_FSB_OAM_order + - index_value + network_role: + get_input: + - port_FSB_OAM_network_role + - index_value + subnetpoolid: + get_input: + - port_FSB_OAM_subnetpoolid + - index_value fixed_ips: get_input: - port_FSB_OAM_fixed_ips @@ -420,4 +636,4 @@ topology_template: - link dependency_FSB1_FSB2_Internal: - FSB1_FSB2_Internal - - dependency + - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/oneComputeMultiplePortsDiffType/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/oneComputeMultiplePortsDiffType/out/MainServiceTemplate.yaml index b441d659c0..ac134c31c5 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/oneComputeMultiplePortsDiffType/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/oneComputeMultiplePortsDiffType/out/MainServiceTemplate.yaml @@ -181,16 +181,18 @@ topology_template: properties: port_FSB1_Internal_mac_address: - get_input: fsb1-Internal1-mac - port_FSB1_Internal_network: - - Internal1-net vm_flavor_name: get_input: fsb-flavor - port_FSB2_Internal_mac_address: - - get_input: fsb1-Internal2-mac vm_image_name: get_input: fsb-image compute_FSB_admin_pass: - STATIC-DATA-FSB1 + port_FSB_OAM_network: + - jsa_net1 + port_FSB1_Internal_network: + - Internal1-net + port_FSB2_Internal_mac_address: + - get_input: fsb1-Internal2-mac port_FSB_OAM_fixed_ips: - - ip_address: get_input: fsb1-oam-ip @@ -202,8 +204,6 @@ topology_template: - path: /path2/etc/sysconfig/network-scripts/ifcfg-eth1 compute_FSB_availability_zone: - get_input: fsb1_zone - port_FSB_OAM_network: - - jsa_net1 compute_FSB_name: - get_input: fsb1-name service_template_filter: @@ -225,4 +225,4 @@ topology_template: - FSB2_Internal2 - FSB1_Internal1 - FSB1_OAM - - FSB1_template + - FSB1_template \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/oneComputeMultiplePortsSameType/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/oneComputeMultiplePortsSameType/out/MainServiceTemplate.yaml index e2adb3038b..8bb81bc2fa 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/oneComputeMultiplePortsSameType/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/oneComputeMultiplePortsSameType/out/MainServiceTemplate.yaml @@ -162,22 +162,22 @@ topology_template: - get_input: fsb1-Internal1-mac port_FSB1_Internal2_network: - Internal2-net + port_FSB1_Internal1_network: + - Internal1-net + vm_flavor_name: + get_input: fsb-flavor + port_FSB1_Internal2_mac_address: + - get_input: fsb1-Internal2-mac vm_image_name: get_input: fsb-image compute_FSB_admin_pass: - STATIC-DATA-FSB1 - port_FSB1_Internal1_network: - - Internal1-net compute_FSB_metadata: - write_files: - path: /path1/etc/sysconfig/network-scripts/ifcfg-eth0 - path: /path2/etc/sysconfig/network-scripts/ifcfg-eth1 compute_FSB_availability_zone: - get_input: fsb1_zone - vm_flavor_name: - get_input: fsb-flavor - port_FSB1_Internal2_mac_address: - - get_input: fsb1-Internal2-mac compute_FSB_name: - get_input: fsb1-name service_template_filter: @@ -198,4 +198,4 @@ topology_template: members: - FSB1_Internal2 - FSB1_Internal1 - - FSB1_template + - FSB1_template \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/twoComputesMultiplePorts/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/twoComputesMultiplePorts/out/MainServiceTemplate.yaml index ce35a8ed2a..92fc5bdb6e 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/twoComputesMultiplePorts/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/createAbstractSubstitute/twoComputesMultiplePorts/out/MainServiceTemplate.yaml @@ -243,6 +243,11 @@ topology_template: port_FSB1_Internal_mac_address: - get_input: fsb1-Internal1-mac - get_input: fsb1-Internal2-mac + compute_FSB_user_data: + - OPTIONAL-DATA-FSB1 + - null + vm_flavor_name: + get_input: fsb-flavor vm_image_name: get_input: fsb-image compute_FSB_admin_pass: @@ -251,6 +256,9 @@ topology_template: port_FSB1_Internal_network: - Internal1-net-fsb1-Internal1 - Internal1-net-fsb1-Internal2 + port_FSB2_Internal_mac_address: + - get_input: fsb2-Internal1-mac + - get_input: fsb2-Internal2-mac port_FSB2_Internal_network: - Internal2-net-fsb2-Internal1 - Internal2-net-fsb2-Internal2 @@ -261,17 +269,9 @@ topology_template: - write_files: - path: /path3/etc/sysconfig/network-scripts/ifcfg-eth0 - path: /path4/etc/sysconfig/network-scripts/ifcfg-eth1 - compute_FSB_user_data: - - OPTIONAL-DATA-FSB1 - - null compute_FSB_availability_zone: - get_input: fsb1_zone - get_input: fsb2_zone - vm_flavor_name: - get_input: fsb-flavor - port_FSB2_Internal_mac_address: - - get_input: fsb2-Internal1-mac - - get_input: fsb2-Internal2-mac compute_FSB_name: - get_input: fsb1-name - get_input: fsb2-name @@ -296,4 +296,4 @@ topology_template: - FSB2_Internal1 - FSB2_Internal2 - FSB1_template - - FSB2_template + - FSB2_template \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/pattern1b/noConsolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/pattern1b/noConsolidation/out/MainServiceTemplate.yaml index 773801f9fa..209d729be8 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/pattern1b/noConsolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/pattern1b/noConsolidation/out/MainServiceTemplate.yaml @@ -148,12 +148,12 @@ topology_template: - get_input: fsb_zone port_FSB1_Internal_network: - Internal1-net - port_FSB2_Internal_network: - - Internal2-net vm_flavor_name: get_input: fsb1-flavor port_FSB2_Internal_mac_address: - get_input: fsb1-Internal2-mac + port_FSB2_Internal_network: + - Internal2-net service_template_filter: substitute_service_template: Nested_FSB1_0ServiceTemplate.yaml count: 1 @@ -291,4 +291,4 @@ topology_template: - abstract_FSB1_0 - FSB1_FSB1_Internal_accessIPv6 - 0 - - OS-EXT-IPS-MAC:mac_addr + - OS-EXT-IPS-MAC:mac_addr \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updGroupsConnectivity/consolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updGroupsConnectivity/consolidation/out/MainServiceTemplate.yaml index f8872c5a9d..492e64573c 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updGroupsConnectivity/consolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updGroupsConnectivity/consolidation/out/MainServiceTemplate.yaml @@ -240,6 +240,11 @@ topology_template: port_FSB1_Internal_mac_address: - get_input: fsb1-Internal1-mac - get_input: fsb1-Internal2-mac + compute_FSB_user_data: + - STATIC-DATA-FSB1 + - STATIC-DATA-FSB2 + vm_flavor_name: + get_input: fsb-flavor vm_image_name: get_input: fsb-image compute_FSB_admin_pass: @@ -248,6 +253,9 @@ topology_template: port_FSB1_Internal_network: - Internal1-net-fsb1-Internal1 - Internal1-net-fsb1-Internal2 + port_FSB2_Internal_mac_address: + - get_input: fsb2-Internal1-mac + - get_input: fsb2-Internal2-mac port_FSB2_Internal_network: - Internal2-net-fsb2-Internal1 - Internal2-net-fsb2-Internal2 @@ -258,17 +266,9 @@ topology_template: - write_files: - path: /path3/etc/sysconfig/network-scripts/ifcfg-eth0 - path: /path4/etc/sysconfig/network-scripts/ifcfg-eth1 - compute_FSB_user_data: - - STATIC-DATA-FSB1 - - STATIC-DATA-FSB2 compute_FSB_availability_zone: - get_input: fsb1_zone - get_input: fsb2_zone - vm_flavor_name: - get_input: fsb-flavor - port_FSB2_Internal_mac_address: - - get_input: fsb2-Internal1-mac - - get_input: fsb2-Internal2-mac compute_FSB_name: - get_input: fsb1-name - get_input: fsb2-name @@ -317,4 +317,4 @@ topology_template: - FSB2_template - jsa_net - jsa_net1 - - packet_mirror_network_name + - packet_mirror_network_name \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updGroupsConnectivity/noConsolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updGroupsConnectivity/noConsolidation/out/MainServiceTemplate.yaml index af3ef63b0f..ce8bde09d3 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updGroupsConnectivity/noConsolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updGroupsConnectivity/noConsolidation/out/MainServiceTemplate.yaml @@ -98,30 +98,30 @@ topology_template: directives: - substitutable properties: - port_port2_network: - - get_input: port_name + compute_smp_availability_zone: + - get_input: availability_zone_0 + vm_flavor_name: + get_input: flavor_smp_name + compute_smp_user_data_format: + - RAW vm_image_name: get_input: image_smp_name port_port2_replacement_policy: - AUTO compute_smp_name: - get_input: smp_name_1 - compute_smp_availability_zone: - - get_input: availability_zone_0 port_port1_replacement_policy: - AUTO port_port1_network: - get_input: port_name - vm_flavor_name: - get_input: flavor_smp_name + port_port2_network: + - get_input: port_name compute_smp_metadata: - jx_vm_role: smp2 vnf_id: get_input: vnf_id jx_lab_name: get_input: lab_name - compute_smp_user_data_format: - - RAW compute_smp_scheduler_hints: - group: BE_Affinity_group service_template_filter: @@ -164,4 +164,4 @@ topology_template: name: abc affinity: host targets: - - FE_SMP_Affinity_group + - FE_SMP_Affinity_group \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedIn/consolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedIn/consolidation/out/MainServiceTemplate.yaml index b98c6e07bb..b7bb7cbb43 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedIn/consolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedIn/consolidation/out/MainServiceTemplate.yaml @@ -253,6 +253,11 @@ topology_template: port_FSB1_Internal_mac_address: - get_input: fsb1-Internal1-mac - get_input: fsb1-Internal2-mac + compute_FSB_user_data: + - OPTIONAL-DATA-FSB1 + - null + vm_flavor_name: + get_input: fsb-flavor vm_image_name: get_input: fsb-image compute_FSB_admin_pass: @@ -261,6 +266,9 @@ topology_template: port_FSB1_Internal_network: - Internal1-net-fsb1-Internal1 - Internal1-net-fsb1-Internal2 + port_FSB2_Internal_mac_address: + - get_input: fsb2-Internal1-mac + - get_input: fsb2-Internal2-mac port_FSB2_Internal_network: - Internal2-net-fsb2-Internal1 - Internal2-net-fsb2-Internal2 @@ -271,17 +279,9 @@ topology_template: - write_files: - path: /path3/etc/sysconfig/network-scripts/ifcfg-eth0 - path: /path4/etc/sysconfig/network-scripts/ifcfg-eth1 - compute_FSB_user_data: - - OPTIONAL-DATA-FSB1 - - null compute_FSB_availability_zone: - get_input: fsb1_zone - get_input: fsb2_zone - vm_flavor_name: - get_input: fsb-flavor - port_FSB2_Internal_mac_address: - - get_input: fsb2-Internal1-mac - - get_input: fsb2-Internal2-mac compute_FSB_name: - get_input: fsb1-name - get_input: fsb2-name @@ -319,4 +319,4 @@ topology_template: - jsa_net - jsa_net1 - packet_mirror_network - - jsa_security_group + - jsa_security_group \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedIn/noConsolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedIn/noConsolidation/out/MainServiceTemplate.yaml index 6ebaa53c6a..44452b959f 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedIn/noConsolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedIn/noConsolidation/out/MainServiceTemplate.yaml @@ -99,14 +99,14 @@ topology_template: properties: compute_QRouter_availability_zone: - Availability-test - port_oam_private_net_network_port_network: - - get_input: oam_private_net_name - vm_image_name: Image-test compute_QRouter_config_drive: - true port_cdr_network_port_network: - get_input: cdr_network vm_flavor_name: FLAVOR-test + port_oam_private_net_network_port_network: + - get_input: oam_private_net_name + vm_image_name: Image-test compute_QRouter_name: - QRouter-name service_template_filter: @@ -127,4 +127,4 @@ topology_template: - packet_mirror_network - packet_internal_network - cdr_network_port - - oam_private_net_network_port + - oam_private_net_network_port \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedOut/consolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedOut/consolidation/out/MainServiceTemplate.yaml index f554f0a844..5cd7faa646 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedOut/consolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedOut/consolidation/out/MainServiceTemplate.yaml @@ -240,6 +240,11 @@ topology_template: port_FSB1_Internal_mac_address: - get_input: fsb1-Internal1-mac - get_input: fsb1-Internal2-mac + compute_FSB_user_data: + - OPTIONAL-DATA-FSB1 + - null + vm_flavor_name: + get_input: fsb-flavor vm_image_name: get_input: fsb-image compute_FSB_admin_pass: @@ -248,6 +253,9 @@ topology_template: port_FSB1_Internal_network: - Internal1-net-fsb1-Internal1 - Internal1-net-fsb1-Internal2 + port_FSB2_Internal_mac_address: + - get_input: fsb2-Internal1-mac + - get_input: fsb2-Internal2-mac port_FSB2_Internal_network: - Internal2-net-fsb2-Internal1 - Internal2-net-fsb2-Internal2 @@ -258,17 +266,9 @@ topology_template: - write_files: - path: /path3/etc/sysconfig/network-scripts/ifcfg-eth0 - path: /path4/etc/sysconfig/network-scripts/ifcfg-eth1 - compute_FSB_user_data: - - OPTIONAL-DATA-FSB1 - - null compute_FSB_availability_zone: - get_input: fsb1_zone - get_input: fsb2_zone - vm_flavor_name: - get_input: fsb-flavor - port_FSB2_Internal_mac_address: - - get_input: fsb2-Internal1-mac - - get_input: fsb2-Internal2-mac compute_FSB_name: - get_input: fsb1-name - get_input: fsb2-name @@ -309,4 +309,4 @@ topology_template: - FSB2_template - jsa_net - jsa_net1 - - packet_mirror_network_name + - packet_mirror_network_name \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedOut/noConsolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedOut/noConsolidation/out/MainServiceTemplate.yaml index 45b3f46412..1779261886 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedOut/noConsolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updNodesConnectedOut/noConsolidation/out/MainServiceTemplate.yaml @@ -175,16 +175,18 @@ topology_template: properties: port_FSB1_Internal_mac_address: - get_input: fsb1-Internal1-mac - port_FSB1_Internal_network: - - Internal1-net vm_flavor_name: get_input: fsb-flavor - port_FSB2_Internal_mac_address: - - get_input: fsb1-Internal2-mac vm_image_name: get_input: fsb-image compute_FSB_admin_pass: - STATIC-DATA-FSB1 + port_FSB_OAM_network: + - jsa_net1 + port_FSB1_Internal_network: + - Internal1-net + port_FSB2_Internal_mac_address: + - get_input: fsb1-Internal2-mac port_FSB_OAM_fixed_ips: - - ip_address: get_input: fsb1-oam-ip @@ -196,8 +198,6 @@ topology_template: - path: /path2/etc/sysconfig/network-scripts/ifcfg-eth1 compute_FSB_availability_zone: - get_input: fsb1_zone - port_FSB_OAM_network: - - jsa_net1 compute_FSB_name: - get_input: fsb1-name service_template_filter: @@ -233,4 +233,4 @@ topology_template: - FSB1_Internal1 - FSB1_OAM - FSB1_template - - packet_mirror_network_name + - packet_mirror_network_name \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updVolumes/consolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updVolumes/consolidation/out/MainServiceTemplate.yaml index 5e53a1d849..e5513bd30a 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updVolumes/consolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updVolumes/consolidation/out/MainServiceTemplate.yaml @@ -280,6 +280,11 @@ topology_template: port_FSB1_Internal_mac_address: - get_input: fsb1-Internal1-mac - get_input: fsb1-Internal2-mac + compute_FSB_user_data: + - OPTIONAL-DATA-FSB1 + - null + vm_flavor_name: + get_input: fsb-flavor vm_image_name: get_input: fsb-image compute_FSB_admin_pass: @@ -288,6 +293,9 @@ topology_template: port_FSB1_Internal_network: - Internal1-net-fsb1-Internal1 - Internal1-net-fsb1-Internal2 + port_FSB2_Internal_mac_address: + - get_input: fsb2-Internal1-mac + - get_input: fsb2-Internal2-mac port_FSB2_Internal_network: - Internal2-net-fsb2-Internal1 - Internal2-net-fsb2-Internal2 @@ -298,17 +306,9 @@ topology_template: - write_files: - path: /path3/etc/sysconfig/network-scripts/ifcfg-eth0 - path: /path4/etc/sysconfig/network-scripts/ifcfg-eth1 - compute_FSB_user_data: - - OPTIONAL-DATA-FSB1 - - null compute_FSB_availability_zone: - get_input: fsb1_zone - get_input: fsb2_zone - vm_flavor_name: - get_input: fsb-flavor - port_FSB2_Internal_mac_address: - - get_input: fsb2-Internal1-mac - - get_input: fsb2-Internal2-mac compute_FSB_name: - get_input: fsb1-name - get_input: fsb2-name @@ -357,4 +357,4 @@ topology_template: - FSB2_template - jsa_net - jsa_net1 - - packet_mirror_network_name + - packet_mirror_network_name \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updVolumes/noConsolidation/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updVolumes/noConsolidation/out/MainServiceTemplate.yaml index 06b43188e5..54d4cfe9ee 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updVolumes/noConsolidation/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/unifiedComposition/updVolumes/noConsolidation/out/MainServiceTemplate.yaml @@ -195,16 +195,18 @@ topology_template: properties: port_FSB1_Internal_mac_address: - get_input: fsb1-Internal1-mac - port_FSB1_Internal_network: - - Internal1-net vm_flavor_name: get_input: fsb-flavor - port_FSB2_Internal_mac_address: - - get_input: fsb1-Internal2-mac vm_image_name: get_input: fsb-image compute_FSB_admin_pass: - STATIC-DATA-FSB1 + port_FSB_OAM_network: + - jsa_net1 + port_FSB1_Internal_network: + - Internal1-net + port_FSB2_Internal_mac_address: + - get_input: fsb1-Internal2-mac port_FSB_OAM_fixed_ips: - - ip_address: get_input: fsb1-oam-ip @@ -216,8 +218,6 @@ topology_template: - path: /path2/etc/sysconfig/network-scripts/ifcfg-eth1 compute_FSB_availability_zone: - get_input: fsb1_zone - port_FSB_OAM_network: - - jsa_net1 compute_FSB_name: - get_input: fsb1-name service_template_filter: @@ -261,4 +261,4 @@ topology_template: - FSB1_Internal1 - FSB1_OAM - FSB1_template - - packet_mirror_network_name + - packet_mirror_network_name \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/inputfiles/main.yml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/inputfiles/main.yml index b97dd4b535..0894686026 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/inputfiles/main.yml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/inputfiles/main.yml @@ -62,7 +62,7 @@ parameters: resources: - server_cmaui: + server_cmaui_1: type: nested.yml properties: cmaui_names: { get_param: [cmaui_names, 0]} diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/inputfiles/nested.yml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/inputfiles/nested.yml index cdaf251b85..d205cee2be 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/inputfiles/nested.yml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/inputfiles/nested.yml @@ -82,9 +82,9 @@ resources: type: OS::Cinder::VolumeAttachment properties: volume_id: {get_param: out_cmaui_volume} - instance_uuid: {get_resource: server_cmaui} + instance_uuid: {get_resource: server_cmaui_2} - server_cmaui: + server_cmaui_2: type: OS::Nova::Server properties: name: { get_param: [cmaui_names, 0]} diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/GlobalSubstitutionTypesServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/GlobalSubstitutionTypesServiceTemplate.yaml index c215d730a6..9ef461e1de 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/GlobalSubstitutionTypesServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/GlobalSubstitutionTypesServiceTemplate.yaml @@ -103,14 +103,14 @@ node_types: type: string status: SUPPORTED requirements: - - dependency_server_cmaui: + - dependency_server_cmaui_2: capability: tosca.capabilities.Node node: tosca.nodes.Root relationship: tosca.relationships.DependsOn occurrences: - 0 - UNBOUNDED - - local_storage_server_cmaui: + - local_storage_server_cmaui_2: capability: tosca.capabilities.Attachment node: tosca.nodes.BlockStorage relationship: tosca.relationships.AttachesTo @@ -138,19 +138,19 @@ node_types: - 1 - 1 capabilities: - cpu.delta_server_cmaui: + disk.write.bytes.rate_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.write.requests.rate_server_cmaui: + disk.device.write.bytes_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.allocation_server_cmaui: + disk.device.usage_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -162,84 +162,69 @@ node_types: occurrences: - 1 - UNBOUNDED - scalable_server_cmaui: - type: tosca.capabilities.Scalable - occurrences: - - 1 - - UNBOUNDED - disk.read.bytes.rate_server_cmaui: + disk.write.bytes_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - cpu_server_cmaui: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + feature_server_cmaui_2: + type: tosca.capabilities.Node occurrences: - 1 - UNBOUNDED - disk.write.bytes.rate_server_cmaui: + disk.device.latency_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.bytes.rate_server_cmaui: + disk.allocation_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - host_server_cmaui: - type: tosca.capabilities.Container - valid_source_types: - - tosca.nodes.SoftwareComponent - occurrences: - - 1 - - UNBOUNDED - cpu_util_server_cmaui: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + feature_cmaui_port_0: + type: tosca.capabilities.Node occurrences: - 1 - UNBOUNDED - feature_cmaui_port_0: - type: tosca.capabilities.Node + binding_server_cmaui_2: + type: tosca.capabilities.network.Bindable occurrences: - 1 - UNBOUNDED - disk.device.latency_server_cmaui: + disk.root.size_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.write.requests_server_cmaui: + disk.device.write.requests.rate_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.read.requests_server_cmaui: + vcpus_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.outgoing.packets.rate_cmaui_port_0: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + scalable_server_cmaui_2: + type: tosca.capabilities.Scalable occurrences: - 1 - UNBOUNDED - disk.device.capacity_server_cmaui: + network.outgoing.packets.rate_cmaui_port_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.usage_server_cmaui: + disk.read.requests_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -250,101 +235,114 @@ node_types: occurrences: - 1 - UNBOUNDED - disk.device.usage_server_cmaui: + network.outgoing.bytes_cmaui_port_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.outgoing.bytes_cmaui_port_0: + disk.write.requests_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.capacity_server_cmaui: + disk.device.iops_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.requests.rate_server_cmaui: + disk.usage_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.requests_server_cmaui: + disk.device.capacity_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - instance_server_cmaui: + disk.device.read.bytes.rate_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.bytes_server_cmaui: + endpoint_server_cmaui_2: + type: tosca.capabilities.Endpoint.Admin + occurrences: + - 1 + - UNBOUNDED + disk.read.bytes_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - memory_server_cmaui: + os_server_cmaui_2: + type: tosca.capabilities.OperatingSystem + occurrences: + - 1 + - UNBOUNDED + disk.device.read.bytes_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.root.size_server_cmaui: + disk.write.requests.rate_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - binding_server_cmaui: - type: tosca.capabilities.network.Bindable + memory_server_cmaui_2: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.read.requests.rate_server_cmaui: + cpu_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.bytes_server_cmaui: + disk.device.allocation_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - os_server_cmaui: - type: tosca.capabilities.OperatingSystem + host_server_cmaui_2: + type: tosca.capabilities.Container + valid_source_types: + - tosca.nodes.SoftwareComponent occurrences: - 1 - UNBOUNDED - disk.device.write.bytes.rate_server_cmaui: + network.incoming.packets_cmaui_port_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.packets_cmaui_port_0: + disk.ephemeral.size_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - memory.resident_server_cmaui: + disk.capacity_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.latency_server_cmaui: + instance_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -357,59 +355,60 @@ node_types: occurrences: - 0 - UNBOUNDED - feature_server_cmaui: + feature_cmaui_volume: type: tosca.capabilities.Node occurrences: - 1 - UNBOUNDED - feature_cmaui_volume: - type: tosca.capabilities.Node + network.incoming.bytes.rate_cmaui_port_0: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - vcpus_server_cmaui: + disk.iops_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.bytes.rate_cmaui_port_0: + disk.device.write.requests_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.write.bytes_server_cmaui: + disk.device.read.requests_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.allocation_server_cmaui: + network.outpoing.packets_cmaui_port_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.write.requests_server_cmaui: + disk.read.bytes.rate_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - memory.usage_server_cmaui: + cpu.delta_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.outpoing.packets_cmaui_port_0: + disk.device.read.requests.rate_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.ephemeral.size_server_cmaui: + memory.resident_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: @@ -421,35 +420,36 @@ node_types: occurrences: - 1 - UNBOUNDED - endpoint_server_cmaui: - type: tosca.capabilities.Endpoint.Admin + disk.latency_server_cmaui_2: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.iops_server_cmaui: + cpu_util_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - disk.device.iops_server_cmaui: - type: org.openecomp.capabilities.metric.Ceilometer - description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. + attachment_cmaui_volume: + type: tosca.capabilities.Attachment occurrences: - 1 - UNBOUNDED - disk.read.bytes_server_cmaui: + network.incoming.bytes_cmaui_port_0: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - attachment_cmaui_volume: - type: tosca.capabilities.Attachment + disk.device.write.bytes.rate_server_cmaui_2: + type: org.openecomp.capabilities.metric.Ceilometer + description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: - 1 - UNBOUNDED - network.incoming.bytes_cmaui_port_0: + memory.usage_server_cmaui_2: type: org.openecomp.capabilities.metric.Ceilometer description: A node type that includes the Metric capability indicates that it can be monitored using ceilometer. occurrences: diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/MainServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/MainServiceTemplate.yaml index d59250444f..b0c76462ac 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/MainServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/MainServiceTemplate.yaml @@ -99,7 +99,7 @@ topology_template: type: string description: the name of the target volume backend node_templates: - server_cmaui: + server_cmaui_1: type: org.openecomp.resource.abstract.nodes.heat.nested directives: - substitutable @@ -123,4 +123,4 @@ topology_template: heat_file: ../Artifacts/main.yml description: cmaui server template for vMMSC members: - - server_cmaui \ No newline at end of file + - server_cmaui_1 \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/nestedServiceTemplate.yaml b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/nestedServiceTemplate.yaml index 7dd65fdfa5..9da203c466 100644 --- a/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/nestedServiceTemplate.yaml +++ b/openecomp-be/lib/openecomp-sdc-translator-lib/openecomp-sdc-translator-core/src/test/resources/mock/services/heattotosca/vol_attach/nested_with_inner_vol/out/nestedServiceTemplate.yaml @@ -114,7 +114,7 @@ topology_template: type: string description: the name of the target volume backend node_templates: - server_cmaui: + server_cmaui_2: type: org.openecomp.resource.vfc.nodes.heat.cmaui properties: flavor: @@ -168,14 +168,14 @@ topology_template: requirements: - binding: capability: tosca.capabilities.network.Bindable - node: server_cmaui + node: server_cmaui_2 relationship: tosca.relationships.network.BindsTo relationship_templates: cmaui_volume_attachment: type: org.openecomp.relationships.VolumeAttachesTo properties: volume_id: cmaui_volume - instance_uuid: server_cmaui + instance_uuid: server_cmaui_2 groups: a_vol_group: type: org.openecomp.groups.heat.HeatStack @@ -190,7 +190,7 @@ topology_template: heat_file: ../Artifacts/nested.yml description: cmaui server template for vMMSC members: - - server_cmaui + - server_cmaui_2 - cmaui_port_0 outputs: out_cmaui_volume: @@ -198,181 +198,181 @@ topology_template: substitution_mappings: node_type: org.openecomp.resource.abstract.nodes.heat.nested capabilities: - cpu.delta_server_cmaui: - - server_cmaui - - cpu.delta - disk.device.write.requests.rate_server_cmaui: - - server_cmaui - - disk.device.write.requests.rate - disk.device.allocation_server_cmaui: - - server_cmaui - - disk.device.allocation + disk.write.bytes.rate_server_cmaui_2: + - server_cmaui_2 + - disk.write.bytes.rate + disk.device.write.bytes_server_cmaui_2: + - server_cmaui_2 + - disk.device.write.bytes + disk.device.usage_server_cmaui_2: + - server_cmaui_2 + - disk.device.usage network.incoming.packets.rate_cmaui_port_0: - cmaui_port_0 - network.incoming.packets.rate - scalable_server_cmaui: - - server_cmaui - - scalable - disk.read.bytes.rate_server_cmaui: - - server_cmaui - - disk.read.bytes.rate - cpu_server_cmaui: - - server_cmaui - - cpu - disk.write.bytes.rate_server_cmaui: - - server_cmaui - - disk.write.bytes.rate - disk.device.read.bytes.rate_server_cmaui: - - server_cmaui - - disk.device.read.bytes.rate - host_server_cmaui: - - server_cmaui - - host - cpu_util_server_cmaui: - - server_cmaui - - cpu_util + disk.write.bytes_server_cmaui_2: + - server_cmaui_2 + - disk.write.bytes + feature_server_cmaui_2: + - server_cmaui_2 + - feature + disk.device.latency_server_cmaui_2: + - server_cmaui_2 + - disk.device.latency + disk.allocation_server_cmaui_2: + - server_cmaui_2 + - disk.allocation feature_cmaui_port_0: - cmaui_port_0 - feature - disk.device.latency_server_cmaui: - - server_cmaui - - disk.device.latency - disk.device.write.requests_server_cmaui: - - server_cmaui - - disk.device.write.requests - disk.read.requests_server_cmaui: - - server_cmaui - - disk.read.requests + binding_server_cmaui_2: + - server_cmaui_2 + - binding + disk.root.size_server_cmaui_2: + - server_cmaui_2 + - disk.root.size + disk.device.write.requests.rate_server_cmaui_2: + - server_cmaui_2 + - disk.device.write.requests.rate + vcpus_server_cmaui_2: + - server_cmaui_2 + - vcpus + scalable_server_cmaui_2: + - server_cmaui_2 + - scalable network.outgoing.packets.rate_cmaui_port_0: - cmaui_port_0 - network.outgoing.packets.rate - disk.device.capacity_server_cmaui: - - server_cmaui - - disk.device.capacity - disk.usage_server_cmaui: - - server_cmaui - - disk.usage + disk.read.requests_server_cmaui_2: + - server_cmaui_2 + - disk.read.requests attachment_cmaui_port_0: - cmaui_port_0 - attachment - disk.device.usage_server_cmaui: - - server_cmaui - - disk.device.usage network.outgoing.bytes_cmaui_port_0: - cmaui_port_0 - network.outgoing.bytes - disk.capacity_server_cmaui: - - server_cmaui - - disk.capacity - disk.write.requests.rate_server_cmaui: - - server_cmaui - - disk.write.requests.rate - disk.device.read.requests_server_cmaui: - - server_cmaui - - disk.device.read.requests - instance_server_cmaui: - - server_cmaui - - instance - disk.device.read.bytes_server_cmaui: - - server_cmaui + disk.write.requests_server_cmaui_2: + - server_cmaui_2 + - disk.write.requests + disk.device.iops_server_cmaui_2: + - server_cmaui_2 + - disk.device.iops + disk.usage_server_cmaui_2: + - server_cmaui_2 + - disk.usage + disk.device.capacity_server_cmaui_2: + - server_cmaui_2 + - disk.device.capacity + disk.device.read.bytes.rate_server_cmaui_2: + - server_cmaui_2 + - disk.device.read.bytes.rate + endpoint_server_cmaui_2: + - server_cmaui_2 + - endpoint + disk.read.bytes_server_cmaui_2: + - server_cmaui_2 + - disk.read.bytes + os_server_cmaui_2: + - server_cmaui_2 + - os + disk.device.read.bytes_server_cmaui_2: + - server_cmaui_2 - disk.device.read.bytes - memory_server_cmaui: - - server_cmaui + disk.write.requests.rate_server_cmaui_2: + - server_cmaui_2 + - disk.write.requests.rate + memory_server_cmaui_2: + - server_cmaui_2 - memory - disk.root.size_server_cmaui: - - server_cmaui - - disk.root.size - binding_server_cmaui: - - server_cmaui - - binding - disk.device.read.requests.rate_server_cmaui: - - server_cmaui - - disk.device.read.requests.rate - disk.write.bytes_server_cmaui: - - server_cmaui - - disk.write.bytes - os_server_cmaui: - - server_cmaui - - os - disk.device.write.bytes.rate_server_cmaui: - - server_cmaui - - disk.device.write.bytes.rate + cpu_server_cmaui_2: + - server_cmaui_2 + - cpu + disk.device.allocation_server_cmaui_2: + - server_cmaui_2 + - disk.device.allocation + host_server_cmaui_2: + - server_cmaui_2 + - host network.incoming.packets_cmaui_port_0: - cmaui_port_0 - network.incoming.packets - memory.resident_server_cmaui: - - server_cmaui - - memory.resident - disk.latency_server_cmaui: - - server_cmaui - - disk.latency + disk.ephemeral.size_server_cmaui_2: + - server_cmaui_2 + - disk.ephemeral.size + disk.capacity_server_cmaui_2: + - server_cmaui_2 + - disk.capacity + instance_server_cmaui_2: + - server_cmaui_2 + - instance binding_cmaui_port_0: - cmaui_port_0 - binding - feature_server_cmaui: - - server_cmaui - - feature feature_cmaui_volume: - cmaui_volume - feature - vcpus_server_cmaui: - - server_cmaui - - vcpus network.incoming.bytes.rate_cmaui_port_0: - cmaui_port_0 - network.incoming.bytes.rate - disk.device.write.bytes_server_cmaui: - - server_cmaui - - disk.device.write.bytes - disk.allocation_server_cmaui: - - server_cmaui - - disk.allocation - disk.write.requests_server_cmaui: - - server_cmaui - - disk.write.requests - memory.usage_server_cmaui: - - server_cmaui - - memory.usage + disk.iops_server_cmaui_2: + - server_cmaui_2 + - disk.iops + disk.device.write.requests_server_cmaui_2: + - server_cmaui_2 + - disk.device.write.requests + disk.device.read.requests_server_cmaui_2: + - server_cmaui_2 + - disk.device.read.requests network.outpoing.packets_cmaui_port_0: - cmaui_port_0 - network.outpoing.packets - disk.ephemeral.size_server_cmaui: - - server_cmaui - - disk.ephemeral.size + disk.read.bytes.rate_server_cmaui_2: + - server_cmaui_2 + - disk.read.bytes.rate + cpu.delta_server_cmaui_2: + - server_cmaui_2 + - cpu.delta + disk.device.read.requests.rate_server_cmaui_2: + - server_cmaui_2 + - disk.device.read.requests.rate + memory.resident_server_cmaui_2: + - server_cmaui_2 + - memory.resident network.outgoing.bytes.rate_cmaui_port_0: - cmaui_port_0 - network.outgoing.bytes.rate - endpoint_server_cmaui: - - server_cmaui - - endpoint - disk.iops_server_cmaui: - - server_cmaui - - disk.iops - disk.device.iops_server_cmaui: - - server_cmaui - - disk.device.iops - disk.read.bytes_server_cmaui: - - server_cmaui - - disk.read.bytes + disk.latency_server_cmaui_2: + - server_cmaui_2 + - disk.latency + cpu_util_server_cmaui_2: + - server_cmaui_2 + - cpu_util attachment_cmaui_volume: - cmaui_volume - attachment network.incoming.bytes_cmaui_port_0: - cmaui_port_0 - network.incoming.bytes + disk.device.write.bytes.rate_server_cmaui_2: + - server_cmaui_2 + - disk.device.write.bytes.rate + memory.usage_server_cmaui_2: + - server_cmaui_2 + - memory.usage requirements: - dependency_server_cmaui: - - server_cmaui - - dependency - local_storage_server_cmaui: - - server_cmaui - - local_storage dependency_cmaui_port_0: - cmaui_port_0 - dependency link_cmaui_port_0: - cmaui_port_0 - link + local_storage_server_cmaui_2: + - server_cmaui_2 + - local_storage + dependency_server_cmaui_2: + - server_cmaui_2 + - dependency dependency_cmaui_volume: - cmaui_volume - dependency \ No newline at end of file diff --git a/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-core/src/main/java/org/openecomp/sdc/vendorlicense/dao/impl/zusammen/FeatureGroupDaoZusammenImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-core/src/main/java/org/openecomp/sdc/vendorlicense/dao/impl/zusammen/FeatureGroupDaoZusammenImpl.java index ee6ffbfca2..624ffeb05e 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-core/src/main/java/org/openecomp/sdc/vendorlicense/dao/impl/zusammen/FeatureGroupDaoZusammenImpl.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-core/src/main/java/org/openecomp/sdc/vendorlicense/dao/impl/zusammen/FeatureGroupDaoZusammenImpl.java @@ -176,8 +176,12 @@ public class FeatureGroupDaoZusammenImpl implements FeatureGroupDao { mapElementInfoToFeatureGroup(featureGroup.getId(), featureGroup.getVersion(), elementInfo.get()); - currentFeatureGroup.getEntitlementPoolIds().removeAll(removedEntitlementPools); - currentFeatureGroup.getEntitlementPoolIds().addAll(addedEntitlementPools); + if (!(removedEntitlementPools == null)) { + currentFeatureGroup.getEntitlementPoolIds().removeAll(removedEntitlementPools); + } + if (!(addedEntitlementPools == null)) { + currentFeatureGroup.getEntitlementPoolIds().addAll(addedEntitlementPools); + } if (featureGroupElement.getRelations() == null) { featureGroupElement.setRelations(new ArrayList<>()); } @@ -187,7 +191,12 @@ public class FeatureGroupDaoZusammenImpl implements FeatureGroupDao { .createRelation(RelationType.FeatureGroupToEntitlmentPool, relation)) .collect(Collectors.toList())); - currentFeatureGroup.getLicenseKeyGroupIds().removeAll(removedLicenseKeyGroups); + if (!(removedLicenseKeyGroups == null)) { + currentFeatureGroup.getLicenseKeyGroupIds().removeAll(removedLicenseKeyGroups); + } + if (!(addedLicenseKeyGroups == null)) { + currentFeatureGroup.getLicenseKeyGroupIds().addAll(addedLicenseKeyGroups); + } currentFeatureGroup.getLicenseKeyGroupIds().addAll(addedLicenseKeyGroups); featureGroupElement.getRelations() .addAll(currentFeatureGroup.getLicenseKeyGroupIds().stream() diff --git a/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-core/src/main/java/org/openecomp/sdc/vendorlicense/dao/impl/zusammen/LicenseAgreementDaoZusammenImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-core/src/main/java/org/openecomp/sdc/vendorlicense/dao/impl/zusammen/LicenseAgreementDaoZusammenImpl.java index 55bbae9b33..45c831fbd7 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-core/src/main/java/org/openecomp/sdc/vendorlicense/dao/impl/zusammen/LicenseAgreementDaoZusammenImpl.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-license-lib/openecomp-sdc-vendor-license-core/src/main/java/org/openecomp/sdc/vendorlicense/dao/impl/zusammen/LicenseAgreementDaoZusammenImpl.java @@ -187,8 +187,13 @@ public class LicenseAgreementDaoZusammenImpl implements LicenseAgreementDao { mapElementInfoToLicenseAgreement(licenseAgreement.getId(), licenseAgreement.getVersion(), elementInfo.get()); - currentLicenseAgreement.getFeatureGroupIds().removeAll(removedFeatureGroupIds); - currentLicenseAgreement.getFeatureGroupIds().addAll(addedFeatureGroupIds); + if (! (removedFeatureGroupIds == null) ) { + currentLicenseAgreement.getFeatureGroupIds().removeAll(removedFeatureGroupIds); + } + + if (! (addedFeatureGroupIds == null)) { + currentLicenseAgreement.getFeatureGroupIds().addAll(addedFeatureGroupIds); + } licenseAgreementElement.setRelations(currentLicenseAgreement.getFeatureGroupIds().stream() .map(relation -> VlmZusammenUtil .createRelation(RelationType.LicenseAgreementToFeatureGroup, relation)) diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/MibDao.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/MibDao.java index cf980a52ff..1efd21ccbf 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/MibDao.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-api/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/MibDao.java @@ -38,4 +38,6 @@ public interface MibDao extends VersionableDao { Collection list(MibEntity entity); void deleteAll(MibEntity entity); + + Collection listArtifacts(MibEntity entity); } diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/MibDaoZusammenImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/MibDaoZusammenImpl.java index 10cdfbd9da..d56db41cee 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/MibDaoZusammenImpl.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/MibDaoZusammenImpl.java @@ -135,6 +135,38 @@ public class MibDaoZusammenImpl implements MibDao { VspZusammenUtil.aggregateElements(componentElement, mibsElement), "Delete mibs"); } + @Override + public Collection listArtifacts(MibEntity mib) { + SessionContext context = ZusammenUtil.createSessionContext(); + Id itemId = new Id(mib.getVspId()); + ElementContext elementContext = new ElementContext(itemId, + VspZusammenUtil.getFirstVersionId(context, itemId, zusammenAdaptor), + VspZusammenUtil.getVersionTag(mib.getVersion())); + + final Optional elementByName = + zusammenAdaptor.getElementByName(context, elementContext, new Id(mib.getComponentId() + ), StructureElement.Mibs.name()); + + if(!elementByName.isPresent()) + return null; + else { + final Id elementId = elementByName.get().getElementId(); + return zusammenAdaptor.listElementData(context, elementContext, elementId).stream() + .map(element -> + buildMibEntity(element,mib) + ).collect(Collectors.toList()); + } + } + + private MibEntity buildMibEntity (Element element, MibEntity mib) { + MibEntity createdMib = new MibEntity(mib.getVspId(), mib.getVersion(), mib.getComponentId(), + null); + createdMib.setArtifactName((String) element.getInfo().getProperties().get(ARTIFACT_NAME)); + createdMib.setArtifact(ByteBuffer.wrap(FileUtils.toByteArray(element.getData()))); + createdMib.setType( ArtifactType.valueOf(element.getInfo().getName())); + return createdMib; + } + private ZusammenElement buildComponentElement(MibEntity mibEntity) { ZusammenElement componentElement = new ZusammenElement(); componentElement.setElementId(new Id(mibEntity.getComponentId())); diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/OrchestrationTemplateDaoZusammenImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/OrchestrationTemplateDaoZusammenImpl.java index 83a78bc705..2b6d52a38a 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/OrchestrationTemplateDaoZusammenImpl.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/OrchestrationTemplateDaoZusammenImpl.java @@ -5,6 +5,7 @@ import com.amdocs.zusammen.adaptor.inbound.api.types.item.ElementInfo; import com.amdocs.zusammen.adaptor.inbound.api.types.item.ZusammenElement; import com.amdocs.zusammen.datatypes.Id; import com.amdocs.zusammen.datatypes.SessionContext; +import com.amdocs.zusammen.datatypes.item.Action; import com.amdocs.zusammen.datatypes.item.ElementContext; import com.amdocs.zusammen.utils.fileutils.FileUtils; import org.openecomp.core.zusammen.api.ZusammenAdaptor; @@ -13,7 +14,6 @@ import org.openecomp.sdc.vendorsoftwareproduct.dao.OrchestrationTemplateDao; import org.openecomp.sdc.vendorsoftwareproduct.dao.type.UploadData; import org.openecomp.sdc.vendorsoftwareproduct.dao.type.UploadDataEntity; import org.openecomp.sdc.versioning.dao.types.Version; -import org.openecomp.sdc.versioning.dao.types.VersionStatus; import java.io.ByteArrayInputStream; import java.nio.ByteBuffer; @@ -89,11 +89,11 @@ public class OrchestrationTemplateDaoZusammenImpl implements OrchestrationTempla VspZusammenUtil.buildStructuralElement(StructureElement.OrchestrationTemplate, null); ZusammenElement orchestrationTemplateValidationDataElement = VspZusammenUtil - .buildStructuralElement(StructureElement.OrchestrationTemplateValidationData, null); + .buildStructuralElement(StructureElement.OrchestrationTemplateValidationData, Action.UPDATE); orchestrationTemplateValidationDataElement.setData(new ByteArrayInputStream(uploadData .getValidationData().getBytes())); ZusammenElement orchestrationTemplateContent = - VspZusammenUtil.buildStructuralElement(StructureElement.OrchestrationTemplateContent, null); + VspZusammenUtil.buildStructuralElement(StructureElement.OrchestrationTemplateContent, Action.UPDATE); orchestrationTemplateContent .setData(new ByteArrayInputStream(uploadData.getContentData().array())); orchestrationTemplateElement.addSubElement(orchestrationTemplateValidationDataElement); diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/ProcessDaoZusammenImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/ProcessDaoZusammenImpl.java index ffc9cb2901..b0cff4371e 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/ProcessDaoZusammenImpl.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/zusammen/ProcessDaoZusammenImpl.java @@ -197,6 +197,9 @@ public class ProcessDaoZusammenImpl implements ProcessDao { processEntity .setArtifactName((String) elementInfo.getInfo().getProperties().get(ARTIFACT_NAME)); processEntity.setDescription((String) elementInfo.getInfo().getProperties().get(DESCRIPTION)); + processEntity.setType( elementInfo.getInfo().getProperties().get(PROCESS_TYPE) != null ? + ProcessType.valueOf((String) elementInfo.getInfo().getProperties().get(PROCESS_TYPE)) : + null); return processEntity; } diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/informationArtifact/impl/TxtInformationArtifactGeneratorImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/informationArtifact/impl/TxtInformationArtifactGeneratorImpl.java index d15014286f..7efb70494d 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/informationArtifact/impl/TxtInformationArtifactGeneratorImpl.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/informationArtifact/impl/TxtInformationArtifactGeneratorImpl.java @@ -214,7 +214,7 @@ public class TxtInformationArtifactGeneratorImpl implements InformationArtifactG .getNetworkDescription(), TAB + TAB + TAB + TAB)); networkOpt.ifPresent(network -> addEntryWithIndent(VNICS_NETWORK, network.toString(), TAB + TAB + TAB + TAB)); - addEntryWithIndent(VNICS_PROTOCOLS, nicQuestionnaire.getProtocols().toString(), + addEntryWithIndent(VNICS_PROTOCOLS, nicQuestionnaire.getProtocols() == null ? "" : nicQuestionnaire.getProtocols().toString(), TAB + TAB + TAB + TAB); Optional ipconfigOpt = Optional.of(nicQuestionnaire).map diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/ToscaAnalyzerService.java b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/ToscaAnalyzerService.java index 7d408ab82e..ac7cab6c51 100644 --- a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/ToscaAnalyzerService.java +++ b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/ToscaAnalyzerService.java @@ -24,6 +24,7 @@ import org.openecomp.sdc.tosca.datatypes.ToscaElementTypes; import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel; import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate; import org.openecomp.sdc.tosca.datatypes.model.NodeType; +import org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition; import org.openecomp.sdc.tosca.datatypes.model.RequirementAssignment; import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate; @@ -76,4 +77,7 @@ public interface ToscaAnalyzerService { boolean isRequirementExistInNodeTemplate(NodeTemplate nodeTemplate, String requirementId, RequirementAssignment requirementAssignment); + + public Map manageSubstitutionNodeTypeProperties( + ServiceTemplate substitutionServiceTemplate); } diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/impl/ToscaAnalyzerServiceImpl.java b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/impl/ToscaAnalyzerServiceImpl.java index e7aacb96cf..eaf3fb492f 100644 --- a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/impl/ToscaAnalyzerServiceImpl.java +++ b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/impl/ToscaAnalyzerServiceImpl.java @@ -94,7 +94,7 @@ public class ToscaAnalyzerServiceImpl implements ToscaAnalyzerService { .filter(nodeTypes -> Objects.nonNull(nodeTypes) && nodeTypes.containsKey(nodeTypeKey)) .findFirst(); if (nodeTypeMap.isPresent()) { - return Optional.ofNullable(nodeTypeMap.get().values().iterator().next()); + return Optional.ofNullable(nodeTypeMap.get().get(nodeTypeKey)); } return Optional.empty(); } @@ -601,7 +601,7 @@ public class ToscaAnalyzerServiceImpl implements ToscaAnalyzerService { return substitutionNodeType; } - private Map manageSubstitutionNodeTypeProperties( + public Map manageSubstitutionNodeTypeProperties( ServiceTemplate substitutionServiceTemplate) { Map substitutionNodeTypeProperties = new HashMap<>(); Map properties = diff --git a/openecomp-be/tools/install/database/schemaTemplates/questionnaire/component.ftl b/openecomp-be/tools/install/database/schemaTemplates/questionnaire/component.ftl index 6e588eb22a..d525c62474 100644 --- a/openecomp-be/tools/install/database/schemaTemplates/questionnaire/component.ftl +++ b/openecomp-be/tools/install/database/schemaTemplates/questionnaire/component.ftl @@ -136,7 +136,6 @@ "minimum": { "type": "number", "minimum": 0, - "exclusiveMinimum": true, "maximum": 100 }, "maximum": { diff --git a/openecomp-be/tools/migration/1702_to_1707_zusammen/pom.xml b/openecomp-be/tools/migration/1702_to_1707_zusammen/pom.xml index 7bc93bddab..1f281c950b 100644 --- a/openecomp-be/tools/migration/1702_to_1707_zusammen/pom.xml +++ b/openecomp-be/tools/migration/1702_to_1707_zusammen/pom.xml @@ -47,7 +47,7 @@ com.amdocs.zusammen.plugin zusammen-state-store-cassandra-plugin - 0.0.1-SNAPSHOT + 0.0.1 org.hibernate diff --git a/openecomp-be/tools/migration/1702_to_1707_zusammen/src/main/java/org/openecomp/core/migration/MigrationMain.java b/openecomp-be/tools/migration/1702_to_1707_zusammen/src/main/java/org/openecomp/core/migration/MigrationMain.java index 283c9cf25d..c43cf32001 100644 --- a/openecomp-be/tools/migration/1702_to_1707_zusammen/src/main/java/org/openecomp/core/migration/MigrationMain.java +++ b/openecomp-be/tools/migration/1702_to_1707_zusammen/src/main/java/org/openecomp/core/migration/MigrationMain.java @@ -78,7 +78,7 @@ public class MigrationMain { printMessage(logger, "Checking whether a migration has already been run."); if (MigrationMarker.isMigrated()) { printMessage(logger, "The DB has already been migrated, this script will now exit."); - return; + System.exit(status); } ItemCassandraDao itemCassandraDao = new ItemCassandraDao(); VersionCassandraDao versionCassandraDao = new VersionCassandraDao(); @@ -243,7 +243,8 @@ public class MigrationMain { new OrchestrationTemplateCandidateCassandraLoader(); orchestrationTemplateCandidateCassandraLoader.list().stream() - .filter(entity -> needMigration(entity.getId(), entity.getVersion())) + .filter(entity -> needMigration(entity.getId(), entity.getVersion()) && + entity.getContentData()!=null && entity.getFilesDataStructure()!=null) .forEach(entity -> ElementHandler .save(context, cassandraElementRepository, entity.getId(), entity.getVersion(), OrchestrationTemplateCandidateConvertor diff --git a/openecomp-ui/resources/scss/components/_sequenceDiagram.scss b/openecomp-ui/resources/scss/components/_sequenceDiagram.scss index 5fad92a668..d89c342d47 100644 --- a/openecomp-ui/resources/scss/components/_sequenceDiagram.scss +++ b/openecomp-ui/resources/scss/components/_sequenceDiagram.scss @@ -1,11 +1,18 @@ .sequence-diagram { - @extend .flex-column; .sequence-diagram-sequencer { - flex: 0 1 auto; - margin-bottom: 30px; + .asdcs-diagram { + overflow: auto; + max-height: 60vh; + } + .asdcs-editor { + height: 60vh; + } } .sequence-diagram-action-buttons { - flex: 0.1; - text-align: center; + margin-left: 20px; + margin-top: 20px; + button:first-of-type { + margin-right: 20px; + } } } diff --git a/openecomp-ui/resources/scss/modules/_workflows.scss b/openecomp-ui/resources/scss/modules/_workflows.scss index c1555df28c..894b6e7973 100644 --- a/openecomp-ui/resources/scss/modules/_workflows.scss +++ b/openecomp-ui/resources/scss/modules/_workflows.scss @@ -25,19 +25,3 @@ padding: 15px; } } - -.sequence-diagram { - position: absolute; - bottom: 0; - right: 0; - left: 0; - top: 0; - - padding-bottom: 20px; - .sequence-diagram-action-buttons { - display: flex; - button { - margin: 20px; - } - } -} diff --git a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx index 47922f86a0..98810d1c0d 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx @@ -110,5 +110,19 @@ class Form extends React.Component { } +export class TabsForm extends Form { + render() { + // eslint-disable-next-line no-unused-vars + let {isValid, formReady, onValidateForm, isReadOnlyMode, hasButtons, onSubmit, labledButtons, onValidChange, onValidityChanged, onDataChanged, children, ...formProps} = this.props; + return ( +
this.form = form} onSubmit={event => this.handleFormValidation(event)}> +
+ {children} +
+ {hasButtons && this.buttons = buttons} isReadOnlyMode={isReadOnlyMode}/>} + + ); + } +} export default Form; diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js index 4945d33b23..74bde4058b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js @@ -155,10 +155,12 @@ export default { licenseModelId = response[0].vendorId; } + const newVersion = response[0].version ? response[0].version : version; + SoftwareProductActionHelper.loadSoftwareProductDetailsData(dispatch, {licenseModelId, licensingVersion}); - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version}); - SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version}); + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version: newVersion}); + SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: newVersion}); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version: newVersion}); }); }, diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx index 5ae22cba95..d69548442c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx @@ -18,7 +18,7 @@ import Tabs from 'nfvo-components/input/validation/Tabs.jsx'; import Tab from 'react-bootstrap/lib/Tab.js'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; -import Form from 'nfvo-components/input/validation/Form.jsx'; +import {TabsForm as Form} from 'nfvo-components/input/validation/Form.jsx'; import DualListboxView from 'nfvo-components/input/dualListbox/DualListboxView.jsx'; import Input from 'nfvo-components/input/validation/Input.jsx'; import i18n from 'nfvo-utils/i18n/i18n.js'; @@ -169,17 +169,23 @@ class FeatureGroupEditorView extends React.Component { className='feature-group-form'> - this.validateName(value)}/> +
+ this.validateName(value)}/> +
- +
+ +
- +
+ +
diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx index 67a3333a3a..42a33fd509 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx @@ -17,7 +17,7 @@ import React from 'react'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; -import Form from 'nfvo-components/input/validation/Form.jsx'; +import {TabsForm as Form} from 'nfvo-components/input/validation/Form.jsx'; import Tabs from 'nfvo-components/input/validation/Tabs.jsx'; import Tab from 'react-bootstrap/lib/Tab.js'; import Input from 'nfvo-components/input/validation/Input.jsx'; @@ -151,21 +151,25 @@ class LicenseAgreementEditorView extends React.Component { eventKey={LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL} data-test-id='general-tab' title={i18n('General')}> - this.validateLTChoice(value)} - validateName={(value)=>this.validateName(value)}/> +
+ this.validateLTChoice(value)} + validateName={(value)=>this.validateName(value)}/> +
+
{featureGroupsList.length > 0 ? - onDataChanged( { featureGroupsIds: selectedValuesList }, LA_EDITOR_FORM )}/> : -

{i18n('There is no available feature groups')}

} + onDataChanged( { featureGroupsIds: selectedValuesList }, LA_EDITOR_FORM )}/> : +

{i18n('There is no available feature groups')}

} +
} diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js index 8f2506abdd..945de4fc36 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js @@ -77,8 +77,8 @@ export const mapActionsToProps = (dispatch, {softwareProductId}) => { } }), onSave: (heatCandidate, version) => SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(dispatch, {softwareProductId, heatCandidate, version}), - onGoToOverview: () => { - OnboardingActionHelper.navigateToSoftwareProductLandingPage(dispatch, {softwareProductId}); + onGoToOverview: ({version}) => { + OnboardingActionHelper.navigateToSoftwareProductLandingPage(dispatch, {softwareProductId, version}); }, onProcessAndValidate: ({heatData, heatDataCache, isReadOnlyMode, version}) => { return HeatSetupActionHelper.processAndValidateHeat(dispatch, diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx index 66fb2f8356..ef4aecf568 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx @@ -50,7 +50,7 @@ class HeatScreenView extends Component { iconClassName={this.props.goToOverview ? '' : 'disabled'} className={`go-to-overview-icon ${this.props.goToOverview ? '' : 'disabled'}`} labelClassName='go-to-overview-label' - onClick={this.props.goToOverview ? onGoToOverview : undefined} + onClick={this.props.goToOverview ? () => onGoToOverview({version}) : undefined} image='go-to-overview' label={i18n('Go to Overview')} data-test-id='go-to-overview'/>} diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js index 2ae9ad0bae..41e7556749 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js @@ -20,6 +20,7 @@ export default (state = {}, action) => { case actionTypes.COMPONENT_LOAD: return { ...state, + data: action.component, formReady: null, formName: forms.ALL_SPC_FORMS, genericFieldInfo: { diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js index 9b3c9eaa73..4e526d3b56 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js @@ -16,7 +16,7 @@ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes, COMPONENTS_QUESTIONNAIRE, forms} from './SoftwareProductComponentsConstants.js'; +import {actionTypes, COMPONENTS_QUESTIONNAIRE} from './SoftwareProductComponentsConstants.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; function baseUrl(softwareProductId, version) { @@ -89,12 +89,12 @@ const SoftwareProductComponentsActionHelper = { }, fetchSoftwareProductComponent(dispatch, {softwareProductId, version, vspComponentId}) { - dispatch({ - type: actionTypes.COMPONENT_LOAD - }); return Promise.all([ fetchSoftwareProductComponent(softwareProductId, version, vspComponentId).then(response => { - ValidationHelper.dataChanged(dispatch,{deltaData: response.data, formName: forms.ALL_SPC_FORMS}); + dispatch({ + type: actionTypes.COMPONENT_LOAD, + component: response.data + }); return response; }), fetchSoftwareProductComponentQuestionnaire(softwareProductId, version, vspComponentId).then(response => { diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js index 9540d3f869..05a1fc7797 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js @@ -25,7 +25,7 @@ export const mapStateToProps = ({softwareProduct}) => { return { isReadOnlyMode, softwareProductDependencies: softwareProductDependencies.length ? softwareProductDependencies : [{sourceId: '', targetId: '', relationType: 'dependsOn', id: 'fake'}], - componentsOptions: componentsList.map(component => ({value: component.id, label: component.name})) + componentsOptions: componentsList.map(component => ({value: component.id, label: component.displayName})) }; }; diff --git a/pom.xml b/pom.xml index 6976a82dc1..81fe758f3b 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,7 @@ 2.6.2 + 2.8.1 2.6.0 diff --git a/sdc-os-chef/pom.xml b/sdc-os-chef/pom.xml index 94ea55f9aa..e511056105 100644 --- a/sdc-os-chef/pom.xml +++ b/sdc-os-chef/pom.xml @@ -223,7 +223,7 @@ true - openecomp/sdc-backend,openecomp/sdc-frontend,openecomp/sdc-elasticsearch,openecomp/sdc-kibana,openecomp/sdc-sanity + openecomp/sdc-backend,openecomp/sdc-frontend,openecomp/sdc-elasticsearch,openecomp/sdc-kibana,openecomp/sdc-sanity @@ -243,7 +243,7 @@ push - openecomp/sdc-backend,openecomp/sdc-frontend,openecomp/sdc-elasticsearch,openecomp/sdc-kibana,openecomp/sdc-sanity + openecomp/sdc-backend,openecomp/sdc-frontend,openecomp/sdc-elasticsearch,openecomp/sdc-kibana,openecomp/sdc-sanity diff --git a/sdc-os-chef/sdc-backend/chef-repo/cookbooks/sdc-catalog-be/attributes/default.rb b/sdc-os-chef/sdc-backend/chef-repo/cookbooks/sdc-catalog-be/attributes/default.rb index f011a51021..4287ca8617 100644 --- a/sdc-os-chef/sdc-backend/chef-repo/cookbooks/sdc-catalog-be/attributes/default.rb +++ b/sdc-os-chef/sdc-backend/chef-repo/cookbooks/sdc-catalog-be/attributes/default.rb @@ -1,3 +1 @@ -# -# Example to value after replacement : default['asdctool'][:version] = "1707.0.66.73.1" -default['asdctool'][:version] = "__CATALOG-ASDCTOOL_TAR_NAME__" \ No newline at end of file +# \ No newline at end of file diff --git a/sdc-os-chef/sdc-backend/chef-repo/cookbooks/sdc-catalog-be/files/default/user.py b/sdc-os-chef/sdc-backend/chef-repo/cookbooks/sdc-catalog-be/files/default/user.py index d1ce9cfad8..90e44561ce 100644 --- a/sdc-os-chef/sdc-backend/chef-repo/cookbooks/sdc-catalog-be/files/default/user.py +++ b/sdc-os-chef/sdc-backend/chef-repo/cookbooks/sdc-catalog-be/files/default/user.py @@ -38,9 +38,9 @@ def checkUser(userName): -def createUser( firstName, lastName, userId , email , role ): - print '[INFO] create first:[' + firstName + '], last:[' + lastName + '], Id:[' + userId + '], email:[' + email + '], role:[' + role +']' - command="curl -s -o /dev/null -w \"%{http_code}\" -X POST -i -H \"Accept: application/json; charset=UTF-8\" -H \"Content-Type: application/json\" -H \"USER_ID: jh0003\" http://localhost:8080/sdc2/rest/v1/user/ -d '{\"firstName\": '" + firstName + "', \"lastName\": '" + lastName + "',\"userId\": '" + userId + "',\"email\": '" + email + "',\"role\": '" + role + "'}'" +def createUser( firstName, lastName, userId , email_dom , role ): + print '[INFO] create first:[' + firstName + '], last:[' + lastName + '], Id:[' + userId + '], email:[' + userId + '@' + email_dom + '], role:[' + role +']' + command="curl -s -o /dev/null -w \"%{http_code}\" -X POST -i -H \"Accept: application/json; charset=UTF-8\" -H \"Content-Type: application/json\" -H \"USER_ID: jh0003\" http://localhost:8080/sdc2/rest/v1/user/ -d '{\"firstName\": '" + firstName + "', \"lastName\": '" + lastName + "',\"userId\": '" + userId + "',\"email\": '" + userId + "@" + email_dom + "',\"role\": '" + role + "'}'" proc = subprocess.Popen( command , shell=True , stdout=subprocess.PIPE) (out, err) = proc.communicate() @@ -53,11 +53,11 @@ def createUser( firstName, lastName, userId , email , role ): ############################## # Definitions ############################## -userList = [ "demo" ] -lastName = "demo" -userId = "demo" -email = "demo@openecomp.org" -role = "ADMIN" +userId = [ "demo" , "op0001" , "gv0001" , "jh0003" , "jm0007" , "cs0008" ] +firstName = [ "demo" , "Oper" , "Giuseppe" , "Jimmy" , "Joni" , "Carlos" ] +lastName = [ "demo" , "P" , "Verdi" , "Hendrix" , "Mitchell" , "Santana" ] +role = [ "ADMIN" , "OPS" , "ADMIN" , "GOVERNOR" , "TESTER" , "DESIGNER" ] +email_dom = "openecomp.org" beStat=0 @@ -80,13 +80,14 @@ if beStat == 0: print '[ERROR]: ' + time.strftime('%Y/%m/%d %H:%M:%S') + bcolors.FAIL + 'Backend is DOWN :-(' + bcolors.ENDC exit() -for user in userList: +for user in userId: myResult = checkUser(user) + pos = userId.index(user) if myResult == '200': print '[INFO]: ' + user + ' already exists' else: - myResult = createUser( user, lastName, userId, email, role ) + myResult = createUser( firstName[pos], lastName[pos], userId[pos], email_dom, role[pos] ) if myResult == '201': - print '[INFO]: ' + userId + ' created, result: [' + myResult + ']' + print '[INFO]: ' + userId[pos] + ' created, result: [' + myResult + ']' else: - print '[ERROR]: ' + bcolors.FAIL + userId + bcolors.ENDC + ' error creating , result: [' + myResult + ']' + print '[ERROR]: ' + bcolors.FAIL + userId[pos] + bcolors.ENDC + ' error creating , result: [' + myResult + ']' diff --git a/sdc-os-chef/sdc-cassandra/chef-repo/cookbooks/cassandra-actions/files/default/titan.properties b/sdc-os-chef/sdc-cassandra/chef-repo/cookbooks/cassandra-actions/files/default/titan.properties deleted file mode 100644 index 43944eae47..0000000000 --- a/sdc-os-chef/sdc-cassandra/chef-repo/cookbooks/cassandra-actions/files/default/titan.properties +++ /dev/null @@ -1,6 +0,0 @@ -storage.backend=cassandra -storage.hostname=localhost -storage.port=9160 -storage.username=asdc_user -storage.password=Aa1234%^! -storage.cassandra.keyspace=sdctitan \ No newline at end of file diff --git a/sdc-os-chef/sdc-cassandra/chef-repo/cookbooks/cassandra-actions/templates/default/create_dox_keyspace.sh.erb b/sdc-os-chef/sdc-cassandra/chef-repo/cookbooks/cassandra-actions/templates/default/create_dox_keyspace.sh.erb index da6bbb184c..f65bb945f3 100644 --- a/sdc-os-chef/sdc-cassandra/chef-repo/cookbooks/cassandra-actions/templates/default/create_dox_keyspace.sh.erb +++ b/sdc-os-chef/sdc-cassandra/chef-repo/cookbooks/cassandra-actions/templates/default/create_dox_keyspace.sh.erb @@ -12,41 +12,23 @@ echo -e "$KEYSPACE\n$KEYSPACE1" > /tmp/create_dox_keyspace.cql chmod 755 /tmp/create_dox_keyspace.cql cqlsh -u $CASSANDRA_USER -p $CASSANDRA_PASS -f /tmp/create_dox_keyspace.cql > /dev/null 2>&1 -CS_VERSION=`cassandra -v` -CS_MAJOR_VERSION=`cassandra -v | cut -c1` -if [ ${CS_MAJOR_VERSION} -gt 2 ]; then - echo "`date` --- CS [${CS_VERSION}] uses system_schema.keyspaces" - res=`echo "select keyspace_name from system_schema.keyspaces ;" | cqlsh -u $CASSANDRA_USER -p $CASSANDRA_PASS |grep -c dox 2>/dev/null` -else - echo "`date` --- CS [${CS_VERSION}] uses system.schema_keyspaces" - res=`echo "select keyspace_name from system.schema_keyspaces ;" | cqlsh -u $CASSANDRA_USER -p $CASSANDRA_PASS |grep -c dox 2>/dev/null` -fi + +res=`echo "select keyspace_name from system.schema_keyspaces ;" | cqlsh -u $CASSANDRA_USER -p $CASSANDRA_PASS |grep -c dox 2>/dev/null` if [ $res -gt 0 ]; then - echo "`date` --- dox keyspace was created " + echo "`date` --- dox keyspace was created " else - echo "`date` --- Failed to create dox keyspace" + echo "`date` --- Failed to create dox keyspace" fi echo "run create_dox_db.cql" chmod 755 /tmp/create_dox_db.cql cqlsh -u $CASSANDRA_USER -p $CASSANDRA_PASS -f /tmp/create_dox_db.cql > /dev/null 2>&1 -$res=$? -if [ $res -gt 0 ]; then - echo "`date` --- dox keyspace: create_dox_db.cql failed ! " -else - echo "`date` --- dox keyspace: create_dox_db.cql completed successfully " -fi sleep 10 echo "run alter_dox_db.cql" chmod 755 /tmp/alter_dox_db.cql cqlsh -u $CASSANDRA_USER -p $CASSANDRA_PASS -f /tmp/alter_dox_db.cql > /dev/null 2>&1 -$res=$? -if [ $res -gt 0 ]; then - echo "`date` --- dox keyspace: alter_dox_db.cql failed !" -else - echo "`date` --- dox keyspace: alter_dox_db.cql completed successfully " -fi + diff --git a/test-apis-ci/.gitignore b/test-apis-ci/.gitignore new file mode 100644 index 0000000000..9b563712b6 --- /dev/null +++ b/test-apis-ci/.gitignore @@ -0,0 +1,4 @@ +/target +/build/ +/bin/ +/target/ diff --git a/test-apis-ci/pom.xml b/test-apis-ci/pom.xml new file mode 100644 index 0000000000..ec8eab07d3 --- /dev/null +++ b/test-apis-ci/pom.xml @@ -0,0 +1,381 @@ + + + 4.0.0 + + test-apis-ci + + + org.openecomp.sdc + sdc-main + 1.1.0-SNAPSHOT + + + + + com.google.guava + guava + ${guava.version} + compile + + + + junit + junit + ${junit.version} + compile + + + + org.testng + testng + ${testng.version} + compile + + + + com.aventstack + extentreports + 3.0.6 + compile + + + + org.mockito + mockito-all + ${mockito.version} + + compile + + + + com.typesafe + config + 1.0.2 + compile + + + + log4j + log4j + 1.2.17 + compile + + + + com.jcraft.jsch + com.springsource.com.jcraft.jsch + 0.1.41 + compile + + + + org.openecomp.sdc + common-app-api + ${project.version} + compile + + + + org.openecomp.sdc.be + common-be + ${project.version} + compile + + + + + org.openecomp.sdc.be + catalog-model + ${project.version} + compile + + + + + org.openecomp.sdc.be + catalog-dao + ${project.version} + compile + + + + org.functionaljava + functionaljava + ${functionaljava.version} + compile + + + + com.datastax.cassandra + cassandra-driver-core + ${cassandra.driver.version} + compile + + + + + + org.slf4j + slf4j-api + ${slf4j-api.version} + compile + + + + ch.qos.logback + logback-classic + ${logback.version} + compile + + + + ch.qos.logback + logback-core + ${logback.version} + compile + + + + com.googlecode.json-simple + json-simple + ${json-simple.version} + compile + + + + + org.apache.commons + commons-jci-core + ${commons-jci-core.version} + compile + + + + commons-codec + commons-codec + ${commons-codec} + compile + + + + + com.google.code.gson + gson + ${gson.version} + compile + + + + + org.yaml + snakeyaml + ${snakeyaml.version} + compile + + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + compile + + + + org.apache.httpcomponents + httpmime + ${httpclient.version} + compile + + + + commons-io + commons-io + 2.5 + compile + + + + commons-logging + commons-logging + ${commons-logging} + compile + + + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + compile + + + + + com.thinkaurelius.titan + titan-core + ${titan.version} + compile + + + slf4j-log4j12 + org.slf4j + + + + + + com.thinkaurelius.titan + titan-cassandra + ${titan.version} + compile + + + slf4j-log4j12 + org.slf4j + + + + + + org.codehaus.jackson + jackson-mapper-asl + 1.9.2 + compile + + + + com.fasterxml.jackson.core + jackson-databind + 2.3.1 + compile + + + + com.fasterxml.jackson.core + jackson-core + 2.3.1 + compile + + + + org.openecomp.ecompsdkos + epsdk-fw + ${ecomp.version} + compile + + + slf4j-log4j12 + org.slf4j + + + + + + org.json + json + 20090211 + + + org.openecomp.sdc.sdc-distribution-client + sdc-tosca-parser + 1.1.9-SNAPSHOT + compile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.7 + + true + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.5.5 + + + create.jar.with.dependencies + package + + single + + + + + org.openecomp.sdc.ci.tests.run.StartTest + + + + jar-with-dependencies + + + + + + + + + + + Fortify + + false + + + + + + + + + com.fortify.ps.maven.plugin + sca-maven-plugin + 4.30 + + false + true + + + + + + + diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/AttSdcTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/AttSdcTest.java new file mode 100644 index 0000000000..f9752febaf --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/AttSdcTest.java @@ -0,0 +1,200 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.api; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.junit.rules.TestWatcher; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.rules.MyTestWatcher; +import org.openecomp.sdc.ci.tests.run.StartTest; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public abstract class AttSdcTest { + + public static StringBuilder doc = new StringBuilder(); + public static String file = null; + public static Config config = null; + // protected Gson gson = new Gson(); + protected Gson prettyGson = new GsonBuilder().setPrettyPrinting().create(); + + protected TestName testName = null; + protected Logger logger = null; + + protected static boolean displayException = false; + + public AttSdcTest(TestName testName, String className) { + super(); + + StartTest.enableLogger(); + + this.testName = testName; + this.logger = LoggerFactory.getLogger(className); + + String displayEx = System.getProperty("displayException"); + if (displayEx != null && Boolean.valueOf(displayEx).booleanValue()) { + displayException = true; + } + + } + + @Rule + public TestWatcher tw = new MyTestWatcher(this); + + @BeforeClass + public static void beforeClass() { + doc = new StringBuilder(); + doc.append( + ""); + + doc.append(""); + doc.append( + ""); + + doc.append(""); + + doc.append(""); + doc.append(""); + + doc.append(""); + + doc.append(""); + doc.append(""); + doc.append(""); + doc.append(""); + + if (displayException) { + doc.append(""); + } + doc.append(""); + } + + @AfterClass + public static void afterClass() { + doc.append("
").append("Test Name").append("").append("Status").append("").append("Message").append("").append("Exception").append("
"); + // writeToFile("./" + ConfigAttOdlIt.REPORT_FILE , doc.toString()); + FileUtils.writeToFile( + Config.instance().getOutputFolder() + File.separator + file + StartTest.timeOfTest + ".html", + doc.toString()); + + } + + @Before + public void beforeTest() throws FileNotFoundException { + file = FileUtils.getFileName(this.getClass().getName()); + config = Utils.getConfig(); + assertTrue(config != null); + } + + @After + public void afterTest() throws FileNotFoundException { + + } + + public void addTestSummary(String testName, boolean isSuccess) { + addTestSummary(testName, isSuccess, null); + } + + public void addTestSummary(String testName, boolean isSuccess, Throwable exception) { + + String message = exception == null ? "" : exception.getMessage(); + + String result = (isSuccess) ? "success" : "fail"; + doc.append(""); + doc.append(""); + doc.append(""); + doc.append(""); + + if (displayException) { + // doc.append(""); + doc.append(""); + } + + doc.append(""); + + if (isSuccess) { + logger.debug("Test {} {}",testName,(isSuccess ? " SUCCEEDED " : " FAILED with error " + message)); + } else { + logger.error("Test {} {}",testName,(isSuccess ? " SUCCEEDED " : " FAILED with error " + message)); + } + } + + private String convertExceptionToString(Throwable exception) { + + if (exception == null) { + return ""; + } + + StringWriter sw = new StringWriter(); + exception.printStackTrace(new PrintWriter(sw)); + String exceptionAsString = sw.toString(); + + return exceptionAsString; + } + + public Logger getLogger() { + return logger; + } + + protected boolean ignoreDueToBug(String bug) { + + List bugs = config.getBugs(); + + if (bugs != null && bugs.size() > 0) { + for (String bugNumber : bugs) { + if (bugNumber.startsWith(bug)) { + return true; + } + } + } + + return false; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ComponentBaseTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ComponentBaseTest.java new file mode 100644 index 0000000000..a9cc119b20 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ComponentBaseTest.java @@ -0,0 +1,607 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.api; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.ImmutableTriple; +import org.apache.log4j.Logger; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels; +import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.cassandra.CassandraUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.AutomationUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.CatalogRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.slf4j.LoggerFactory; +import org.testng.ITestContext; +import org.testng.ITestResult; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeSuite; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.ExtentTest; +import com.aventstack.extentreports.Status; +import com.thinkaurelius.titan.core.TitanFactory; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanVertex; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; + +public abstract class ComponentBaseTest { + +// private static Logger logger = LoggerFactory.getLogger(ComponentBaseTest.class.getName()); + + protected static Logger logger= Logger.getLogger(ComponentBaseTest.class); + + + // public ComponentBaseTest(TestName testName, String className) { + // super(testName, className); + // } + + protected static ExtentReports extentReport; + public static final String REPORT_FOLDER = "./ExtentReport/"; + private static final String VERSIONS_INFO_FILE_NAME = "versions.info"; + private static final String REPORT_FILE_NAME = "SDC_CI_Extent_Report.html"; + protected static TitanGraph titanGraph; + private static Config myconfig; + public static Config config; + + + + /**************** METHODS ****************/ + public static ExtentTest getExtendTest() { + return ExtentTestManager.getTest(); + } + + public static enum ComponentOperationEnum { + CREATE_COMPONENT, UPDATE_COMPONENT, GET_COMPONENT, DELETE_COMPONENT, CHANGE_STATE_CHECKIN, CHANGE_STATE_CHECKOUT, CHANGE_STATE_UNDO_CHECKOUT + }; + + public ComponentBaseTest(TestName name, String name2) { + // TODO Auto-generated constructor stub + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + lc.getLogger("com.thinkaurelius").setLevel(Level.INFO); + lc.getLogger("com.datastax").setLevel(Level.INFO); + lc.getLogger("io.netty").setLevel(Level.INFO); + lc.getLogger("c.d").setLevel(Level.INFO); + } + + @BeforeSuite(alwaysRun = true) + public static void openTitan(ITestContext context) throws Exception { + + logger.info("<<>>"); + myconfig = Utils.getConfig(); + config = Utils.getConfig(); + + File dir = new File(REPORT_FOLDER); + try { + FileUtils.deleteDirectory(dir); + } catch (IOException e) { + } + dir.mkdir(); + + System.out.println("BeforeSuite - get reporter"); + extentReport = ExtentManager.getReporter(REPORT_FOLDER + REPORT_FILE_NAME); + + String onboardVersion = AutomationUtils.getOnboardVersion(); + String osVersion = AutomationUtils.getOSVersion(); + String envData = myconfig.getUrl(); + // TODO: uncomment config file +// extentReport.loadConfig(AutomationUtils.getConfigFile(CONFIG_FILE)); + + extentReport.setSystemInfo("Onboard Version", onboardVersion); + extentReport.setSystemInfo("OS Version", osVersion); + extentReport.setSystemInfo("ExecutedOn", envData); + extentReport.setSystemInfo("SuiteName", context.getName()); + AutomationUtils.createVersionsInfoFile(REPORT_FOLDER + VERSIONS_INFO_FILE_NAME, onboardVersion, osVersion, envData); + + System.out.println("BeforeSuite - open titan"); + openTitanLogic(); + + System.out.println("BeforeSuite - createConsumer"); + AtomicOperationUtils.createDefaultConsumer(true); + + System.out.println("BeforeSuite - performClean"); + performClean(); + } + + protected static void openTitanLogic() throws Exception { + + logger.trace(config.toString()); + String titanConfigFilePath = myconfig.getTitanPropertiesFile(); + titanGraph = TitanFactory.open(titanConfigFilePath); + assertNotNull(titanGraph); + + } + + @AfterClass(alwaysRun = true) + public synchronized static void cleanAfterClass() throws Exception{ + +// System.out.println("<<<<<<<>>>>"+method.getDeclaringClass()); +// System.out.println("<<<<<<<>>>>"+method.getName()); + + + System.out.println("delete components AfterClass"); + deleteCreatedComponents(getCatalogAsMap()); +// extentReport.flush(); + + } + + @AfterSuite(alwaysRun = true) + public static void shutdownTitan() throws Exception { + + System.out.println("AfterSuite - flush report"); + extentReport.flush(); + System.out.println("AfterSuite - perform clean"); + performClean(); + System.out.println("AfterSuite - close report"); +// extentReport.close(); + System.out.println("AfterSuite - close titan"); + shutdownTitanLogic(); + System.out.println("AfterSuite - suite ended"); + } + + protected static void shutdownTitanLogic() { + if (titanGraph.isOpen()) { + titanGraph.close(); + } + CassandraUtils.close(); + } + + @BeforeMethod(alwaysRun = true) + public void beforeState(java.lang.reflect.Method method) throws Exception { + + + ExtentTestManager.startTest(method.getName()); + String[] parts = this.getClass().getName().toString().split("\\."); + String lastOne1 = parts[parts.length-1]; + String lastOne2 = parts[parts.length-2]; + getExtendTest().assignCategory(lastOne2 + "-" + lastOne1); + getExtendTest().log(Status.INFO, "Test started"); + + } + + @AfterMethod(alwaysRun = true) + public void afterState(ITestResult result) throws Exception { + + String testName = result.getName(); + Throwable throwable = result.getThrowable(); + int status = result.getStatus(); + + switch(status){ + case ITestResult.SUCCESS: + getExtendTest().log(Status.PASS, "Test Result : Success"); + break; + + case ITestResult.FAILURE: + getExtendTest().log(Status.ERROR, "ERROR - The following exepction occured"); + getExtendTest().log(Status.ERROR, result.getThrowable()); + getExtendTest().log(Status.FAIL, "Failure"); + break; + + case ITestResult.SKIP: + getExtendTest().log(Status.SKIP, "SKIP - The following exepction occured"); + break; + default: + break; + } + + + ExtentTestManager.endTest(); + extentReport.flush(); + + + } + + protected static void performClean() throws Exception, FileNotFoundException { +// cleanComponents(); + deleteCreatedComponents(getCatalogAsMap()); + CassandraUtils.truncateAllKeyspaces(); + } + + public void verifyErrorCode(RestResponse response, String action, int expectedCode) { + assertNotNull("check response object is not null after " + action, response); + assertNotNull("check error code exists in response after " + action, response.getErrorCode()); + assertEquals("Check response code after + action" + action, expectedCode, response.getErrorCode().intValue()); + } + + private static void cleanComponents() throws Exception { + + // Components to delete + List vfResourcesToDelete = new ArrayList(); + List nonVfResourcesToDelete = new ArrayList(); + List servicesToDelete = new ArrayList(); + List productsToDelete = new ArrayList(); + + // Categories to delete + List> productGroupingsToDelete = new ArrayList<>(); + List> productSubsToDelete = new ArrayList<>(); + List> resourceSubsToDelete = new ArrayList<>(); + List productCategoriesToDelete = new ArrayList<>(); + List resourceCategoriesToDelete = new ArrayList(); + List serviceCategoriesToDelete = new ArrayList(); + + List resourcesNotToDelete = config.getResourcesNotToDelete(); + List resourceCategoriesNotToDelete = config.getResourceCategoriesNotToDelete(); + List serviceCategoriesNotToDelete = config.getServiceCategoriesNotToDelete(); + + Iterable vertices = titanGraph.query().has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.Resource.getName()).vertices(); + if (vertices != null) { + Iterator iter = vertices.iterator(); + while (iter.hasNext()) { + Vertex vertex = iter.next(); + Boolean isAbstract = vertex.value(GraphPropertiesDictionary.IS_ABSTRACT.getProperty()); + // if (!isAbstract) { + String name = vertex.value(GraphPropertiesDictionary.NAME.getProperty()); + String version = vertex.value(GraphPropertiesDictionary.VERSION.getProperty()); + + if ((resourcesNotToDelete != null && !resourcesNotToDelete.contains(name)) || (version != null && !version.equals("1.0"))) { + String id = vertex.value(GraphPropertiesDictionary.UNIQUE_ID.getProperty()); + String resourceType = vertex.value(GraphPropertiesDictionary.RESOURCE_TYPE.getProperty()); + if (name.startsWith("ci")) { + if (resourceType.equals(ResourceTypeEnum.VF.name())) { + vfResourcesToDelete.add(id); + } else { + nonVfResourcesToDelete.add(id); + } + } + } else if ((resourcesNotToDelete != null && !resourcesNotToDelete.contains(name)) || (version != null && version.equals("1.0"))) { + if ((boolean) vertex.value(GraphPropertiesDictionary.IS_HIGHEST_VERSION.getProperty()) == false) { + vertex.property(GraphPropertiesDictionary.IS_HIGHEST_VERSION.getProperty(), true); + } + } + // } + } + } + vertices = titanGraph.query().has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.Service.getName()).vertices(); + if (vertices != null) { + Iterator iter = vertices.iterator(); + while (iter.hasNext()) { + Vertex vertex = iter.next(); + String id = vertex.value(GraphPropertiesDictionary.UNIQUE_ID.getProperty()); + String name = vertex.value(GraphPropertiesDictionary.NAME.getProperty()); + if (name.startsWith("ci")) { + servicesToDelete.add(id); + } + } + } + + vertices = titanGraph.query().has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.Product.getName()).vertices(); + if (vertices != null) { + Iterator iter = vertices.iterator(); + while (iter.hasNext()) { + Vertex vertex = iter.next(); + String id = vertex.value(GraphPropertiesDictionary.UNIQUE_ID.getProperty()); + String name = vertex.value(GraphPropertiesDictionary.NAME.getProperty()); + if (name.startsWith("Ci")) { + productsToDelete.add(id); + } + } + } + + // Getting categories + + vertices = titanGraph.query().has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.ResourceNewCategory.getName()).vertices(); + if (vertices != null) { + Iterator iter = vertices.iterator(); + while (iter.hasNext()) { + Vertex category = iter.next(); + String name = category.value(GraphPropertiesDictionary.NAME.getProperty()); + if (!resourceCategoriesNotToDelete.contains(name)) { + String catId = category.value(GraphPropertiesDictionary.UNIQUE_ID.getProperty()); + resourceCategoriesToDelete.add(catId); + Iterator subs = category.vertices(Direction.OUT, GraphEdgeLabels.SUB_CATEGORY.getProperty()); + while (subs.hasNext()) { + Vertex sub = subs.next(); + String subCatId = sub.value(GraphPropertiesDictionary.UNIQUE_ID.getProperty()); + resourceSubsToDelete.add(new ImmutablePair(catId, subCatId)); + } + } + } + } + + vertices = titanGraph.query().has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.ServiceNewCategory.getName()).vertices(); + if (vertices != null) { + Iterator iter = vertices.iterator(); + while (iter.hasNext()) { + Vertex category = iter.next(); + String name = category.value(GraphPropertiesDictionary.NAME.getProperty()); + if (!serviceCategoriesNotToDelete.contains(name)) { + String id = category.value(GraphPropertiesDictionary.UNIQUE_ID.getProperty()); + serviceCategoriesToDelete.add(id); + } + } + } + + vertices = titanGraph.query().has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.ProductCategory.getName()).vertices(); + if (vertices != null) { + Iterator iter = vertices.iterator(); + while (iter.hasNext()) { + Vertex category = iter.next(); + String catId = category.value(GraphPropertiesDictionary.UNIQUE_ID.getProperty()); + productCategoriesToDelete.add(catId); + Iterator subs = category.vertices(Direction.OUT, GraphEdgeLabels.SUB_CATEGORY.getProperty()); + while (subs.hasNext()) { + Vertex sub = subs.next(); + String subCatId = sub.value(GraphPropertiesDictionary.UNIQUE_ID.getProperty()); + productSubsToDelete.add(new ImmutablePair(catId, subCatId)); + Iterator groupings = sub.vertices(Direction.OUT, GraphEdgeLabels.GROUPING.getProperty()); + while (groupings.hasNext()) { + Vertex grouping = groupings.next(); + String groupId = grouping.value(GraphPropertiesDictionary.UNIQUE_ID.getProperty()); + productGroupingsToDelete.add(new ImmutableTriple(catId, subCatId, groupId)); + } + } + + } + } + + titanGraph.tx().commit(); + + String adminId = UserRoleEnum.ADMIN.getUserId(); + String productStrategistId = UserRoleEnum.PRODUCT_STRATEGIST1.getUserId(); + + // Component delete + for (String id : productsToDelete) { + RestResponse deleteProduct = ProductRestUtils.deleteProduct(id, productStrategistId); + + } + for (String id : servicesToDelete) { + RestResponse deleteServiceById = ServiceRestUtils.deleteServiceById(id, adminId); + + } + for (String id : vfResourcesToDelete) { + RestResponse deleteResource = ResourceRestUtils.deleteResource(id, adminId); + + } + + for (String id : nonVfResourcesToDelete) { + RestResponse deleteResource = ResourceRestUtils.deleteResource(id, adminId); + + } + + // Categories delete - product + String componentType = BaseRestUtils.PRODUCT_COMPONENT_TYPE; + for (ImmutableTriple triple : productGroupingsToDelete) { + CategoryRestUtils.deleteGrouping(triple.getRight(), triple.getMiddle(), triple.getLeft(), productStrategistId, componentType); + } + for (ImmutablePair pair : productSubsToDelete) { + CategoryRestUtils.deleteSubCategory(pair.getRight(), pair.getLeft(), productStrategistId, componentType); + } + for (String id : productCategoriesToDelete) { + CategoryRestUtils.deleteCategory(id, productStrategistId, componentType); + } + + // Categories delete - resource + componentType = BaseRestUtils.RESOURCE_COMPONENT_TYPE; + for (ImmutablePair pair : resourceSubsToDelete) { + CategoryRestUtils.deleteSubCategory(pair.getRight(), pair.getLeft(), adminId, componentType); + } + for (String id : resourceCategoriesToDelete) { + CategoryRestUtils.deleteCategory(id, adminId, componentType); + } + // Categories delete - resource + componentType = BaseRestUtils.SERVICE_COMPONENT_TYPE; + for (String id : serviceCategoriesToDelete) { + CategoryRestUtils.deleteCategory(id, adminId, componentType); + } + + } + + private static void deleteCreatedComponents(Map> convertCatalogResponseToJavaObject) throws IOException { + final String userId = UserRoleEnum.DESIGNER.getUserId(); + + List resourcesArrayList = convertCatalogResponseToJavaObject.get(ComponentTypeEnum.PRODUCT_PARAM_NAME); + if (resourcesArrayList.size() > 0) { + List collect = buildCollectionUniqueId(resourcesArrayList); + for (String uId : collect) { + ProductRestUtils.deleteProduct(uId, userId); + } + } + + + resourcesArrayList = convertCatalogResponseToJavaObject.get(ComponentTypeEnum.SERVICE_PARAM_NAME); + if (resourcesArrayList.size() > 0) { + List collect = buildCollectionUniqueId(resourcesArrayList); + for (String uId : collect) { + ServiceRestUtils.markServiceToDelete(uId, userId); + } + ServiceRestUtils.deleteMarkedServices(userId); + } + + + resourcesArrayList = convertCatalogResponseToJavaObject.get(ComponentTypeEnum.RESOURCE_PARAM_NAME); + + // List collect = resourcesArrayList.stream().filter(s -> + // s.getName().startsWith("ci")).map(e -> + // e.getUniqueId()).collect(Collectors.toList()); + + // List> collect = + // resourcesArrayList.stream().filter(s -> + // s.getName().startsWith("ci")).map(e -> + // e.getAllVersions()).collect(Collectors.toList()); + /* + * List collect = resourcesArrayList.stream().filter(s -> s.getName().startsWith("ci")) .flatMap(e -> e.getAllVersions().values().stream()).collect(Collectors.toList()); + */ + + if (!CollectionUtils.isEmpty(resourcesArrayList)) { + List collect = buildCollectionUniqueId(resourcesArrayList); + for (String uId : collect) { + ResourceRestUtils.markResourceToDelete(uId, userId); + } + ResourceRestUtils.deleteMarkedResources(userId); + } + + + + } + + private void deleteCollection(List componentArrayList, Consumer deleteHandler) { + + if (componentArrayList.size() > 0) { + List collect = buildCollectionUniqueId(componentArrayList); + for (String uId : collect) { + deleteHandler.accept(uId); + // ProductRestUtils.deleteProduct(uId, userId); + } + } + } + + protected static List buildCollectionUniqueId(List resourcesArrayList) { + + // Stream flatMap = resourcesArrayList.stream().filter(s -> + // s.getName().startsWith("ci")).map(e -> e.getAllVersions()).map( e -> + // e.values()).flatMap( e -> e.stream()); + + // List collect = resourcesArrayList.stream() + // // + // .filter(s -> s.getName().startsWith("ci") ) + // // + // .map(e -> e.getUniqueId()) + + // .map( e -> e.values()) + // .filter(out -> out!=null ) + // .flatMap( e -> e.stream()) + // .collect(Collectors.toList()); + + // List collect = resourcesArrayList.stream().filter(s -> + // s.getName().startsWith("ci")) + // .flatMap(e -> + // e.getAllVersions().values().stream()).collect(Collectors.toList()); + ComponentTypeEnum componentTypeEnum = resourcesArrayList.get(0).getComponentType(); + + List genericCollection = new ArrayList(); + + resourcesArrayList.stream().filter(s -> s.getName().toLowerCase().startsWith("ci") && !s.getName().toLowerCase().equals("cindervolume")).map(e -> e.getUniqueId()).collect(Collectors.toList()).forEach((i) -> { + buildCollectionBaseOnComponentType(componentTypeEnum, genericCollection, i); + }); + + + // + + // List collect = + // genericCollection.stream().collect(Collectors.toList()); + + return genericCollection; + } + + public static void buildCollectionBaseOnComponentType(ComponentTypeEnum componentTypeEnum, + List genericCollection, String i) { + try { + switch (componentTypeEnum) { + case RESOURCE: + RestResponse resource = ResourceRestUtils.getResource(i); + Resource convertResourceResponseToJavaObject = ResponseParser.convertResourceResponseToJavaObject(resource.getResponse()); + Map allVersions = convertResourceResponseToJavaObject.getAllVersions(); + Collection values = allVersions.values(); + genericCollection.addAll(values); + + break; + case SERVICE: + RestResponse service = ServiceRestUtils.getService(i); + Service convertServiceResponseToJavaObject = ResponseParser.convertServiceResponseToJavaObject(service.getResponse()); + allVersions = convertServiceResponseToJavaObject.getAllVersions(); + values = allVersions.values(); + genericCollection.addAll(values); + + break; + + + case PRODUCT: + RestResponse product = ProductRestUtils.getProduct(i); + Product convertProductResponseToJavaObject = ResponseParser.convertProductResponseToJavaObject(product.getResponse()); + allVersions = convertProductResponseToJavaObject.getAllVersions(); + values = allVersions.values(); + genericCollection.addAll(values); + + break; + + // default: + // break; + } + } catch (Exception e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + + protected static Map> getCatalogAsMap() throws Exception { + RestResponse catalog = CatalogRestUtils.getCatalog(UserRoleEnum.DESIGNER.getUserId()); + Map> convertCatalogResponseToJavaObject = ResponseParser.convertCatalogResponseToJavaObject(catalog.getResponse()); + return convertCatalogResponseToJavaObject; + } + protected Resource createVfFromCSAR(User sdncModifierDetails, String csarId) throws Exception { + // create new resource from Csar + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + + resourceDetails.setCsarUUID(csarId); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource createdResource = ResponseParser.convertResourceResponseToJavaObject(createResource.getResponse()); + return createdResource; + } + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ComponentInstanceBaseTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ComponentInstanceBaseTest.java new file mode 100644 index 0000000000..47efca66d0 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ComponentInstanceBaseTest.java @@ -0,0 +1,764 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.api; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Function; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.Assert; + +public class ComponentInstanceBaseTest extends ComponentBaseTest { + public static final String acceptHeaderData = "application/json"; + // Req/cap of container component + protected Map> expectedContainerCapabilities; + protected Map> expectedContainerRequirements; + protected Map>> removedRequirements; + protected Map>, Map>>> expectedContInstReqCap; + + protected User sdncPsDetails1; + protected User sdncPsDetails2; + protected User sdncPmDetails1; + protected User sdncPmDetails2; + protected User sdncDesignerDetails; + protected User sdncAdminDetails; + protected User sdncTesterDetails; + protected ResourceReqDetails resourceDetailsVFC_01; + protected ResourceReqDetails resourceDetailsVFC_02; + protected ResourceReqDetails resourceDetailsVF_01; + protected ResourceReqDetails resourceDetailsVF_02; + protected ResourceReqDetails resourceDetailsCP_01; + protected ResourceReqDetails resourceDetailsCP_02; + protected ResourceReqDetails resourceDetailsVL_01; + protected ResourceReqDetails resourceDetailsVL_02; + protected ServiceReqDetails serviceDetails_01; + protected ServiceReqDetails serviceDetails_02; + protected ServiceReqDetails serviceDetails_03; + protected ProductReqDetails productDetails_01; + protected ProductReqDetails productDetails_02; + + public void init() { + // Req/caps of inner componentInstances + expectedContainerCapabilities = new LinkedHashMap>(); + expectedContainerRequirements = new LinkedHashMap>(); + removedRequirements = new HashMap<>(); + expectedContInstReqCap = new HashMap<>(); + + sdncPsDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1); + sdncPsDetails2 = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST2); + sdncPmDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1); + sdncPmDetails2 = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER2); + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncAdminDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncTesterDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + resourceDetailsVFC_01 = ElementFactory.getDefaultResourceByType("ciVFC100", NormativeTypesEnum.SOFTWARE_COMPONENT, ResourceCategoryEnum.GENERIC_DATABASE, sdncDesignerDetails.getUserId(), ResourceTypeEnum.VFC.toString()); // resourceType = VFC + resourceDetailsVFC_02 = ElementFactory.getDefaultResourceByType("ciVFC200", NormativeTypesEnum.COMPUTE, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), ResourceTypeEnum.VFC.toString()); + resourceDetailsVF_01 = ElementFactory.getDefaultResourceByType("ciVF100", NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), ResourceTypeEnum.VF.toString()); + resourceDetailsVF_02 = ElementFactory.getDefaultResourceByType("ciVF200", NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), ResourceTypeEnum.VF.toString()); + resourceDetailsCP_01 = ElementFactory.getDefaultResourceByType("ciCP100", NormativeTypesEnum.PORT, ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, sdncDesignerDetails.getUserId(), ResourceTypeEnum.CP.toString()); + resourceDetailsCP_02 = ElementFactory.getDefaultResourceByType("ciCP200", NormativeTypesEnum.PORT, ResourceCategoryEnum.GENERIC_DATABASE, sdncDesignerDetails.getUserId(), ResourceTypeEnum.CP.toString()); + resourceDetailsVL_01 = ElementFactory.getDefaultResourceByType("ciVL100", NormativeTypesEnum.NETWORK, ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, sdncDesignerDetails.getUserId(), ResourceTypeEnum.VL.toString()); + resourceDetailsVL_02 = ElementFactory.getDefaultResourceByType("ciVL200", NormativeTypesEnum.NETWORK, ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, sdncDesignerDetails.getUserId(), ResourceTypeEnum.VL.toString()); + serviceDetails_01 = ElementFactory.getDefaultService("ciNewtestservice1", ServiceCategoriesEnum.MOBILITY, sdncDesignerDetails.getUserId()); + serviceDetails_02 = ElementFactory.getDefaultService("ciNewtestservice2", ServiceCategoriesEnum.MOBILITY, sdncDesignerDetails.getUserId()); + serviceDetails_03 = ElementFactory.getDefaultService("ciNewtestservice3", ServiceCategoriesEnum.MOBILITY, sdncDesignerDetails.getUserId()); + productDetails_01 = ElementFactory.getDefaultProduct("ciProduct01"); + productDetails_02 = ElementFactory.getDefaultProduct("ciProduct02"); + } + + public ComponentInstanceBaseTest(TestName testName, String className) { + super(testName, className); + } + + public void verifyVFReqCap(String componentId) throws Exception { + RestResponse restResponse = ResourceRestUtils.getResource(componentId); + Resource resource = ResponseParser.parseToObject(restResponse.getResponse(), Resource.class); + verifyReqCap(resource); + } + + public void verifyServiceReqCap(String componentId) throws Exception { + RestResponse restResponse = ServiceRestUtils.getService(componentId, sdncDesignerDetails); + Service service = ResponseParser.parseToObject(restResponse.getResponse(), Service.class); + verifyReqCap(service); + } + + public void verifyProductReqCap(String componentId) throws Exception { + RestResponse restResponse = ProductRestUtils.getProduct(componentId, sdncPsDetails1.getUserId()); + Product product = ResponseParser.parseToObject(restResponse.getResponse(), Product.class); + verifyReqCap(product); + } + + public void verifyReqCap(Component actualComponent) { + verifyContainerReqCap(actualComponent); + verifyCompInstReqCap(actualComponent); + } + + public RestResponse changeServiceInstanceVersion(String componentUniqueId, String serviceInstanceToReplaceUniqueId, String serviceUniqueId, User sdncModifierDetails, ComponentTypeEnum componentType, boolean isHighestLevel) throws Exception { + RestResponse changeResourceInstanceVersion = ProductRestUtils.changeServiceInstanceVersion(componentUniqueId, serviceInstanceToReplaceUniqueId, serviceUniqueId, sdncModifierDetails, componentType); + if (changeResourceInstanceVersion.getErrorCode().equals(BaseRestUtils.STATUS_CODE_SUCCESS) && isHighestLevel) { + /* + * // Add RI Capabilities and Requirements to expected MAP --> expectedVfCapabilities and expectedVfRequirements + * + * ComponentInstance componentInstance = ResponseParser.parseToObjectUsingMapper( changeResourceInstanceVersion.getResponse(), ComponentInstance.class); addCompInstReqCapToExpected(componentInstance, componentType); + */ + } + return changeResourceInstanceVersion; + } + + protected void updateExpectedReqCapAfterChangeLifecycleState(String oldContainerUniqueIdToReplace, String newContainerUniqueId) { + + // Update of container req/cap + + Set compInstKeysToChange = new HashSet<>(); + + for (String expKey : expectedContainerCapabilities.keySet()) { + List expCapList = expectedContainerCapabilities.get(expKey); + for (CapabilityDefinition cap : expCapList) { + String ownerId = cap.getOwnerId(); + + if (ownerId.contains(oldContainerUniqueIdToReplace)) { + compInstKeysToChange.add(ownerId); + cap.setOwnerId(cap.getOwnerId().replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId)); + } + } + } + + for (String expKey : expectedContainerRequirements.keySet()) { + List expCapList = expectedContainerRequirements.get(expKey); + for (RequirementDefinition cap : expCapList) { + String ownerId = cap.getOwnerId(); + if (ownerId.contains(oldContainerUniqueIdToReplace)) { + compInstKeysToChange.add(ownerId); + cap.setOwnerId(cap.getOwnerId().replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId)); + } + } + } + + // Update of internal comp instances req/cap + for (String oldKey : compInstKeysToChange) { + ImmutablePair>, Map>> immutablePair = expectedContInstReqCap.get(oldKey); + if (immutablePair != null) { + expectedContInstReqCap.remove(oldKey); + String newKey = oldKey.replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId); + expectedContInstReqCap.put(newKey, immutablePair); + } + } + + // Update of removed req + for (String oldKey : compInstKeysToChange) { + Map> map = removedRequirements.get(oldKey); + if (map != null) { + removedRequirements.remove(oldKey); + String newKey = oldKey.replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId); + Collection> values = map.values(); + if (values != null) { + for (List list : values) { + for (RequirementDefinition reqDef : list) { + reqDef.setOwnerId(reqDef.getOwnerId().replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId)); + } + } + } + removedRequirements.put(newKey, map); + } + } + } + + private void verifyCompInstReqCap(Component actualComponent) { + List componentInstances = actualComponent.getComponentInstances(); + if (componentInstances != null) { + assertEquals(expectedContInstReqCap.size(), componentInstances.size()); + for (ComponentInstance compInst : componentInstances) { + String uniqueId = compInst.getUniqueId(); + // System.out.println("Verifying req/cap of component instance + // "+ uniqueId); + Map> actualCompInstReq = compInst.getRequirements(); + if (actualCompInstReq == null) { + actualCompInstReq = new HashMap<>(); + } + Map> actualCompInstCap = compInst.getCapabilities(); + if (actualCompInstCap == null) { + actualCompInstCap = new HashMap<>(); + } + ImmutablePair>, Map>> expReqCap = expectedContInstReqCap.get(uniqueId); + assertNotNull(expReqCap); + // System.out.println("expected instance requirements: + // "+expReqCap.right); + // System.out.println("expected instance capabilities: + // "+expReqCap.left); + // System.out.println("actual instance requirements: + // "+actualCompInstReq); + // System.out.println("actual instance capabilities: + // "+actualCompInstCap); + + // REQ comparison + compareReqCapMaps(expReqCap.right, actualCompInstReq); + + // CAP comparison + compareReqCapMaps(expReqCap.left, actualCompInstCap); + } + + } else { + assertTrue(expectedContInstReqCap.isEmpty()); + } + } + + private void verifyContainerReqCap(Component actualComponent) { + Map> actualContainerRequirements = actualComponent.getRequirements(); + if (actualContainerRequirements == null) { + actualContainerRequirements = new HashMap<>(); + } + Map> actualContainerCapabilities = actualComponent.getCapabilities(); + if (actualContainerCapabilities == null) { + actualContainerCapabilities = new HashMap<>(); + } + // System.out.println("Verifying req/cap of container component "+ + // actualComponent.getUniqueId()); + // System.out.println("expected container requirements: + // "+expectedContainerRequirements); + // System.out.println("expected container capabilities: + // "+expectedContainerCapabilities); + // System.out.println("actual container requirements: + // "+actualContainerRequirements); + // System.out.println("actual container capabilities: + // "+actualContainerCapabilities); + + // REQ comparison + compareReqCapMaps(expectedContainerRequirements, actualContainerRequirements); + + // CAP comparison + compareReqCapMaps(expectedContainerCapabilities, actualContainerCapabilities); + } + + private void compareReqCapMaps(Map> expectedMap, Map> actualMap) { + assertEquals(expectedMap.size(), actualMap.size()); + for (String expKey : expectedMap.keySet()) { + List expCapList = expectedMap.get(expKey); + List actCapList = actualMap.get(expKey); + assertEquals(expCapList.size(), actCapList.size()); + assertEquals(new HashSet<>(expCapList), new HashSet<>(actCapList)); + } + } + + public void addCompInstReqCapToExpected(ComponentInstance componentInstance, ComponentTypeEnum containerComponentType) throws Exception { + String uniqueId = componentInstance.getUniqueId(); + String name = componentInstance.getName(); + String originComponentId = componentInstance.getComponentUid(); + RestResponse getResponse = null; + ComponentTypeEnum compInstType = getCompInstTypeByContainerType(containerComponentType); + Component component = null; + if (compInstType == ComponentTypeEnum.RESOURCE) { + getResponse = ResourceRestUtils.getResource(sdncDesignerDetails, originComponentId); + ResourceRestUtils.checkSuccess(getResponse); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Resource.class); + } else if (compInstType == ComponentTypeEnum.SERVICE) { + getResponse = ServiceRestUtils.getService(originComponentId, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getResponse); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Service.class); + } else { + Assert.fail("Unsupported type - " + containerComponentType); + } + + Map> resourceRequirements = component.getRequirements(); + if (resourceRequirements == null) { + resourceRequirements = new HashMap<>(); + } + + Function>, List> requirementDefinitionMapper = e -> new ArrayList<>(e.getValue().stream().map(item -> new RequirementDefinition(item)).collect(Collectors.toList())); + Map> reqCopy = resourceRequirements.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), requirementDefinitionMapper)); + + Map> resourceCapabilities = component.getCapabilities(); + if (resourceCapabilities == null) { + resourceCapabilities = new HashMap<>(); + } + + Function>, List> capabilityDefinitionMapper = e -> new ArrayList<>(e.getValue().stream().map(item -> new CapabilityDefinition(item)).collect(Collectors.toList())); + Map> capCopy = resourceCapabilities.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), capabilityDefinitionMapper)); + + setupContainerExpectedReqCap(uniqueId, name, resourceRequirements, resourceCapabilities); + if (component.getComponentType().equals(ComponentTypeEnum.RESOURCE) && ((Resource) component).getResourceType() != ResourceTypeEnum.VF) { + setupConstInstExpectedReqCap(uniqueId, name, reqCopy, capCopy); + } + + // adding entry for expected componentInstance + ImmutablePair>, Map>> compInstReqCapPair = new ImmutablePair>, Map>>(capCopy, reqCopy); + expectedContInstReqCap.put(uniqueId, compInstReqCapPair); + } + + private void setupContainerExpectedReqCap(String uniqueId, String name, Map> componentRequirements, Map> componentCapabilities) { + for (Entry> resReq : componentRequirements.entrySet()) { + List reqListToAdd = resReq.getValue(); + for (RequirementDefinition requirementDefinition : reqListToAdd) { + requirementDefinition.setOwnerId(uniqueId); + requirementDefinition.setOwnerName(name); + } + List expectedReqList = expectedContainerRequirements.get(resReq.getKey()); + if (expectedReqList == null) { + expectedReqList = reqListToAdd; + } else { + expectedReqList.addAll(reqListToAdd); + } + expectedContainerRequirements.put(resReq.getKey(), expectedReqList); + } + + for (Entry> resCap : componentCapabilities.entrySet()) { + List capListToAdd = resCap.getValue(); + for (CapabilityDefinition capDefinition : capListToAdd) { + capDefinition.setOwnerId(uniqueId); + capDefinition.setOwnerName(name); + } + List expectedCapList = expectedContainerCapabilities.get(resCap.getKey()); + if (expectedCapList == null) { + expectedCapList = capListToAdd; + } else { + expectedCapList.addAll(capListToAdd); + } + expectedContainerCapabilities.put(resCap.getKey(), expectedCapList); + } + } + + private void setupConstInstExpectedReqCap(String uniqueId, String name, Map> componentRequirements, Map> componentCapabilities) { + for (Entry> resReq : componentRequirements.entrySet()) { + List reqListToAdd = resReq.getValue(); + for (RequirementDefinition requirementDefinition : reqListToAdd) { + requirementDefinition.setOwnerId(uniqueId); + requirementDefinition.setOwnerName(name); + } + } + + for (Entry> resCap : componentCapabilities.entrySet()) { + List capListToAdd = resCap.getValue(); + for (CapabilityDefinition capDefinition : capListToAdd) { + capDefinition.setOwnerId(uniqueId); + capDefinition.setOwnerName(name); + } + } + } + + private ComponentTypeEnum getCompInstTypeByContainerType(ComponentTypeEnum componentType) { + switch (componentType) { + case RESOURCE: + return ComponentTypeEnum.RESOURCE; + case SERVICE: + return ComponentTypeEnum.RESOURCE; + case PRODUCT: + return ComponentTypeEnum.SERVICE; + default: + break; + } + return null; + } + + public void deleteCompInstReqCapFromExpected(String componentInstanceId) { + List entriesRequirementsToRemove = new ArrayList<>(); + List entriesCapabilitiesToRemove = new ArrayList<>(); + for (Entry> reqEntry : expectedContainerRequirements.entrySet()) { + List reqList = reqEntry.getValue(); + List reqListToDelete = new ArrayList<>(); + for (RequirementDefinition requirementDefinition : reqList) { + if (requirementDefinition.getOwnerId().equals(componentInstanceId)) { + reqListToDelete.add(requirementDefinition); + } + } + reqList.removeAll(reqListToDelete); + if (reqList.isEmpty()) { + entriesRequirementsToRemove.add(reqEntry.getKey()); + } + } + + for (String ekey : entriesRequirementsToRemove) { + expectedContainerRequirements.remove(ekey); + } + + for (Entry> capEntry : expectedContainerCapabilities.entrySet()) { + List capList = capEntry.getValue(); + List capListToDelete = new ArrayList<>(); + for (CapabilityDefinition capabilityDefinition : capList) { + if (capabilityDefinition.getOwnerId().equals(componentInstanceId)) { + capListToDelete.add(capabilityDefinition); + } + } + capList.removeAll(capListToDelete); + if (capList.isEmpty()) { + entriesCapabilitiesToRemove.add(capEntry.getKey()); + } + } + for (String ekey : entriesCapabilitiesToRemove) { + expectedContainerCapabilities.remove(ekey); + } + + expectedContInstReqCap.remove(componentInstanceId); + + } + + // Automatically updates the expected req/cap of the container + protected RestResponse createAtomicInstanceForVF(ResourceReqDetails containerDetails, ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.RESOURCE, true); + } + + // Automatically updates the expected req/cap of the container + protected RestResponse createAtomicInstanceForService(ServiceReqDetails containerDetails, ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, true); + } + + // Automatically updates the expected req/cap of the container + protected RestResponse createVFInstance(ServiceReqDetails containerDetails, ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, true); + } + + // Automatically updates the expected req/cap of the container + protected RestResponse createServiceInstance(ProductReqDetails containerDetails, ServiceReqDetails compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.PRODUCT, true); + } + + // Automatically updates the expected req/cap of the container + protected RestResponse deleteAtomicInstanceForVF(String compInstUniqueId, ResourceReqDetails containerDetails, User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.RESOURCE, true); + } + + // Automatically updates the expected req/cap of the container + protected RestResponse deleteAtomicInstanceForService(String compInstUniqueId, ServiceReqDetails containerDetails, User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.SERVICE, true); + } + + // Automatically updates the expected req/cap of the container + protected RestResponse deleteVFInstance(String compInstUniqueId, ServiceReqDetails containerDetails, User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.SERVICE, true); + + } + + // Automatically updates the expected req/cap of the container + protected RestResponse deleteServiceInstance(String compInstUniqueId, ProductReqDetails containerDetails, User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.PRODUCT, true); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + protected RestResponse createAtomicInstanceForVFDuringSetup(ResourceReqDetails containerDetails, ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.RESOURCE, false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + protected RestResponse createAtomicInstanceForServiceDuringSetup(ServiceReqDetails containerDetails, ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + protected RestResponse createVFInstanceDuringSetup(ServiceReqDetails containerDetails, ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + protected RestResponse createServiceInstanceDuringSetup(ProductReqDetails containerDetails, ServiceReqDetails compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.PRODUCT, false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + protected RestResponse deleteAtomicInstanceForVFDuringSetup(String compInstUniqueId, ResourceReqDetails containerDetails, User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.RESOURCE, false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + protected RestResponse deleteAtomicInstanceForServiceDuringSetup(String compInstUniqueId, ServiceReqDetails containerDetails, User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.SERVICE, false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + protected RestResponse deleteVFInstanceDuringSetup(String compInstUniqueId, ServiceReqDetails containerDetails, User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.SERVICE, false); + + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + protected RestResponse deleteServiceInstanceDuringSetup(String compInstUniqueId, ProductReqDetails containerDetails, User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.PRODUCT, false); + } + + protected Component getComponentAndValidateRIs(ComponentReqDetails componentDetails, int numberOfRIs, int numberOfRelations) throws IOException, Exception { + + RestResponse getResponse = null; + Component component = null; + if (componentDetails instanceof ResourceReqDetails) { + getResponse = ResourceRestUtils.getResource(sdncAdminDetails, componentDetails.getUniqueId()); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Resource.class); + } else if (componentDetails instanceof ServiceReqDetails) { + getResponse = ServiceRestUtils.getService((ServiceReqDetails) componentDetails, sdncAdminDetails); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Service.class); + } else if (componentDetails instanceof ProductReqDetails) { + getResponse = ProductRestUtils.getProduct(componentDetails.getUniqueId(), sdncAdminDetails.getUserId()); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Product.class); + } else { + Assert.fail("Unsupported type of componentDetails - " + componentDetails.getClass().getSimpleName()); + } + ResourceRestUtils.checkSuccess(getResponse); + int numberOfActualRIs = component.getComponentInstances() != null ? component.getComponentInstances().size() : 0; + int numberOfActualRelations = component.getComponentInstancesRelations() != null ? component.getComponentInstancesRelations().size() : 0; + assertEquals("Check number of RIs meet the expected number", numberOfRIs, numberOfActualRIs); + assertEquals("Check number of RI relations meet the expected number", numberOfRelations, numberOfActualRelations); + verifyReqCap(component); + + return component; + } + + protected void getComponentAndValidateRIsAfterChangeLifecycleState(String oldComponentUniqueIdToReplace, ComponentReqDetails componentDetails, int numOfRIs, int numOfRelations) throws IOException, Exception { + updateExpectedReqCapAfterChangeLifecycleState(oldComponentUniqueIdToReplace, componentDetails.getUniqueId()); + getComponentAndValidateRIs(componentDetails, numOfRIs, numOfRelations); + } + + private RestResponse createComponentInstance(ComponentReqDetails containerDetails, ComponentReqDetails compInstOriginDetails, User modifier, ComponentTypeEnum containerComponentTypeEnum, boolean isHighestLevel) throws IOException, Exception { + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory.getComponentResourceInstance(compInstOriginDetails); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, modifier, containerDetails.getUniqueId(), containerComponentTypeEnum); + if (createResourceInstanceResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_CREATED) && isHighestLevel) { + // Add RI Capabilities and Requirements to expected MAP --> + // expectedVfCapabilities and expectedVfRequirements + ComponentInstance componentInstance = ResponseParser.parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, containerComponentTypeEnum); + } + return createResourceInstanceResponse; + } + + private RestResponse deleteComponentInstance(String compInstUniqueId, ComponentReqDetails containerDetails, User modifier, ComponentTypeEnum componentTypeEnum, boolean isHighestLevel) throws Exception { + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance(modifier, containerDetails.getUniqueId(), compInstUniqueId, componentTypeEnum); + if (deleteResourceInstanceResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_DELETE) && isHighestLevel) { + deleteCompInstReqCapFromExpected(compInstUniqueId); + } + return deleteResourceInstanceResponse; + } + + // Create Atomic resource ( VFC/CP/VL) + protected void createAtomicResource(ResourceReqDetails resourceDetails) throws Exception { + RestResponse createResourceResponse = ResourceRestUtils.createResource(resourceDetails, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createResourceResponse); + + } + + protected void createVF(ResourceReqDetails resourceDetails) throws Exception { + createVF(resourceDetails, sdncDesignerDetails); + + } + + protected void createVF(ResourceReqDetails resourceDetails, User sdncModifier) throws Exception { + RestResponse createVfResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifier); + ResourceRestUtils.checkCreateResponse(createVfResponse); + } + + protected void createService(ServiceReqDetails serviceDetails) throws Exception { + createService(serviceDetails, sdncDesignerDetails); + } + + protected void createService(ServiceReqDetails serviceDetails, User sdncModifier) throws Exception { + RestResponse createServiceResponse = ServiceRestUtils.createService(serviceDetails, sdncModifier); + ResourceRestUtils.checkCreateResponse(createServiceResponse); + } + + protected void createProduct(ProductReqDetails productDetails) throws Exception { + createProduct(productDetails, sdncPmDetails1); + } + + protected void createProduct(ProductReqDetails productDetails, User sdncModifier) throws Exception { + RestResponse createProductResponse = ProductRestUtils.createProduct(productDetails, sdncModifier); + ResourceRestUtils.checkCreateResponse(createProductResponse); + } + + protected RestResponse associateComponentInstancesForService(RequirementCapabilityRelDef requirementDef, ComponentReqDetails containerDetails, User user) throws IOException { + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, user, containerDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(associateInstances); + deleteAssociatedFromExpected(requirementDef); + + return associateInstances; + } + + private void deleteAssociatedFromExpected(RequirementCapabilityRelDef requirementDef) { + // removing from requirements + RequirementAndRelationshipPair relationship = requirementDef.getRelationships().get(0); + String type = relationship.getRelationship().getType(); + String fromId = requirementDef.getFromNode(); + List reqList = expectedContainerRequirements.get(type); + List capList = expectedContainerCapabilities.get(type); + RequirementDefinition toDelete = null; + if (reqList != null) { + for (RequirementDefinition reqDef : reqList) { + if (reqDef.getOwnerId().equals(fromId)) { + toDelete = reqDef; + } + } + if (toDelete != null) { + reqList.remove(toDelete); + if (reqList.isEmpty()) { + expectedContainerRequirements.remove(type); + } + String ownerId = toDelete.getOwnerId(); + Map> map = removedRequirements.get(ownerId); + if (map == null) { + map = new HashMap<>(); + removedRequirements.put(ownerId, map); + } + List list = map.get(type); + if (list == null) { + list = new ArrayList<>(); + map.put(type, list); + } + list.add(toDelete); + } + } + + for (CapabilityDefinition capabilityDefinition : capList) { + if (capabilityDefinition.getType().equals(type)) { + int minOccurrences = Integer.parseInt(capabilityDefinition.getMinOccurrences()) - 1; + if (minOccurrences < 0) + minOccurrences = 0; + String minOccurrencesString = Integer.toString(minOccurrences); + capabilityDefinition.setMinOccurrences(minOccurrencesString); + if (!capabilityDefinition.getMaxOccurrences().equals("UNBOUNDED")) { + int maxOccurrences = Integer.parseInt(capabilityDefinition.getMaxOccurrences()) - 1; + if (maxOccurrences < 0) + maxOccurrences = 0; + String maxOccurrencesString = Integer.toString(maxOccurrences); + capabilityDefinition.setMaxOccurrences(maxOccurrencesString); + } + } + } + expectedContainerCapabilities.put(type, capList); + } + + protected void dissociateComponentInstancesForService(RequirementCapabilityRelDef requirementDef, ComponentReqDetails containerDetails, User user) throws IOException { + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, user, containerDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(dissociateInstances); + addDissociatedToExpected(requirementDef); + } + + protected void fulfillCpRequirement(ComponentReqDetails component, String cpCompInstId, String cpReqFulfillerCompInstId, String cpReqFulfillerOwnerId, User user, ComponentTypeEnum containerCompType) throws IOException { + // Fulfilling cp's "binding" requirement - US626240 + String requirementName = "binding"; + String capType = "tosca.capabilities.network.Bindable"; + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(user, component); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + RequirementCapabilityRelDef reqCapRelation = ElementFactory.getReqCapRelation(cpCompInstId, cpReqFulfillerCompInstId, cpCompInstId, cpReqFulfillerOwnerId, capType, requirementName, capList, reqList); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(reqCapRelation, user, component.getUniqueId(), containerCompType); + ResourceRestUtils.checkSuccess(associateInstances); + } + + protected void consumeVlCapability(ComponentReqDetails component, String vlCapConsumerCompInstId, String vlCompInstId, String vlCapConsumerOwnerId, User user, ComponentTypeEnum containerCompType) throws IOException { + // Consuming vl's "link" capability - US626240 + String requirementName = "link"; + String capType = "tosca.capabilities.network.Linkable"; + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(user, component); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + RequirementCapabilityRelDef reqCapRelation = ElementFactory.getReqCapRelation(vlCapConsumerCompInstId, vlCompInstId, vlCapConsumerOwnerId, vlCompInstId, capType, requirementName, capList, reqList); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(reqCapRelation, user, component.getUniqueId(), containerCompType); + ResourceRestUtils.checkSuccess(associateInstances); + } + + private void addDissociatedToExpected(RequirementCapabilityRelDef requirementDef) { + // adding to requirements + RequirementAndRelationshipPair relationship = requirementDef.getRelationships().get(0); + String type = relationship.getRelationship().getType(); + String fromId = requirementDef.getFromNode(); + Map> map = removedRequirements.get(fromId); + if (map != null) { + List list = map.get(type); + if (list != null && !list.isEmpty()) { + List reqList = expectedContainerRequirements.get(type); + if (reqList == null) { + reqList = new ArrayList<>(); + expectedContainerRequirements.put(type, reqList); + } + reqList.add(list.remove(0)); + } + } + + List capList = expectedContainerCapabilities.get(type); + + for (CapabilityDefinition capabilityDefinition : capList) { + if (capabilityDefinition.getType().equals(type)) { + int minOccurrences = Integer.parseInt(capabilityDefinition.getMinOccurrences()) + 1; + String minOccurrencesString = Integer.toString(minOccurrences); + capabilityDefinition.setMinOccurrences(minOccurrencesString); + if (!capabilityDefinition.getMaxOccurrences().equals("UNBOUNDED")) { + int maxOccurrences = Integer.parseInt(capabilityDefinition.getMaxOccurrences()) + 1; + String maxOccurrencesString = Integer.toString(maxOccurrences); + capabilityDefinition.setMaxOccurrences(maxOccurrencesString); + } + } + } + expectedContainerCapabilities.put(type, capList); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ExtentManager.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ExtentManager.java new file mode 100644 index 0000000000..2b970fd8a1 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ExtentManager.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.api; + +import org.openecomp.sdc.ci.tests.utils.rest.AutomationUtils; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.reporter.ExtentHtmlReporter; +import com.aventstack.extentreports.reporter.ExtentXReporter; +import com.aventstack.extentreports.reporter.configuration.Protocol; +import com.aventstack.extentreports.reporter.configuration.Theme; + +public class ExtentManager { + + private static ExtentReports extent; + + public synchronized static ExtentReports getReporter(String filePath) { + if (extent == null) { + // initialize the HtmlReporter + ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(filePath); + + // initialize ExtentReports and attach the HtmlReporter + extent = new ExtentReports(); + + // attach all reporters + extent.attachReporter(htmlReporter); + + + } + + return extent; + } + + public synchronized static ExtentHtmlReporter setConfiguration(ExtentHtmlReporter htmlReporter) { + htmlReporter.config().setTheme(Theme.STANDARD); + + htmlReporter.config().setEncoding("UTF-8"); + + htmlReporter.config().setProtocol(Protocol.HTTPS); + + htmlReporter.config().setDocumentTitle("ASDC Automation Report"); + + htmlReporter.config().setChartVisibilityOnOpen(true); + + htmlReporter.config().setReportName(AutomationUtils.getOSVersion()); + + return htmlReporter; + } + + public synchronized static ExtentReports getReporter() { + return extent; + } +} + diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ExtentTestManager.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ExtentTestManager.java new file mode 100644 index 0000000000..9c4acd4367 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/ExtentTestManager.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.api; + +import java.util.HashMap; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.ExtentTest; + + +public class ExtentTestManager { + + private static HashMap extentTestMap = new HashMap(); + private static ExtentReports extent = ExtentManager.getReporter(); + + public static synchronized ExtentTest getTest() { + return extentTestMap.get(Thread.currentThread().getId()); + } + + public static synchronized void endTest() { +// extent.endTest(extentTestMap.get(Thread.currentThread().getId())); +// extentTestMap.get(Thread.currentThread().getId()); // This is test + // TODO: maybe uncomment becuase we will need it only at the end + extent.flush(); + } + + public static synchronized ExtentTest startTest(String testName) { + return startTest(testName, ""); + } + + public static synchronized ExtentTest startTest(String testName, String desc) { + ExtentTest test = extent.createTest(testName, desc); + extentTestMap.put(Thread.currentThread().getId(), test); + + return test; + } +} + diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java new file mode 100644 index 0000000000..3977f16d5a --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/api/Urls.java @@ -0,0 +1,368 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.api; + +public interface Urls { + + final String UPLOAD_ZIP_URL = "http://%s:%s/sdc1/rest/v1/catalog/resources"; + final String GET_IMAGE_DATA_FROM_ES = "http://%s:%s/resources/imagedata/_search?q=resourceName:%s&pretty=true&size=1000"; + final String GET_SCRIPT_DATA_FROM_ES = "http://%s:%s/resources/artifactdata/_search?q=resourceName:%s&pretty=true&size=1000"; + final String GET_ID_LIST_BY_INDEX_FROM_ES = "http://%s:%s/%s/%s/_search?fields=_id&size=1000"; + + final String ES_URL = "http://%s:%s"; + final String GET_SERVICE_CSAR_API1 = "http://%s:%s/sdc2/rest/services/%s/%s"; + final String GET_SERVICE_CSAR_API2 = "http://%s:%s/sdc2/rest/services/%s/%s/csar"; + + final String GET_SERVICE_CSAR_FE_PROXY_API1 = "http://%s:%s/sdc1/portal/rest/services/%s/%s"; + final String GET_CSAR_USING_SIMULATOR = "http://%s:%s/onboardingci/onbrest/onboarding-api/v1.0/vendor-software-products/packages/%s"; + final String COPY_CSAR_USING_SIMULATOR = "http://%s:%s/onboardingci/onbrest/onboarding-api/v1.0/vendor-software-products/packages/%s/%s"; + + final String GET_HEALTH_CHECK_VIA_PROXY = "http://%s:%s/sdc1/rest/healthCheck"; + + // Get back-end config http://172.20.43.132:8080/sdc2/rest/configmgr/get + final String GET_CONFIG_MANAGER = "http://%s:%s/sdc2/rest/configmgr/get"; + + // Get latest version of all non-abstract resources + final String GET_RESOURCE_lATEST_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/resources/latestversion/notabstract"; + + final String GET_SERVICE_lATEST_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/services/latestversion/notabstract"; + + // Get resource artifact list: + // http://172.20.43.124:8080/sdc2/rest/v1/catalog/resources/alien.nodes.Apache/2.0.0-SNAPSHOT/artifacts + final String GET_RESOURCE_ARTIFACTS_LIST = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/%s/artifacts"; + + // get resource artifact metadata (creation, MD5, etc): + // http://172.20.43.124:8080/sdc2/rest/v1/catalog/resources/alien.nodes.Apache/2.0.0-SNAPSHOT/artifacts/install_apache.sh/metadata + final String GET_RESOURCE_ARTIFACT_METADATA = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/%s/artifacts/%s/metadata"; + + // resource artifact payload: + // http://172.20.43.124:8080/sdc2/rest/v1/catalog/resources/alien.nodes.Apache/2.0.0-SNAPSHOT/artifacts/install_apache.sh + final String GET_RESOURCE_ARTIFACT_PAYLOAD = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/%s/artifacts/%s"; + + final String GET_RESOURCE_ARTIFACT_PAYLOAD_FE_PROXY = "http://%s:%s/sdc1/portal/rest/v1/catalog/resources/%s/%s/artifacts/%s"; + + // Get service list: http://172.20.43.124:8080/sdc2/rest/v1/catalog/services + final String GET_SERVICE_LIST = "http://%s:%s/sdc2/rest/v1/catalog/services"; + + // Get service versions: + // http://172.20.43.124:8080/sdc2/rest/v1/catalog/services/MyService + final String GET_SERVICE_VERSIONS = "http://%s:%s/sdc2/rest/v1/catalog/services/%s"; + + // Get service artifact list: + // http://172.20.43.124:8080/sdc2/rest/v1/catalog/services/alien.nodes.Apache/0.0.1/artifacts + final String GET_SERVICE_ARTIFACTS_LIST = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/%s/artifacts"; + + // get service artifact metadata (creation, MD5, etc): + // http://172.20.43.124:8080/sdc2/rest/v1/catalog/services/alien.nodes.Apache/0.0.1/artifacts/install_apache.sh/metadata + final String GET_SERVICE_METADATA = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/%s/artifacts/%s/metadata"; + + // service artifact payload: + // http://172.20.43.124:8080/sdc2/rest/v1/catalog/services/alien.nodes.Apache/0.0.1/artifacts/install_apache.sh + final String GET_SERVICE_ARTIFACT_PAYLOAD = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/%s/artifacts/%s"; + + final String GET_SEARCH_DATA_FROM_ES = "http://%s:%s/%s"; + + // ****************************************************USER + // URLs******************************************************** + final String GET_USER = "http://%s:%s/sdc2/rest/v1/user/%s"; + + final String GET_USER_ROLE = "http://%s:%s/sdc2/rest/v1/user/%s/role"; + + final String CREATE_USER = "http://%s:%s/sdc2/rest/v1/user"; + + final String UPDATE_USER = "http://%s:%s/sdc2/rest/v1/user/%s"; + + final String UPDATE_USER_ROLE = "http://%s:%s/sdc2/rest/v1/user/%s/role"; + + final String DELETE_USER = "http://%s:%s/sdc2/rest/v1/user/%s"; + + final String GET_ALL_ADMIN_USERS = "http://%s:%s/sdc2/rest/v1/user/admins"; + + final String AUTHORIZE_USER = "http://%s:%s/sdc2/rest/v1/user/authorize"; + + final String GET_ALL_TAGS = "http://%s:%s/sdc2/rest/v1/tags"; + + final String AUTH_USER = "http://%s:%s/sdc2/rest/v1/user/authorize"; + + final String GET_ALL_NOT_ABSTRACT_RESOURCES = "http://%s:%s/sdc2/rest/v1/catalog/resources/certified/notabstract"; + + final String GET_ALL_ABSTRACT_RESOURCES = "http://%s:%s/sdc2/rest/v1/catalog/resources/certified/abstract"; + + final String QUERY_NEO4J = "http://%s:%s/db/data/transaction"; + final String CHANGE_IN_NEO4J = "http://%s:%s/db/data/transaction/commit"; + + final String GET_ALL_ADMINS = "http://%s:%s/sdc2/rest/v1/user/admins"; + + final String GET_USERS_BY_ROLES = "http://%s:%s/sdc2/rest/v1/user/users?roles=%s"; + + final String GET_ALL_USERS = "http://%s:%s/sdc2/rest/v1/user/users?roles/"; + + // *****************************************ECOMP User + // URL's***************************************************** + final String ECOMP_PUSH_USER = "http://%s:%s/api/user"; + + final String ECOMP_EDIT_USER = "http://%s:%s/api/user/%s"; + + final String ECOMP_GET_USER = "http://%s:%s/api/user/%s"; + + final String ECOMP_GET_ALL_USERS = "http://%s:%s/api/users"; + + final String ECOMP_GET_ALL_AVAILABLE_ROLES = "http://%s:%s/api/roles"; + + final String ECOMP_PUSH_USER_ROLES = "http://%s:%s/api/user/%s/roles"; + + final String ECOMP_GET_USER_ROLES = "http://%s:%s/api/user/%s/roles"; + + // *****************************************Elements************************************************************* + final String GET_TAGS_LIST = "http://%s:%s/sdc2/rest/v1/tags"; + + final String GET_PROPERTY_SCOPES_LIST = "http://%s:%s/sdc2/rest/v1/propertyScopes"; + + final String GET_CONFIGURATION = "http://%s:%s/sdc2/rest/v1/configuration/ui"; + + final String GET_ALL_ARTIFACTS = "http://%s:%s/sdc2/rest/v1/artifactTypes"; + + final String GET_FOLLWED_LIST = "http://%s:%s/sdc2/rest/v1/followed"; + + final String GET_CATALOG_DATA = "http://%s:%s/sdc2/rest/v1/screen"; + + // *****************************************Resources + // ********************************************************************** + final String GET_LIST_CERTIFIED_RESOURCE_TEMPLATES = "http://%s:%s/sdc2/rest/v1/resoourceTemplates"; + + final String CREATE_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources"; + final String UPDATE_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s"; + + final String IMPORT_RESOURCE_NORMATIVE = "http://%s:%s/sdc2/rest/v1/catalog/upload/multipart"; + + final String IMPORT_USER_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/upload/user-resource"; + + final String IMPORT_CAPABILITY_TYPE = "http://%s:%s/sdc2/rest/v1/catalog/uploadType/capability"; + final String IMPORT_CATEGORIES = "http://%s:%s/sdc2/rest/v1/catalog/uploadType/categories"; + final String IMPORT_GROUP_TYPE = "http://%s:%s/sdc2/rest/v1/catalog/uploadType/grouptypes"; + + // last %s is resourceId, resourceId = resourceName.resourceVersion + final String GET_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s"; + final String GET_RESOURCE_BY_NAME_AND_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/resources/resourceName/%s/resourceVersion/%s"; + final String GET_RESOURCE_BY_CSAR_UUID = "http://%s:%s/sdc2/rest/v1/catalog/resources/csar/%s"; + final String GET_COMPONENT_REQUIRMENTS_CAPABILITIES = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/requirmentsCapabilities"; + + final String DELETE_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s"; + final String DELETE_RESOURCE_BY_NAME_AND_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/%s"; + final String DELETE_SERVICE_BY_NAME_AND_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/%s"; + + final String DELETE_MARKED_RESOURCES = "http://%s:%s/sdc2/rest/v1/inactiveComponents/resource"; + final String DELETE_MARKED_SERVICES = "http://%s:%s/sdc2/rest/v1/inactiveComponents/service"; + + final String GET_FOLLOWED_RESOURCES = "http://%s:%s/sdc2/rest/v1/followed/resources/%s"; + final String CHANGE_RESOURCE_LIFECYCLE_STATE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/lifecycleState/%s"; + final String CHANGE_SERVICE_LIFECYCLE_STATE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/lifecycleState/%s"; + final String CHANGE_PRODUCT_LIFECYCLE_STATE = "http://%s:%s/sdc2/rest/v1/catalog/products/%s/lifecycleState/%s"; + final String CHANGE_COMPONENT_LIFECYCLE_STATE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/lifecycleState/%s"; + + final String CREATE_PROPERTY = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/properties"; + + final String UPDATE_RESOURCE_METADATA = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/metadata"; + + // ***********************************External API's + // (AssetData)**************************************** + + final String DELETE_EXTRNAL_API_DELETE_ARTIFACT_OF_ASSET = "http://%s:%s/sdc/v1/catalog/%s/%s/artifacts/%s"; + final String DELETE_EXTRNAL_API_DELETE_ARTIFACT_OF_COMPONENTINSTANCE_ON_ASSET = "http://%s:%s/sdc/v1/catalog/%s/%s/resourceInstances/%s/artifacts/%s"; + + final String POST_EXTERNAL_API_UPDATE_ARTIFACT_OF_ASSET = "http://%s:%s/sdc/v1/catalog/%s/%s/artifacts/%s"; + final String POST_EXTERNAL_API_UPDATE_ARTIFACT_OF_COMPONENTINSTANCE_ON_ASSET = "http://%s:%s/sdc/v1/catalog/%s/%s/resourceInstances/%s/artifacts/%s"; + + final String POST_EXTERNAL_API_UPLOAD_ARTIFACT_OF_ASSET = "http://%s:%s/sdc/v1/catalog/%s/%s/artifacts"; + final String POST_EXTERNAL_API_UPLOAD_ARTIFACT_OF_COMPONENTINSTANCE_ON_ASSET = "http://%s:%s/sdc/v1/catalog/%s/%s/resourceInstances/%s/artifacts"; + + final String GET_DOWNLOAD_RESOURCE_ARTIFACT_OF_ASSET = "http://%s:%s/sdc/v1/catalog/resources/%s/artifacts/%s"; + final String GET_DOWNLOAD_SERVICE_ARTIFACT_OF_ASSET = "http://%s:%s/sdc/v1/catalog/services/%s/artifacts/%s"; + + final String GET_DOWNLOAD_RESOURCE_ARTIFACT_OF_COMPONENT_INSTANCE = "http://%s:%s/sdc/v1/catalog/resources/%s/resourceInstances/%s/artifacts/%s"; + final String GET_DOWNLOAD_SERVICE_ARTIFACT_OF_COMPONENT_INSTANCE = "http://%s:%s/sdc/v1/catalog/services/%s/resourceInstances/%s/artifacts/%s"; + + final String GET_ASSET_LIST = "http://%s:%s/sdc/v1/catalog/%s"; + final String GET_FILTERED_ASSET_LIST = "http://%s:%s/sdc/v1/catalog/%s?%s"; + final String GET_TOSCA_MODEL = "http://%s:%s/sdc/v1/catalog/%s/%s/toscaModel"; + // https://{serverRoot}/sdc/v1/catalog/{assetType}/{uuid}/metadata, where + // assetType in {resources, services} + final String GET_ASSET_METADATA = "http://%s:%s/sdc/v1/catalog/%s/%s/metadata"; + final String POST_AUTHORIZATION = "http://%s:%s/sdc2/rest/v1/consumers"; + final String GET_DOWNLOAD_SERVICE_RI_ARTIFACT = "http://%s:%s/sdc/v1/catalog/services/%s/resourceInstances/%s/artifacts/%s"; + final String GET_DOWNLOAD_SERVICE_ARTIFACT = "http://%s:%s/sdc/v1/catalog/services/%s/artifacts/%s"; + + final String POST_EXTERNAL_API_CREATE_RESOURCE = "http://%s:%s/sdc/v1/catalog/resources"; + + // Change LifeCycle of Resource + // https://{serverRoot}:{port}/sdc/v1/catalog/{resources|services}/{uuid}/lifecycleState/{lifecycle state} + final String POST_EXTERNAL_API_CHANGE_LIFE_CYCLE_OF_ASSET = "http://%s:%s/sdc/v1/catalog/%s/%s/lifecycleState/%s"; + + + // ***************************************************************************************************** + + final String ADD_ARTIFACT_TO_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/artifacts"; + final String UPDATE_OR_DELETE_ARTIFACT_OF_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/artifacts/%s"; + final String ADD_ARTIFACT_TO_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/artifacts"; + final String UPDATE_OR_DELETE_ARTIFACT_OF_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/artifacts/%s"; + + final String UPLOAD_DELETE_ARTIFACT_OF_COMPONENT = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/artifacts"; + final String UPDATE_ARTIFACT_OF_COMPONENT = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/artifacts/%s"; + final String UPLOAD_HEAT_ENV_ARTIFACT = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/%s/artifacts/%s"; + // ***************************************************************************************************** + final String UPLOAD_ARTIFACT_BY_INTERFACE_TO_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/%s/%s/artifacts/"; + final String UPDATE_OR_DELETE_ARTIFACT_BY_INTERFACE_TO_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/%s/%s/artifacts/%s"; + + final String UPLOAD_ARTIFACT_BY_INTERFACE_TO_COMPONENT = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/%s/%s/artifacts/"; + final String UPDATE_OR_DELETE_ARTIFACT_BY_INTERFACE_TO_COMPONENT = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/%s/%s/artifacts/%s"; + + // ***************************************************************************************************** + // "/sdc2/v1/services//<0.1>/artifacts/aaa.hh" + final String DISTRIB_DOWNLOAD_SERVICE_ARTIFACT = "/sdc2/rest/v1/catalog/services/%s/%s/artifacts/%s"; + // "/sdc2/v1/services//<0.1>/resources/{resourceName}/{resourceVersion}/artifacts/_aaa.hh" + final String DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT = "/sdc2/rest/v1/catalog/services/%s/%s/resources/%s/%s/artifacts/%s"; + final String DISTRIB_DOWNLOAD_SERVICE_ARTIFACT_RELATIVE_URL = "/sdc/v1/catalog/services/%s/%s/artifacts/%s"; + final String DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT_RELATIVE_URL = "/sdc/v1/catalog/services/%s/%s/resources/%s/%s/artifacts/%s"; + final String DOWNLOAD_SERVICE_ARTIFACT_FULL_URL = "http://%s:%s%s"; + final String DOWNLOAD_RESOURCE_ARTIFACT_FULL_URL = "http://%s:%s%s"; + // ********************************************************************************** + final String UI_DOWNLOAD_RESOURCE_ARTIFACT = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/artifacts/%s"; + final String UI_DOWNLOAD_SERVICE_ARTIFACT = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/artifacts/%s"; + + // ********************************************************************************************************** + final String UPDATE_PROPERTY = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/properties/%s"; + + final String DELETE_PROPERTY = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/properties/%s"; + + final String GET_PROPERTY = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/properties/%s"; + + // ***************************************************************************************************** + + final String VALIDATE_RESOURCE_NAME = "http://%s:%s/sdc2/rest/v1/catalog/resources/validate-name/%s"; + + final String CREATE_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services"; + final String DELETE_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s"; + final String GET_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s"; + final String GET_SERVICE_BY_NAME_AND_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/services/serviceName/%s/serviceVersion/%s"; + + final String GET_SERVICES_REQUIRMENTS_CAPABILITIES = "http://%s:%s/sdc2/rest/v1/catalog/requirmentsCapabilities/services/%s"; + + final String CREATE_COMPONENT_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance"; + final String DELETE_COMPONENT_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/%s"; + final String UPDATE_COMPONENT_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/%s"; + final String GET_COMPONENT_INSTANCES = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/componentInstances"; + // Tal New API + final String UPDATE_MULTIPLE_COMPONENT_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/multipleComponentInstance"; + + final String CHANGE__RESOURCE_INSTANCE_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/%s/changeVersion"; + + final String CREATE_AND_ASSOCIATE_RESOURCE_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/resourceInstance/createAndAssociate"; + final String ASSOCIATE__RESOURCE_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/associate"; + final String DISSOCIATE__RESOURCE_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/dissociate"; + + final String DISTRIBUTION_INIT = "http://%s:%s/init"; + final String DISTRIBUTION_INIT_RESET = "http://%s:%s/initReset"; + final String APPROVE_DISTRIBUTION = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/distribution-state/approve"; + final String REJECT_DISTRIBUTION = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/distribution-state/reject"; + final String DISTRIBUTION_DOWNLOAD_ARTIFACT = "http://%s:%s/download"; + final String ACTIVATE_DISTRIBUTION = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/distribution/%s/activate"; + final String DISTRIBUTION_SERVICE_LIST = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/distribution"; + + final String DEPLOY_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/distribution/%s/markDeployed"; + final String UPDATE_SERVICE_METADATA = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/metadata"; + + // Andrey changed name from ADD_PROPERTY_TO_RESOURCE_INSTANCE to + // UPDATE_PROPERTY_TO_RESOURCE_INSTANCE + final String UPDATE_PROPERTY_TO_RESOURCE_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/%s/property"; + final String DELETE_PROPERTY_FROM_RESOURCE_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/resourceInstance/%s/property/%s"; + final String UPDATE_RESOURCE_INSTANCE_HEAT_ENV_PARAMS = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/resourceInstance/%s/artifacts/%s/heatParams"; + + // Actions on artifact in resource instance + final String ADD_RESOURCE_INSTANCE_ARTIFACT = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/resourceInstance/%s/artifacts"; + final String UPDATE_RESOURCE_INSTANCE_ARTIFACT = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/resourceInstance/%s/artifacts/%s"; + final String DELETE_RESOURCE_INSTANCE_ARTIFACT = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/resourceInstance/%s/artifacts/%s"; + + // Attributes On Resource instance + public static final String UPDATE_ATTRIBUTE_ON_RESOURCE_INSTANCE = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/resourceInstance/%s/attribute"; + + // ("/services/{serviceId}/resourceInstances/{resourceInstanceId}/artifacts/{artifactId}") + final String DOWNLOAD_COMPONENT_INSTANCE_ARTIFACT = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/resourceInstances/%s/artifacts/%s"; + + // -------------------------------service api + // artifact----------------------------------------------------- + final String UPDATE_DELETE_SERVICE_API_ARTIFACT = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/artifacts/api/%s"; + + final String CREATE_ADDITIONAL_INFORMATION_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/additionalinfo"; + final String UPDATE_ADDITIONAL_INFORMATION_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/additionalinfo/%s"; + final String DELETE_ADDITIONAL_INFORMATION_RESOURCE = UPDATE_ADDITIONAL_INFORMATION_RESOURCE; + final String GET_ADDITIONAL_INFORMATION_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/additionalinfo/%s"; + final String GET_ALL_ADDITIONAL_INFORMATION_RESOURCE = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/additionalinfo"; + + final String CREATE_ADDITIONAL_INFORMATION_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/additionalinfo"; + final String UPDATE_ADDITIONAL_INFORMATION_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/additionalinfo/%s"; + final String DELETE_ADDITIONAL_INFORMATION_SERVICE = UPDATE_ADDITIONAL_INFORMATION_SERVICE; + final String GET_ADDITIONAL_INFORMATION_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/additionalinfo/%s"; + final String GET_ALL_ADDITIONAL_INFORMATION_SERVICE = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/additionalinfo"; + + final String GET_COMPONENT_AUDIT_RECORDS = "http://%s:%s/sdc2/rest/v1/catalog/audit-records/%s/%s"; + + // CONSUMER + final String CREATE_CONSUMER = "http://%s:%s/sdc2/rest/v1/consumers"; + final String GET_CONSUMER = "http://%s:%s/sdc2/rest/v1/consumers/%s"; + final String DELETE_CONSUMER = "http://%s:%s/sdc2/rest/v1/consumers/%s"; + + // Categories + final String CREATE_CATEGORY = "http://%s:%s/sdc2/rest/v1/category/%s"; + final String GET_ALL_CATEGORIES = "http://%s:%s/sdc2/rest/v1/categories/%s"; + final String GET_ALL_CATEGORIES_FE = "http://%s:%s/sdc1/feProxy/rest/v1/categories/%s"; + final String DELETE_CATEGORY = "http://%s:%s/sdc2/rest/v1/category/%s/%s"; + final String CREATE_SUB_CATEGORY = "http://%s:%s/sdc2/rest/v1/category/%s/%s/subCategory"; + final String DELETE_SUB_CATEGORY = "http://%s:%s/sdc2/rest/v1/category/%s/%s/subCategory/%s"; + final String CREATE_GROUPING = "http://%s:%s/sdc2/rest/v1/category/%s/%s/subCategory/%s/grouping"; + final String DELETE_GROUPING = "http://%s:%s/sdc2/rest/v1/category/%s/%s/subCategory/%s/grouping/%s"; + + // product + final String CREATE_PRODUCT = "http://%s:%s/sdc2/rest/v1/catalog/products"; + final String DELETE_PRODUCT = "http://%s:%s/sdc2/rest/v1/catalog/products/%s"; + // last %s is resourceId, productId + final String GET_PRODUCT = "http://%s:%s/sdc2/rest/v1/catalog/products/%s"; + final String UPDATE_PRODUCT = "http://%s:%s/sdc2/rest/v1/catalog/products/%s/metadata"; + final String GET_PRODUCT_BY_NAME_AND_VERSION = "http://%s:%s/sdc2/rest/v1/catalog/products/productName/%s/productVersion/%s"; + + // groups + final String GET_GROUP_BY_ID = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/groups/%s"; + + // modules + final String GET_MODULE_BY_ID = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/groups/%s"; + + // inputs + final String ADD_INPUTS = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/create/inputs"; //{componentType}/{componentId}/create/inputs + final String DELETE_INPUT_BY_ID = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/delete/%s/input"; //{componentType}/{componentId}/delete/{inputId}/input + final String GET_COMPONENT_INPUTS = "http://%s:%s/sdc2/rest/v1/catalog/services/%s/inputs"; //services/{componentId}/inputs + final String GET_COMPONENT_INSTANCE_INPUTS = "http://%s:%s/sdc2/rest/v1/catalog/%s/%s/componentInstances/%s/%s/inputs"; //{componentType}/{componentId}/componentInstances/{instanceId}/{originComonentUid}/inputs + final String GET_INPUTS_FOR_COMPONENT_INPUT = "http://%s:%s/sdc2/rest/v1/catalog/resources/%s/groups/%s"; //{componentType}/{componentId}/inputs/{inputId}/inputs + + // check version + final String ONBOARD_VERSION = "http://%s:%s/onboarding-api/docs/build-info.json"; + final String OS_VERSION = "http://%s:%s/sdc2/rest/version"; + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/config/Config.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/config/Config.java new file mode 100644 index 0000000000..d2e8d14c04 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/config/Config.java @@ -0,0 +1,696 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.config; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +import org.yaml.snakeyaml.Yaml; + +public class Config { + + private static String WINDOWS_CONFIG_FILE = "src/main/resources/ci/conf/attsdc.yaml"; + private boolean systemUnderDebug; + private boolean rerun; + private String reportDBhost; + private int reportDBport; + + private String browser; + private String catalogBeHost; + private String esHost; + private String esPort; + private String neoHost; + private String neoPort; + private String disributionClientHost; + private String disributionClientPort; + private boolean isDistributionClientRunning; + + + private String errorConfigurationFile; + private String resourceConfigDir; + private String componentsConfigDir; + private String importResourceConfigDir; + private String importResourceTestsConfigDir; + private String importTypesConfigDir; + + private String testSuites; + + private String catalogFeHost; + private String catalogFePort; + private String catalogBePort; + private String catalogBeTlsPort; + + private String neoDBusername; + private String neoDBpassword; + + private String titanPropertiesFile; + private List packages; + private List bugs; + private List resourcesNotToDelete; + private List resourceCategoriesNotToDelete; + private List serviceCategoriesNotToDelete; + private boolean stopOnClassFailure = false; + + private String outputFolder; + private String reportName; + private String url; + private String remoteTestingMachineIP; + private String remoteTestingMachinePort; + private boolean remoteTesting; + + private String cassandraHost; + private String cassandraAuditKeySpace; + private String cassandraArtifactKeySpace; + private boolean cassandraAuthenticate; + private String cassandraUsername; + private String cassandraPassword; + private boolean cassandraSsl; + private String cassandraTruststorePath; + private String cassandraTruststorePassword; + private String windowsDownloadDirectory; + private boolean captureTraffic; + private boolean useBrowserMobProxy; + + private static Config configIt = null; + + private static Yaml yaml = new Yaml(); + + + private Config() { + super(); + } + + public static class TestPackages { + + List packages; + List bugs; + + public List getPackages() { + return packages; + } + + public void setPackages(List packages) { + this.packages = packages; + } + + public List getBugs() { + return bugs; + } + + public void setBugs(List bugs) { + this.bugs = bugs; + } + + @Override + public String toString() { + return "TestPackages [packages=" + packages + ", bugs=" + bugs + "]"; + } + + } + + public synchronized static Config instance() { + if (configIt == null) { + try { + configIt = init(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + return configIt; + } + + private static Config init() throws IOException { + + Config config = null; + + String configFile = System.getProperty("config.resource"); + if (configFile == null) { + if (System.getProperty("os.name").contains("Windows")) { + configFile = WINDOWS_CONFIG_FILE; + } else { + throw new RuntimeException("Please Add Jvm Argument config.resource"); + } + } + + File file = new File(configFile); + if (false == file.exists()) { + throw new RuntimeException("The config file " + configFile + " cannot be found."); + } + + InputStream in = null; + try { + + in = Files.newInputStream(Paths.get(configFile)); + + config = yaml.loadAs(in, Config.class); + + setPackagesAndBugs(configFile, config); + + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + // JsonReader jsonReader = new JsonReader(new FileReader(configFile)); + // Config configAttOdlIt = new Gson().fromJson(jsonReader, + // Config.class); + + return config; + } + + private static void setPackagesAndBugs(String path, Config config) throws IOException { + + int separator = Math.max(path.lastIndexOf("\\"), path.lastIndexOf("/")); + String dirPath = path.substring(0, separator + 1); + String packagesFile = dirPath + File.separator + "attsdc-packages.yaml"; + File file = new File(packagesFile); + if (false == file.exists()) { + throw new RuntimeException("The config file " + packagesFile + " cannot be found."); + } + + TestPackages testPackages = null; + InputStream in = null; + try { + + in = Files.newInputStream(Paths.get(packagesFile)); + + testPackages = yaml.loadAs(in, TestPackages.class); + + List bugs = testPackages.getBugs(); + List packages = testPackages.getPackages(); + + config.setBugs(bugs); + config.setPackages(packages); + + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + } + + // public Config(String catalogBeHost, String esHost, String esPort, String + // resourceConfigDir, String componentsConfigDir, String catalogFeHost, + // String catalogFePort, String catalogBePort) { + // super(); + // this.catalogBeHost = catalogBeHost; + // this.esHost = esHost; + // this.esPort = esPort; + // this.resourceConfigDir = resourceConfigDir; + // this.componentsConfigDir = componentsConfigDir; + // this.catalogFeHost = catalogFeHost; + // this.catalogFePort = catalogFePort; + // this.catalogBePort = catalogBePort; + // } + + String configurationFile; + + public boolean getSystemUnderDebug() { + return systemUnderDebug; + } + + public void setSystemUnderDebug(boolean systemUnderDebug) { + this.systemUnderDebug = systemUnderDebug; + } + + public boolean getRerun() { + return rerun; + } + + public void setRerun(boolean rerun) { + this.rerun = rerun; + } + + public String getReportDBhost() { + return reportDBhost; + } + + public void setReportDBhost(String reportDBhost) { + this.reportDBhost = reportDBhost; + } + + public int getReportDBport() { + return reportDBport; + } + + public void setReportDBport(int reportDBport) { + this.reportDBport = reportDBport; + } +// public boolean isUsingBrowserMobProxy() { +// return useBrowserMobProxy; +// } +// +// public void setUsingBrowserMobProxy(boolean usingBrowserMobProxy) { +// this.useBrowserMobProxy = usingBrowserMobProxy; +// } + + + + + public String getBrowser() { + return browser; + } + + public boolean getUseBrowserMobProxy() { + return useBrowserMobProxy; + } + + public void setUseBrowserMobProxy(boolean useBrowserMobProxy) { + this.useBrowserMobProxy = useBrowserMobProxy; + } + + + + public boolean getCaptureTraffic() { + return captureTraffic; + } + + public void setCaptureTraffic(boolean captureTraffic) { + this.captureTraffic = captureTraffic; + } + + public void setBrowser(String browser) { + this.browser = browser; + } + + public String getConfigurationFile() { + return configurationFile; + } + + public void setConfigurationFile(String configurationFile) { + this.configurationFile = configurationFile; + } + + public boolean getIsDistributionClientRunning() { + return isDistributionClientRunning; + } + + public void setIsDistributionClientRunning(boolean isDistributionClientRunning) { + this.isDistributionClientRunning = isDistributionClientRunning; + } + + public String getCatalogBePort() { + return catalogBePort; + } + + public String getDisributionClientHost() { + return disributionClientHost; + } + + public void setDisributionClientHost(String disributionClientHost) { + this.disributionClientHost = disributionClientHost; + } + + public String getDisributionClientPort() { + return disributionClientPort; + } + + public void setDisributionClientPort(String disributionClientPort) { + this.disributionClientPort = disributionClientPort; + } + + public void setCatalogBePort(String catalogBePort) { + this.catalogBePort = catalogBePort; + } + + public String getCatalogFeHost() { + return catalogFeHost; + } + + public void setCatalogFeHost(String catalogFeHost) { + this.catalogFeHost = catalogFeHost; + } + + public String getCatalogFePort() { + return catalogFePort; + } + + public void setCatalogFePort(String catalogFePort) { + this.catalogFePort = catalogFePort; + } + + public String getCatalogBeHost() { + return catalogBeHost; + } + + public void setCatalogBeHost(String catalogBeHost) { + this.catalogBeHost = catalogBeHost; + } + + public String getEsHost() { + return esHost; + } + + public void setEsHost(String esHost) { + this.esHost = esHost; + } + + public String getEsPort() { + return esPort; + } + + public void setEsPort(String esPort) { + this.esPort = esPort; + } + + public String getResourceConfigDir() { + return resourceConfigDir; + } + + public void setResourceConfigDir(String resourceConfigDir) { + this.resourceConfigDir = resourceConfigDir; + } + + public String getComponentsConfigDir() { + return componentsConfigDir; + } + + public void setComponentsConfigDir(String componentsConfigDir) { + this.componentsConfigDir = componentsConfigDir; + } + + public String getOutputFolder() { + return outputFolder; + } + + public void setOutputFolder(String outputFolder) { + this.outputFolder = outputFolder; + } + + public String getReportName() { + return reportName; + } + + public void setReportName(String reportName) { + this.reportName = reportName; + } + + public String getNeoPort() { + return neoPort; + } + + public void setNeoPort(String neoPort) { + this.neoPort = neoPort; + } + + public String getNeoHost() { + return neoHost; + } + + public void setNeoHost(String neoHost) { + this.neoHost = neoHost; + } + + public String getNeoDBpassword() { + return neoDBpassword; + } + + public String getNeoDBusername() { + return neoDBusername; + } + + public void setNeoDBusername(String neoDBusername) { + this.neoDBusername = neoDBusername; + } + + public void setNeoDBpassword(String neoDBpassword) { + this.neoDBpassword = neoDBpassword; + } + + public String getTitanPropertiesFile() { + return titanPropertiesFile; + } + + public void setTitanPropertiesFile(String titanPropertiesFile) { + this.titanPropertiesFile = titanPropertiesFile; + } + + public List getPackages() { + return packages; + } + + public void setPackages(List packages) { + this.packages = packages; + } + + public List getBugs() { + return bugs; + } + + public void setBugs(List bugs) { + this.bugs = bugs; + } + + public boolean isStopOnClassFailure() { + return stopOnClassFailure; + } + + public void setStopOnClassFailure(boolean stopOnClassFailure) { + this.stopOnClassFailure = stopOnClassFailure; + } + + public String getImportResourceConfigDir() { + return importResourceConfigDir; + } + + public void setImportResourceConfigDir(String importResourceConfigDir) { + this.importResourceConfigDir = importResourceConfigDir; + } + + public String getImportResourceTestsConfigDir() { + return importResourceTestsConfigDir; + } + + public void setImportResourceTestsConfigDir(String importResourceTestsConfigDir) { + this.importResourceTestsConfigDir = importResourceTestsConfigDir; + } + + public String getErrorConfigurationFile() { + return errorConfigurationFile; + } + + public void setErrorConfigurationFile(String errorConfigurationFile) { + this.errorConfigurationFile = errorConfigurationFile; + } + + public String getCatalogBeTlsPort() { + return catalogBeTlsPort; + } + + public void setCatalogBeTlsPort(String catalogBeTlsPort) { + this.catalogBeTlsPort = catalogBeTlsPort; + } + + public List getResourcesNotToDelete() { + return resourcesNotToDelete; + } + + public void setResourcesNotToDelete(List resourcesNotToDelete) { + this.resourcesNotToDelete = resourcesNotToDelete; + } + + public List getResourceCategoriesNotToDelete() { + return resourceCategoriesNotToDelete; + } + + public void setResourceCategoriesNotToDelete(List resourceCategoriesNotToDelete) { + this.resourceCategoriesNotToDelete = resourceCategoriesNotToDelete; + } + + public List getServiceCategoriesNotToDelete() { + return serviceCategoriesNotToDelete; + } + + public void setServiceCategoriesNotToDelete(List serviceCategoriesNotToDelete) { + this.serviceCategoriesNotToDelete = serviceCategoriesNotToDelete; + } + + public String getImportTypesConfigDir() { + return importTypesConfigDir; + } + + public void setImportTypesConfigDir(String importTypesConfigDir) { + this.importTypesConfigDir = importTypesConfigDir; + } + + public String getCassandraHost() { + return cassandraHost; + } + + public void setCassandraHost(String cassandraHost) { + this.cassandraHost = cassandraHost; + } + + public String getCassandraAuditKeySpace() { + return cassandraAuditKeySpace; + } + + public void setCassandraAuditKeySpace(String cassandraAuditKeySpace) { + this.cassandraAuditKeySpace = cassandraAuditKeySpace; + } + + public String getCassandraArtifactKeySpace() { + return cassandraArtifactKeySpace; + } + + public void setCassandraArtifactKeySpace(String cassandraArtifactKeySpace) { + this.cassandraArtifactKeySpace = cassandraArtifactKeySpace; + } + + + public String getWindowsDownloadDirectory() { + return windowsDownloadDirectory; + } + + public void setWindowsDownloadDirectory(String windowsDownloadDirectory) { + this.windowsDownloadDirectory = windowsDownloadDirectory; + } + + @Override + public String toString() { + return "Config [systemUnderDebug=" + systemUnderDebug + ", rerun=" + rerun + ", reportDBhost=" + reportDBhost + + ", reportDBport=" + reportDBport + ", browser=" + browser + ", catalogBeHost=" + catalogBeHost + + ", esHost=" + esHost + ", esPort=" + esPort + ", neoHost=" + neoHost + ", neoPort=" + neoPort + + ", disributionClientHost=" + disributionClientHost + ", disributionClientPort=" + + disributionClientPort + ", isDistributionClientRunning=" + isDistributionClientRunning + + ", errorConfigurationFile=" + errorConfigurationFile + ", resourceConfigDir=" + resourceConfigDir + + ", componentsConfigDir=" + componentsConfigDir + ", importResourceConfigDir=" + + importResourceConfigDir + ", importResourceTestsConfigDir=" + importResourceTestsConfigDir + + ", importTypesConfigDir=" + importTypesConfigDir + ", testSuites=" + testSuites + ", catalogFeHost=" + + catalogFeHost + ", catalogFePort=" + catalogFePort + ", catalogBePort=" + catalogBePort + + ", catalogBeTlsPort=" + catalogBeTlsPort + ", neoDBusername=" + neoDBusername + ", neoDBpassword=" + + neoDBpassword + ", titanPropertiesFile=" + titanPropertiesFile + ", packages=" + packages + ", bugs=" + + bugs + ", resourcesNotToDelete=" + resourcesNotToDelete + ", resourceCategoriesNotToDelete=" + + resourceCategoriesNotToDelete + ", serviceCategoriesNotToDelete=" + serviceCategoriesNotToDelete + + ", stopOnClassFailure=" + stopOnClassFailure + ", outputFolder=" + outputFolder + ", reportName=" + + reportName + ", url=" + url + ", remoteTestingMachineIP=" + remoteTestingMachineIP + + ", remoteTestingMachinePort=" + remoteTestingMachinePort + ", remoteTesting=" + remoteTesting + + ", cassandraHost=" + cassandraHost + ", cassandraAuditKeySpace=" + cassandraAuditKeySpace + + ", cassandraArtifactKeySpace=" + cassandraArtifactKeySpace + ", cassandraAuthenticate=" + + cassandraAuthenticate + ", cassandraUsername=" + cassandraUsername + ", cassandraPassword=" + + cassandraPassword + ", cassandraSsl=" + cassandraSsl + ", cassandraTruststorePath=" + + cassandraTruststorePath + ", cassandraTruststorePassword=" + cassandraTruststorePassword + + ", windowsDownloadDirectory=" + windowsDownloadDirectory + ", captureTraffic=" + captureTraffic + + ", useBrowserMobProxy=" + useBrowserMobProxy + ", configurationFile=" + configurationFile + "]"; + } + + public boolean isRemoteTesting() { + return remoteTesting; + } + + public void setRemoteTesting(boolean remoteTesting) { + this.remoteTesting = remoteTesting; + } + + public String getUrl() { + try { + return url; + } catch (Exception e) { + return null; + } + } + + public void setUrl(String url) { + this.url = url; + } + + public String getRemoteTestingMachineIP() { + return remoteTestingMachineIP; + } + + public void setRemoteTestingMachineIP(String remoteTestingMachineIP) { + this.remoteTestingMachineIP = remoteTestingMachineIP; + } + + public String getRemoteTestingMachinePort() { + return remoteTestingMachinePort; + } + + public void setRemoteTestingMachinePort(String remoteTestingMachinePort) { + this.remoteTestingMachinePort = remoteTestingMachinePort; + } + + public boolean getCassandraAuthenticate() { + return cassandraAuthenticate; + } + + public void setCassandraAuthenticate(boolean cassandraAuthenticate) { + this.cassandraAuthenticate = cassandraAuthenticate; + } + + public String getCassandraUsername() { + return cassandraUsername; + } + + public void setCassandraUsername(String cassandraUsername) { + this.cassandraUsername = cassandraUsername; + } + + public String getCassandraPassword() { + return cassandraPassword; + } + + public void setCassandraPassword(String cassandraPassword) { + this.cassandraPassword = cassandraPassword; + } + + public boolean getCassandraSsl() { + return cassandraSsl; + } + + public void setCassandraSsl(boolean cassandraSsl) { + this.cassandraSsl = cassandraSsl; + } + + public String getCassandraTruststorePath() { + return cassandraTruststorePath; + } + + public void setCassandraTruststorePath(String cassandraTruststorePath) { + this.cassandraTruststorePath = cassandraTruststorePath; + } + + public String getCassandraTruststorePassword() { + return cassandraTruststorePassword; + } + + public void setCassandraTruststorePassword(String cassandraTruststorePassword) { + this.cassandraTruststorePassword = cassandraTruststorePassword; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/config/InvokedMethodListener.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/config/InvokedMethodListener.java new file mode 100644 index 0000000000..fbc493ffd6 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/config/InvokedMethodListener.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.config; + +import java.util.HashMap; +import java.util.Map; + +import org.testng.IInvokedMethod; +import org.testng.IInvokedMethodListener; +import org.testng.ITestResult; +import org.testng.SkipException; +import org.testng.internal.TestResult; + +public class InvokedMethodListener implements IInvokedMethodListener { + + static Map methodFailCount = new HashMap(); + + @Override + + public void beforeInvocation(IInvokedMethod method, ITestResult testResult) { + + if (methodFailCount.get(method.getTestMethod().getMethodName()) != null + && methodFailCount.get(method.getTestMethod().getMethodName()) > 1) + throw new SkipException("Skipped due to failure count > 1"); + ; + + } + + @Override + + public void afterInvocation(IInvokedMethod method, ITestResult testResult) { + + if (testResult.getStatus() == TestResult.FAILURE) { + if (methodFailCount.get(method.getTestMethod().getMethodName()) == null) + methodFailCount.put(method.getTestMethod().getMethodName(), 1); + else { + methodFailCount.put(method.getTestMethod().getMethodName(), + methodFailCount.get(method.getTestMethod().getMethodName()) + 1); + } + + } + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactAssetStructure.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactAssetStructure.java new file mode 100644 index 0000000000..41936e2c30 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactAssetStructure.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class ArtifactAssetStructure { + + String artifactName; + String artifactType; + String artifactURL; + String artifactDescription; + int artifactTimeout;// optional + String artifactChecksum; + String artifactUUID; + String artifactVersion; + String generatedFromUUID;// optional + + public ArtifactAssetStructure(String artifactName, String artifactType, String artifactURL, + String artifactDescription, int artifactTimeout, String artifactChecksum, String artifactUUID, + String artifactVersion, String generatedFromUUID) { + super(); + this.artifactName = artifactName; + this.artifactType = artifactType; + this.artifactURL = artifactURL; + this.artifactDescription = artifactDescription; + this.artifactTimeout = artifactTimeout; + this.artifactChecksum = artifactChecksum; + this.artifactUUID = artifactUUID; + this.artifactVersion = artifactVersion; + this.generatedFromUUID = generatedFromUUID; + } + + public ArtifactAssetStructure() { + super(); + // TODO Auto-generated constructor stub + } + + public String getArtifactName() { + return artifactName; + } + + public void setArtifactName(String artifactName) { + this.artifactName = artifactName; + } + + public String getArtifactType() { + return artifactType; + } + + public void setArtifactType(String artifactType) { + this.artifactType = artifactType; + } + + public String getArtifactURL() { + return artifactURL; + } + + public void setArtifactURL(String artifactURL) { + this.artifactURL = artifactURL; + } + + public String getArtifactDescription() { + return artifactDescription; + } + + public void setArtifactDescription(String artifactDescription) { + this.artifactDescription = artifactDescription; + } + + public int getArtifactTimeout() { + return artifactTimeout; + } + + public void setArtifactTimeout(int artifactTimeout) { + this.artifactTimeout = artifactTimeout; + } + + public String getArtifactChecksum() { + return artifactChecksum; + } + + public void setArtifactChecksum(String artifactChecksum) { + this.artifactChecksum = artifactChecksum; + } + + public String getArtifactUUID() { + return artifactUUID; + } + + public void setArtifactUUID(String artifactUUID) { + this.artifactUUID = artifactUUID; + } + + public String getArtifactVersion() { + return artifactVersion; + } + + public void setArtifactVersion(String artifactVersion) { + this.artifactVersion = artifactVersion; + } + + public String getGeneratedFromUUID() { + return generatedFromUUID; + } + + public void setGeneratedFromUUID(String generatedFromUUID) { + this.generatedFromUUID = generatedFromUUID; + } + + @Override + public String toString() { + return "ArtifactAssetStructure [artifactName=" + artifactName + ", artifactType=" + artifactType + + ", artifactURL=" + artifactURL + ", artifactDescription=" + artifactDescription + ", artifactTimeout=" + + artifactTimeout + ", artifactChecksum=" + artifactChecksum + ", artifactUUID=" + artifactUUID + + ", artifactVersion=" + artifactVersion + ", generatedFromUUID=" + generatedFromUUID + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactReqDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactReqDetails.java new file mode 100644 index 0000000000..93f65b9f63 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactReqDetails.java @@ -0,0 +1,243 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.HeatParameterDefinition; + +public class ArtifactReqDetails { + + public ArtifactReqDetails() { + + } + + public ArtifactReqDetails(String artifactName, String artifactType, String artifactDescription, String payloadData, + String artifactLable) { + super(); + this.artifactName = artifactName; + this.artifactType = artifactType; + this.description = artifactDescription; + this.payloadData = payloadData; + this.artifactLabel = artifactLable; + } + + public ArtifactReqDetails(String artifactLable, ArtifactReqDetails a) { + super(); + this.artifactName = a.getArtifactName(); + this.artifactType = a.getArtifactType(); + this.description = a.getArtifactType(); + this.payloadData = a.getPayload(); + this.artifactLabel = artifactLable; + } + + private String uniqueId; + private String artifactName; + private String artifactType; + private String description; + private String payloadData; + private String artifactLabel; + private String apiUrl; + private String artifactGroupType; + private Integer timeout; + private String userIdLastUpdater; + private String creatorFullName; + private String updaterFullName; + private String artifactChecksum; + private String artifactDisplayName; + private List heatParameters; + + private boolean mandatory; + private boolean serviceApi; + + public boolean isServiceApi() { + return serviceApi; + } + + public void setServiceApi(boolean serviceApi) { + this.serviceApi = serviceApi; + } + + public String getArtifactLabel() { + return artifactLabel; + } + + public void setArtifactLabel(String artifactLabel) { + this.artifactLabel = artifactLabel; + } + + public String getArtifactName() { + return artifactName; + } + + public void setArtifactName(String artifactName) { + this.artifactName = artifactName; + } + + public String getArtifactType() { + return artifactType; + } + + public void setArtifactType(String artifactType) { + this.artifactType = artifactType; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getPayload() { + return payloadData; + } + + public void setPayload(String payload) { + this.payloadData = payload; + } + + public void setPayloadData(String payloadData) { + this.payloadData = payloadData; + } + + public String getArtifactGroupType() { + return artifactGroupType; + } + + public void setArtifactGroupType(String artifactGroupType) { + this.artifactGroupType = artifactGroupType; + } + + public Integer getTimeout() { + return timeout; + } + + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + + public boolean isMandatory() { + return mandatory; + } + + public void setMandatory(boolean mandatory) { + this.mandatory = mandatory; + } + + public String getUrl() { + return apiUrl; + } + + public void setUrl(String url) { + this.apiUrl = url; + } + + @Override + public String toString() { + if (!apiUrl.isEmpty()) { + return "ArtifactReqDetails [artifactName=" + artifactName + ", artifactType=" + artifactType + + ", description=" + description + ", payloadData=" + payloadData + ", artifactLabel=" + + artifactLabel + ", mandatory=" + mandatory + ", url=" + apiUrl + "]"; + } + + return "ArtifactReqDetails [artifactName=" + artifactName + ", artifactType=" + artifactType + ", description=" + + description + ", payloadData=" + payloadData + ", artifactLabel=" + artifactLabel + + ", artifactUniqueId=" + uniqueId + ", mandatory=" + mandatory + ", serviceApi=" + serviceApi + "]"; + + } + + // public String getPayloadData() { + // return payloadData; + // } + // + // public void setPayloadData(String payloadData) { + // this.payloadData = payloadData; + // } + + // public String getUserIdCreator() { + // return userIdCreator; + // } + // + // public void setUserIdCreator(String userIdCreator) { + // this.userIdCreator = userIdCreator; + // } + // + public String getArtifactDisplayName() { + + return artifactDisplayName; + } + + public void setArtifactDisplayName(String artifactDisplayName) { + this.artifactDisplayName = artifactDisplayName; + } + + public String getUserIdLastUpdater() { + return userIdLastUpdater; + } + + public void setUserIdLastUpdater(String userIdLastUpdater) { + this.userIdLastUpdater = userIdLastUpdater; + } + + public String getCreatorFullName() { + return creatorFullName; + } + + public void setCreatorFullName(String creatorFullName) { + this.creatorFullName = creatorFullName; + } + + public String getUpdaterFullName() { + return updaterFullName; + } + + public void setUpdaterFullName(String updaterFullName) { + this.updaterFullName = updaterFullName; + } + + public String getArtifactChecksum() { + return artifactChecksum; + } + + public void setArtifactChecksum(String artifactChecksum) { + this.artifactChecksum = artifactChecksum; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String artifactUniqueId) { + this.uniqueId = artifactUniqueId; + } + + public List getHeatParameters() { + return heatParameters; + } + + public void setHeatParameters(List heatParameters) { + this.heatParameters = heatParameters; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/AssetStructure.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/AssetStructure.java new file mode 100644 index 0000000000..8820b05772 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/AssetStructure.java @@ -0,0 +1,122 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class AssetStructure { + + private String uuid; + private String invariantUUID; + private String name; + private String version; + private String toscaModelURL; + private String category; + private String lifecycleState; + private String lastUpdaterUserId; + + public AssetStructure() { + super(); + } + + public AssetStructure(String uuid, String invariantUUID, String name, String version, String toscaModelURL, + String category, String lifecycleState, String lastUpdaterUserId) { + super(); + this.uuid = uuid; + this.invariantUUID = invariantUUID; + this.name = name; + this.version = version; + this.toscaModelURL = toscaModelURL; + this.category = category; + this.lifecycleState = lifecycleState; + this.lastUpdaterUserId = lastUpdaterUserId; + } + + @Override + public String toString() { + return "AssetStructure [uuid=" + uuid + ", invariantUUID=" + invariantUUID + ", name=" + name + ", version=" + + version + ", toscaModelURL=" + toscaModelURL + ", category=" + category + ", lifecycleState=" + + lifecycleState + ", lastUpdaterUserId=" + lastUpdaterUserId + "]"; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getInvariantUUID() { + return invariantUUID; + } + + public void setInvariantUUID(String invariantUUID) { + this.invariantUUID = invariantUUID; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getToscaModelURL() { + return toscaModelURL; + } + + public void setToscaModelURL(String toscaModelURL) { + this.toscaModelURL = toscaModelURL; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getLifecycleState() { + return lifecycleState; + } + + public void setLifecycleState(String lifecycleState) { + this.lifecycleState = lifecycleState; + } + + public String getLastUpdaterUserId() { + return lastUpdaterUserId; + } + + public void setLastUpdaterUserId(String lastUpdaterUserId) { + this.lastUpdaterUserId = lastUpdaterUserId; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ComponentInstanceReqDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ComponentInstanceReqDetails.java new file mode 100644 index 0000000000..549700f384 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ComponentInstanceReqDetails.java @@ -0,0 +1,121 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import org.openecomp.sdc.be.model.ComponentInstance; + +public class ComponentInstanceReqDetails { + + String componentUid; + String description; + String posX; + String posY; + String name; + String uniqueId; + + public ComponentInstanceReqDetails() { + super(); + // TODO Auto-generated constructor stub + } + + public ComponentInstanceReqDetails(ComponentInstance componentInstance) { + super(); + this.setUniqueId(componentInstance.getUniqueId()); + this.description = componentInstance.getDescription(); + this.posX = componentInstance.getPosX(); + this.posY = componentInstance.getPosY(); + // this.name = "myResourceInstance"; + this.name = componentInstance.getName(); + } + + public ComponentInstanceReqDetails(String resourceUid, String description, String posX, String posY, String name) { + super(); + this.componentUid = resourceUid; + this.description = description; + this.posX = posX; + this.posY = posY; + // this.name = "myResourceInstance"; + this.name = name; + } + + public ComponentInstanceReqDetails(String resourceUid, String description, String posX, String posY) { + super(); + this.componentUid = resourceUid; + this.description = description; + this.posX = posX; + this.posY = posY; + } + + public String getComponentUid() { + return componentUid; + } + + public void setComponentUid(String resourceUid) { + this.componentUid = resourceUid; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getPosX() { + return posX; + } + + public void setPosX(String posX) { + this.posX = posX; + } + + public String getPosY() { + return posY; + } + + public void setPosY(String posY) { + this.posY = posY; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + @Override + public String toString() { + return "ResourceInstanceReqDetails [resourceUid=" + componentUid + ", description=" + description + ", posX=" + + posX + ", posY=" + posY + ", name=" + name + ", uniqueId=" + uniqueId + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ComponentReqDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ComponentReqDetails.java new file mode 100644 index 0000000000..8546732414 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ComponentReqDetails.java @@ -0,0 +1,272 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; + +public abstract class ComponentReqDetails { + + protected String name; + protected String description; + protected List tags = new ArrayList<>(); + protected String contactId; + protected String icon; + protected String uniqueId; + protected String creatorUserId; + protected String creatorFullName; + protected String lastUpdaterUserId; + protected String lastUpdaterFullName; + protected Long creationDate; + protected Long lastUpdateDate; + protected LifecycleStateEnum lifecycleState; + protected String version; + protected String UUID; + protected List categories; + protected String projectCode; + protected String csarUUID; + protected String csarVersion; + protected String importedToscaChecksum; + protected String invariantUUID; + + public String getCsarVersion() { + return csarVersion; + } + + public void setCsarVersion(String csarVersion) { + this.csarVersion = csarVersion; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + tags.add(name); + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + // public String getCategory() { + // return category; + // } + // + public String getContactId() { + return contactId; + } + + public void setContactId(String contactId) { + this.contactId = contactId; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public void setCreatorUserId(String creatorUserId) { + this.creatorUserId = creatorUserId; + } + + public void setCreatorFullName(String creatorFullName) { + this.creatorFullName = creatorFullName; + } + + public void setLastUpdaterUserId(String lastUpdaterUserId) { + this.lastUpdaterUserId = lastUpdaterUserId; + } + + public void setLastUpdaterFullName(String lastUpdaterFullName) { + this.lastUpdaterFullName = lastUpdaterFullName; + } + + public void setCreationDate(Long creationDate) { + this.creationDate = creationDate; + } + + public void setLastUpdateDate(Long lastUpdateDate) { + this.lastUpdateDate = lastUpdateDate; + } + + public void setLifecycleState(LifecycleStateEnum lifecycleState) { + this.lifecycleState = lifecycleState; + } + + public void setUUID(String uUID) { + this.UUID = uUID; + } + + public String getCreatorUserId() { + return creatorUserId; + } + + public String getCreatorFullName() { + return creatorFullName; + } + + public String getLastUpdaterUserId() { + return lastUpdaterUserId; + } + + public String getLastUpdaterFullName() { + return lastUpdaterFullName; + } + + public Long getCreationDate() { + return creationDate; + } + + public Long getLastUpdateDate() { + return lastUpdateDate; + } + + public LifecycleStateEnum getLifecycleState() { + return lifecycleState; + } + + public String getUUID() { + return UUID; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getCategories() { + return categories; + } + + public void setCategories(List categories) { + this.categories = categories; + } + + public void removeAllCategories() { + this.categories = new ArrayList<>(); + } + + public void addCategoryChain(String category, String subCategory) { + if (category != null || subCategory != null) { + if (categories == null) { + categories = new ArrayList<>(); + } + CategoryDefinition selectedCategory = null; + for (CategoryDefinition categoryDef : categories) { + if (categoryDef.getName().equals(category)) { + selectedCategory = categoryDef; + } + } + if (selectedCategory == null) { + selectedCategory = new CategoryDefinition(); + selectedCategory.setName(category); + categories.add(selectedCategory); + } + if (subCategory != null) { + List subcategories = selectedCategory.getSubcategories(); + if (subcategories == null) { + subcategories = new ArrayList<>(); + selectedCategory.setSubcategories(subcategories); + } + SubCategoryDefinition selectedSubcategory = null; + for (SubCategoryDefinition subcategory : subcategories) { + if (subcategory.getName().equals(subCategory)) { + selectedSubcategory = subcategory; + } + } + if (selectedSubcategory == null) { + selectedSubcategory = new SubCategoryDefinition(); + selectedSubcategory.setName(subCategory); + subcategories.add(selectedSubcategory); + } + } + } + } + + public void addCategory(String category) { + addCategoryChain(category, null); + } + + public String getProjectCode() { + return projectCode; + } + + public void setProjectCode(String projectCode) { + this.projectCode = projectCode; + } + + public String getCsarUUID() { + return csarUUID; + } + + public void setCsarUUID(String csarUUID) { + this.csarUUID = csarUUID; + } + + public String getImportedToscaChecksum() { + return importedToscaChecksum; + } + + public void setImportedToscaChecksum(String importedToscaChecksum) { + this.importedToscaChecksum = importedToscaChecksum; + } + + public String getInvariantUUID() { + return invariantUUID; + } + + public void setInvariantUUID(String invariantUUID) { + this.invariantUUID = invariantUUID; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CsarArtifacts.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CsarArtifacts.java new file mode 100644 index 0000000000..f3379766e2 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CsarArtifacts.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class CsarArtifacts { + + private String artifactType; + private String artifactName; + + public CsarArtifacts() { + super(); + } + + public CsarArtifacts(String artifactName, String artifactType) { + super(); + this.artifactName = artifactName; + this.artifactType = artifactType; + } + + @Override + public String toString() { + return "AssetStructure [artifactName=" + artifactName + ", artifactType=" + artifactType + "]"; + } + + public String getArtifactType() { + return artifactType; + } + + public void setArtifactType(String artifactType) { + this.artifactType = artifactType; + } + + public String getArtifactName() { + return artifactName; + } + + public void setArtifactName(String artifactName) { + this.artifactName = artifactName; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/GroupHeatMetaDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/GroupHeatMetaDefinition.java new file mode 100644 index 0000000000..03bedd6746 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/GroupHeatMetaDefinition.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GroupHeatMetaDefinition { + + private int group = 0; +// private List artifactList = new ArrayList(); + private List artifactList = new ArrayList(); + @Override + public String toString() { + return "GroupHeatMetaDefinition [group=" + group + ", artifactList=" + artifactList + ", artifactMap=" + artifactMap + ", propertyHeatMetaDefinition=" + propertyHeatMetaDefinition + "]"; + } + + public List getArtifactList() { + return artifactList; + } + + public void setArtifactList(List artifactList) { + this.artifactList = artifactList; + } + + private Map artifactMap = new HashMap<>(); + PropertyHeatMetaDefinition propertyHeatMetaDefinition; + + public Map getArtifactMap() { + return artifactMap; + } + + public void setArtifactMap(Map artifactMap) { + this.artifactMap = artifactMap; + } + + + public PropertyHeatMetaDefinition getPropertyHeatMetaDefinition() { + return propertyHeatMetaDefinition; + } + + public void setPropertyHeatMetaDefinition(PropertyHeatMetaDefinition propertyHeatMetaDefinition) { + this.propertyHeatMetaDefinition = propertyHeatMetaDefinition; + } + + public GroupHeatMetaDefinition() { + super(); + } + + public int getGroup() { + return group; + } + + public void setGroup(int group) { + this.group = group; + } + +// public List getArtifactList() { +// return artifactList; +// } +// +// public void setArtifactList(List artifactList) { +// this.artifactList = artifactList; +// } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatMetaFirstLevelDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatMetaFirstLevelDefinition.java new file mode 100644 index 0000000000..4e760227f3 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatMetaFirstLevelDefinition.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class HeatMetaFirstLevelDefinition { + + public HeatMetaFirstLevelDefinition(String fileName, String type, String checkSum) { + super(); + this.fileName = fileName; + this.type = type; + this.checkSum = checkSum; + + } + + private String fileName; + private String type; + private String checkSum; + + public HeatMetaFirstLevelDefinition() { + super(); + // TODO Auto-generated constructor stub + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + + public String getCheckSum() { + return checkSum; + } + + public void setCheckSum(String checkSum) { + this.checkSum = checkSum; + } + + @Override + public String toString() { + return "HeatMetaFirstLevelDefinition [fileName=" + fileName + ", type=" + type + ", checkSum=" + checkSum + "]"; + } + + + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ImportReqDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ImportReqDetails.java new file mode 100644 index 0000000000..638ece8c6d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ImportReqDetails.java @@ -0,0 +1,335 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.yaml.snakeyaml.Yaml; + +public class ImportReqDetails extends ResourceReqDetails { + + private String payloadName; + private String payloadData; + + private Map requirements; + private Map capabilities; + + private List derivedList; + private String derivedFromField; + + public ImportReqDetails(String resourceName, String description, List tags, List derivedFrom, + String vendorName, String vendorRelease, String contactId, String icon) { + super(resourceName, description, tags, null, derivedFrom, vendorName, vendorRelease, contactId, icon); + } + + public String getPayloadName() { + return payloadName; + } + + public void setPayloadName(String payloadName) { + this.payloadName = payloadName; + } + + public String getPayloadData() { + return payloadData; + } + + public void setPayloadData(String payloadData) { + this.payloadData = payloadData; + } + + @Override + public String toString() { + return "ImportReqDetails [payloadName=" + payloadName + ", payloadData=" + payloadData + "]"; + } + + public void setReqirementsAndCapabilities(String path, String fileName, User user, String derivedFromSource) + throws Exception { + setRequirements(path, fileName, user, derivedFromSource); + setCapabilities(path, fileName, user, derivedFromSource); + } + + public List getDerivedList() { + return derivedList; + } + + public void setDerivedList(List derivedList) { + this.derivedList = derivedList; + } + + public String getDerivedFromField() { + return derivedFromField; + } + + public void setDerivedFromField(String derivedFromField) { + this.derivedFromField = derivedFromField; + } + + public Map getRequirements() { + return requirements; + } + + public void setRequirements(String path, String fileName, User user, String derivedFromSource) throws Exception { + Map requirementsFromFile = getRequirementsMapFromFile(path + File.separator + fileName, + toscaResourceName, "requirements"); + Map requirements = organizeRequirementsMap(requirementsFromFile); + getDerivedReqCap(user, requirements, "requirements", derivedFromSource); + this.requirements = requirements; + } + + private void getDerivedReqCap(User user, Map reqCapMap, String field, String derivedFromResource) + throws IOException, JSONException { + + if (derivedFromResource == null) { + derivedFromResource = "Root"; + } + + RestResponse rest = getResourceSource(user, derivedFromResource); + Map parsedFieldFromResponseAsMap = ResponseParser.getJsonValueAsMap(rest, field); + Iterator iterator = parsedFieldFromResponseAsMap.keySet().iterator(); + Map convertListToMap = null; + while (iterator.hasNext()) { + String type = iterator.next(); + List lst = (List) parsedFieldFromResponseAsMap.get(type); + convertListToMap = convertListToMap(lst); + + if (field.equals("capabilities")) { + convertListToMap.replace("capabilitySources", derivedList); + lst = new ArrayList(Arrays.asList(convertListToMap)); + } + + Object existingValue = reqCapMap.get(type); + if (existingValue != null) { + Map convertedExistingValue = convertListToMap((List) existingValue); + if (convertedExistingValue.get("name").toString().toLowerCase() + .equals(convertListToMap.get("name").toString().toLowerCase())) { + lst = new ArrayList(Arrays.asList(convertedExistingValue)); + } else { + lst.add(convertedExistingValue); + } + } + + reqCapMap.put(type, lst); + } + } + + private RestResponse getResourceSource(User user, String source) throws IOException, JSONException { + org.codehaus.jettison.json.JSONObject getResourceJSONObject = null; + RestResponse rest = ResourceRestUtils.getResourceByNameAndVersion(user.getUserId(), source, "1.0"); + if (rest.getErrorCode().intValue() == 200) { + JSONArray jArray = new JSONArray(rest.getResponse()); + for (int i = 0; i < jArray.length(); i++) { + getResourceJSONObject = jArray.getJSONObject(i); + String resourceType = getResourceJSONObject.get("resourceType").toString(); + if (!resourceType.equals("VF")) { + rest.setResponse(getResourceJSONObject.toString()); + } + } + } + return rest; + } + + public Map getCapabilities() { + return capabilities; + } + + public void setCapabilities(String path, String fileName, User user, String derivedFromSource) throws Exception { + Map capabilitiesFromFile = getCapabilitiesMapFromFile(path + File.separator + fileName, + toscaResourceName, "capabilities"); + Map capabilities = organizeCapabilitiesMap(capabilitiesFromFile); + getDerivedReqCap(user, capabilities, "capabilities", derivedFromSource); + this.capabilities = capabilities; + } + + private Map organizeCapabilitiesMap(Map capabilitiesFromFile) { + Iterator iterator = capabilitiesFromFile.keySet().iterator(); + Map capMap = new HashMap(); + while (iterator.hasNext()) { + List valueList = new ArrayList(); + String next = iterator.next(); + Map valuesMap = (Map) capabilitiesFromFile.get(next); + String key = valuesMap.remove("type").toString(); + valuesMap.put("name", next); + valuesMap.put("capabilitySources", derivedList); + valuesMap.put("type", key); + + if (!valuesMap.containsKey("occurrences")) { + valuesMap.put("minOccurrences", "1"); + valuesMap.put("maxOccurrences", "UNBOUNDED"); + } + + Object tempValue = capMap.get(key); + if (tempValue == null) { + valueList.add(valuesMap); + } else { + Map convertValue = convertListToMap((List) tempValue); + valueList = new ArrayList(Arrays.asList(convertValue, valuesMap)); + } + capMap.put(key, valueList); + } + return capMap; + } + + private Map getCapabilitiesMapFromFile(String fileName, String toscaResourceName, + String fieldToTest) throws Exception { + Map resourceToscaMap = getToscaResourceFromFile(fileName, toscaResourceName); + Object capMap = resourceToscaMap.get(fieldToTest); + if (capMap == null) { + return new HashMap(); + } + return (Map) capMap; + } + + private Map organizeRequirementsMap(Map requirementsFromFile) { + Map reqMap = new HashMap(); + List valueList = new ArrayList(); + Iterator iterator = requirementsFromFile.keySet().iterator(); + while (iterator.hasNext()) { + String key = iterator.next(); + Map valuesMap = (Map) requirementsFromFile.get(key); + valuesMap.put("name", key); + String capability = valuesMap.get("capability").toString(); + + List occurencesList = (List) valuesMap.remove("occurrences"); + if (occurencesList != null) { + valuesMap.put("minOccurrences", occurencesList.get(0).toString()); + valuesMap.put("maxOccurrences", occurencesList.get(1).toString()); + } + + valueList.add(valuesMap); + reqMap.put(capability, valueList); + } + + return reqMap; + } + + private Map getRequirementsMapFromFile(String fileName, String toscaResourceName, + String fieldToTest) throws Exception { + Map resourceToscaMap = getToscaResourceFromFile(fileName, toscaResourceName); + List reqListFromFile = (List) resourceToscaMap.get(fieldToTest); + if (reqListFromFile == null) { + return new HashMap(); + } + Map testedMapFromFile = convertListToMap(reqListFromFile); + return testedMapFromFile; + } + + private Map getToscaResourceFromFile(String fullFileName, String toscaResourceName) + throws Exception { + Map nodesTypesMap = getNodesTypesMapFromFile(fullFileName); + Map resourceToscaMap = (Map) nodesTypesMap.get(toscaResourceName); + + derivedFromField = resourceToscaMap.get("derived_from").toString(); + + return resourceToscaMap; + } + + private Map getNodesTypesMapFromFile(String fullFileName) throws FileNotFoundException { + Yaml yaml = new Yaml(); + File file = new File(fullFileName); + InputStream inputStream = new FileInputStream(file); + Map mapFromFile = (Map) yaml.load(inputStream); + Map nodesTypesMap = (Map) mapFromFile.get("node_types"); + return nodesTypesMap; + } + + private Map convertListToMap(List testedListFromFile) { + Map testedMapFromFile = new HashMap(); + for (int i = 0; i < testedListFromFile.size(); i++) { + Object req = testedListFromFile.get(i); + ObjectMapper m = new ObjectMapper(); + Map mappedObject = m.convertValue(req, Map.class); + testedMapFromFile.putAll(mappedObject); + } + return testedMapFromFile; + } + + public void compareRequirementsOrCapabilities(Map exepectedReq, Map actualReq) { + Iterator iterator = exepectedReq.keySet().iterator(); + while (iterator.hasNext()) { + String key = iterator.next(); + List expectedValues = (List) exepectedReq.get(key); + List actualValues = (List) actualReq.get(key); + assertNotNull(actualValues); + + List> expectedMapsList = convertListToMapList(expectedValues); + List> actualMapsList = convertListToMapList(actualValues); + assertEquals(expectedMapsList.size(), actualMapsList.size()); + + for (int i = 0; i < expectedMapsList.size(); i++) { + Map expectedMap = expectedMapsList.get(i); + Map actualdMap = actualMapsList.get(i); + if (expectedMap.get("name").equals(actualdMap.get("name"))) { + Iterator iterator2 = expectedMap.keySet().iterator(); + while (iterator2.hasNext()) { + String innerKey = iterator2.next(); + assertTrue( + "check " + innerKey + " in " + key + ":\nexpected: " + + expectedMap.get(innerKey).toString() + "\nactual: " + + actualdMap.get(innerKey).toString(), + expectedMap.get(innerKey).equals(actualdMap.get(innerKey))); + + } + + } + } + } + } + + private List> convertListToMapList(List testedListFromFile) { + List> listOfMaps = new ArrayList>(); + for (int i = 0; i < testedListFromFile.size(); i++) { + Object req = testedListFromFile.get(i); + ObjectMapper m = new ObjectMapper(); + Map mappedObject = m.convertValue(req, Map.class); + mappedObject.remove("uniqueId"); + Map testedMapFromFile = new HashMap(); + testedMapFromFile.putAll(mappedObject); + listOfMaps.add(testedMapFromFile); + } + return listOfMaps; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ProductReqDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ProductReqDetails.java new file mode 100644 index 0000000000..f2484e274d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ProductReqDetails.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.model.category.CategoryDefinition; + +public class ProductReqDetails extends ComponentReqDetails { + + private String fullName; + private List contacts; + private String isActive; + + public ProductReqDetails(String name, List category) { + this.categories = category; + this.name = name; + } + + public ProductReqDetails(String name) { + this.name = name; + } + + public void addCategory(CategoryDefinition category) { + if (categories == null) { + categories = new ArrayList<>(); + } + categories.add(category); + } + + public void addContact(String contactUserId) { + if (contacts == null) { + contacts = new ArrayList<>(); + } + contacts.add(contactUserId); + } + + public List getContacts() { + return contacts; + } + + public void setContacts(List contacts) { + this.contacts = contacts; + } + + public List getCategories() { + return categories; + } + + public void setCategories(List categories) { + this.categories = categories; + } + + public String getFullName() { + return fullName; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getActive() { + return isActive; + } + + public void setActive(String isActive) { + this.isActive = isActive; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyHeatMetaDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyHeatMetaDefinition.java new file mode 100644 index 0000000000..5c9083d757 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyHeatMetaDefinition.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class PropertyHeatMetaDefinition { + + String name; + boolean value; + + public PropertyHeatMetaDefinition() { + super(); + } + + + + public String getName() { + return name; + } + + + + public void setName(String name) { + this.name = name; + } + + + + public boolean getValue() { + return value; + } + + + + public void setValue(boolean value) { + this.value = value; + } + + + + @Override + public String toString() { + return "PropertyHeatMetaDefinition [name=" + name + ", value=" + value + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyReqDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyReqDetails.java new file mode 100644 index 0000000000..208e4aa3ea --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyReqDetails.java @@ -0,0 +1,145 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; + +public class PropertyReqDetails { + String name; + String type; + Boolean required = false; + String defaultValue; + String description; + String propertyRangeMin; + String propertyRangeMax; + Boolean isPassword = false; + SchemaDefinition schema; + + public PropertyReqDetails() { + super(); + } + + public PropertyReqDetails(String propertyName, String propertyType, Boolean propertyRequired, + String propertyDefaultValue, String propertyDescription, String propertyRangeMin, String propertyRangeMax, + Boolean propertyPassword) { + super(); + this.name = propertyName; + this.type = propertyType; + this.required = propertyRequired; + this.defaultValue = propertyDefaultValue; + this.description = propertyDescription; + this.propertyRangeMin = propertyRangeMin; + this.propertyRangeMax = propertyRangeMax; + this.isPassword = propertyPassword; + } + + public PropertyReqDetails(String propertyName, String propertyType, String propertyDefaultValue, + String propertyDescription, SchemaDefinition schema) { + super(); + this.name = propertyName; + this.type = propertyType; + this.defaultValue = propertyDefaultValue; + this.description = propertyDescription; + this.schema = schema; + } + + public SchemaDefinition getSchema() { + return schema; + } + + public void setSchema(SchemaDefinition schema) { + this.schema = schema; + } + + public String getName() { + return name; + } + + public void setName(String propertyName) { + this.name = propertyName; + } + + public String getPropertyType() { + return type; + } + + public void setPropertyType(String propertyType) { + this.type = propertyType; + } + + public Boolean getPropertyRequired() { + return required; + } + + public void setPropertyRequired(Boolean propertyRequired) { + this.required = propertyRequired; + } + + public String getPropertyDefaultValue() { + return defaultValue; + } + + public void setPropertyDefaultValue(String propertyDefaultValue) { + this.defaultValue = propertyDefaultValue; + } + + public String getPropertyDescription() { + return description; + } + + public void setPropertyDescription(String propertyDescription) { + this.description = propertyDescription; + } + + public String getPropertyRangeMin() { + return propertyRangeMin; + } + + public void setPropertyRangeMin(String propertyRangeMin) { + this.propertyRangeMin = propertyRangeMin; + } + + public String getPropertyRangeMax() { + return propertyRangeMax; + } + + public void setPropertyRangeMax(String propertyRangeMax) { + this.propertyRangeMax = propertyRangeMax; + } + + public Boolean getPropertyPassword() { + return isPassword; + } + + public void setPropertyPassword(Boolean propertyPassword) { + this.isPassword = propertyPassword; + } + + public String propertyToJsonString() { + String jsonString; + jsonString = "{\"" + this.getName() + "\":{" + "\"type\":\"" + this.getPropertyType() + "\"," + "\"required\":" + + this.getPropertyRequired() + "," + "\"defaultValue\":\"" + this.getPropertyDefaultValue() + "\"," + + "\"description\":\"" + this.getPropertyDescription() + "\"," + "\"constraints\":[{\"inRange\":[\"" + + this.getPropertyRangeMin() + "\",\"" + this.getPropertyRangeMax() + "\"]}]," + "\"isPassword\":" + + this.getPropertyPassword() + "}}"; + return jsonString; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceAssetStructure.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceAssetStructure.java new file mode 100644 index 0000000000..62f5e0c8f0 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceAssetStructure.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class ResourceAssetStructure extends AssetStructure { + + private String subCategory; + private String resourceType; + protected String lastUpdaterFullName; + protected String toscaResourceName; + + public ResourceAssetStructure() { + super(); + } + + public ResourceAssetStructure(String uuid, String invariantUUID, String name, String version, String toscaModelURL, + String category, String lifecycleState, String lastUpdaterUserId) { + super(uuid, invariantUUID, name, version, toscaModelURL, category, lifecycleState, lastUpdaterUserId); + } + + @Override + public String toString() { + return "ResourceAssetStructure [subCategory=" + subCategory + ", resourceType=" + resourceType + "]"; + } + + public String getLastUpdaterFullName() { + return lastUpdaterFullName; + } + + public void setLastUpdaterFullName(String lastUpdaterFullName) { + this.lastUpdaterFullName = lastUpdaterFullName; + } + + public String getToscaResourceName() { + return toscaResourceName; + } + + public void setToscaResourceName(String toscaResourceName) { + this.toscaResourceName = toscaResourceName; + } + + public String getSubCategory() { + return subCategory; + } + + public void setSubCategory(String subCategory) { + this.subCategory = subCategory; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceDetailedAssetStructure.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceDetailedAssetStructure.java new file mode 100644 index 0000000000..b521b4bf08 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceDetailedAssetStructure.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +public class ResourceDetailedAssetStructure extends ResourceAssetStructure { + + private List resources; + private List artifacts; + + public ResourceDetailedAssetStructure() { + super(); + } + + public ResourceDetailedAssetStructure(String lastUpdaterFullName, String toscaResourceName, + List resources, List artifacts) { + super(); + this.lastUpdaterFullName = lastUpdaterFullName; + this.toscaResourceName = toscaResourceName; + this.resources = resources; + this.artifacts = artifacts; + } + + public List getResources() { + return resources; + } + + public void setResources(List resources) { + this.resources = resources; + } + + public List getArtifacts() { + return artifacts; + } + + public void setArtifacts(List artifacts) { + this.artifacts = artifacts; + } + + @Override + public String toString() { + return "ResourceDetailedAssetStructure [lastUpdaterFullName=" + lastUpdaterFullName + ", toscaResourceName=" + + toscaResourceName + ", resources=" + resources + ", artifacts=" + artifacts + ", toString()=" + + super.toString() + ", getSubCategory()=" + getSubCategory() + ", getResourceType()=" + + getResourceType() + ", getUuid()=" + getUuid() + ", getInvariantUUID()=" + getInvariantUUID() + + ", getName()=" + getName() + ", getVersion()=" + getVersion() + ", getToscaModelURL()=" + + getToscaModelURL() + ", getCategory()=" + getCategory() + ", getLifecycleState()=" + + getLifecycleState() + ", getLastUpdaterUserId()=" + getLastUpdaterUserId() + ", getClass()=" + + getClass() + ", hashCode()=" + hashCode() + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceExternalReqDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceExternalReqDetails.java new file mode 100644 index 0000000000..a5132e8bf6 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceExternalReqDetails.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; + +public class ResourceExternalReqDetails extends ComponentReqDetails { + String vendorName; + String vendorRelease; + String category; + String subcategory; + + private String resourceType = ResourceTypeEnum.VFC.toString(); // Default + // value + public ResourceExternalReqDetails() { + super(); + } + + + public ResourceExternalReqDetails(String resourceName, String description, List tags, + String vendorName, String vendorRelease, String contactId, String icon, + String resourceType, String resourceCategory, String resourceSubcategory) { + super(); + this.resourceType = resourceType; + this.name = resourceName; + this.description = description; + this.tags = tags; + this.vendorName = vendorName; + this.vendorRelease = vendorRelease; + this.contactId = contactId; + this.icon = icon; + this.category = resourceCategory; + this.subcategory = resourceSubcategory; + } + + public String getVendorName() { + return vendorName; + } + + public void setVendorName(String vendorName) { + this.vendorName = vendorName; + } + + public String getVendorRelease() { + return vendorRelease; + } + + public void setVendorRelease(String vendorRelease) { + this.vendorRelease = vendorRelease; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getSubcategory() { + return subcategory; + } + + public void setSubcategory(String subcategory) { + this.subcategory = subcategory; + } + + + @Override + public String toString() { + return "ResourceReqDetails [name=" + name + ", vendorName=" + vendorName + + ", vendorRelease=" + vendorRelease + ", version=" + version + + ", resourceType=" + resourceType + ", category=" + category + ", subcategory=" + subcategory +"]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceInstanceAssetStructure.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceInstanceAssetStructure.java new file mode 100644 index 0000000000..6a69120a05 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceInstanceAssetStructure.java @@ -0,0 +1,116 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +public class ResourceInstanceAssetStructure { + + String resourceInstanceName; + String resourceName; + String resourceInvariantUUID; + String resourceVersion; + String resoucreType; + String resourceUUID; + List artifacts; + + public ResourceInstanceAssetStructure() { + super(); + } + + public ResourceInstanceAssetStructure(String resourceInstanceName, String resourceName, + String resourceInvariantUUID, String resourceVersion, String resoucreType, String resourceUUID, + List artifacts) { + super(); + this.resourceInstanceName = resourceInstanceName; + this.resourceName = resourceName; + this.resourceInvariantUUID = resourceInvariantUUID; + this.resourceVersion = resourceVersion; + this.resoucreType = resoucreType; + this.resourceUUID = resourceUUID; + this.artifacts = artifacts; + } + + public String getResourceInstanceName() { + return resourceInstanceName; + } + + public void setResourceInstanceName(String resourceInstanceName) { + this.resourceInstanceName = resourceInstanceName; + } + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public String getResourceInvariantUUID() { + return resourceInvariantUUID; + } + + public void setResourceInvariantUUID(String resourceInvariantUUID) { + this.resourceInvariantUUID = resourceInvariantUUID; + } + + public String getResourceVersion() { + return resourceVersion; + } + + public void setResourceVersion(String resourceVersion) { + this.resourceVersion = resourceVersion; + } + + public String getResoucreType() { + return resoucreType; + } + + public void setResoucreType(String resoucreType) { + this.resoucreType = resoucreType; + } + + public String getResourceUUID() { + return resourceUUID; + } + + public void setResourceUUID(String resourceUUID) { + this.resourceUUID = resourceUUID; + } + + public List getArtifacts() { + return artifacts; + } + + public void setArtifacts(List artifacts) { + this.artifacts = artifacts; + } + + @Override + public String toString() { + return "ResourceInstanceAssetStructure [resourceInstanceName=" + resourceInstanceName + ", resourceName=" + + resourceName + ", resourceInvariantUUID=" + resourceInvariantUUID + ", resourceVersion=" + + resourceVersion + ", resoucreType=" + resoucreType + ", resourceUUID=" + resourceUUID + ", artifacts=" + + artifacts + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceReqDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceReqDetails.java new file mode 100644 index 0000000000..8456e5b35b --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceReqDetails.java @@ -0,0 +1,220 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; + +public class ResourceReqDetails extends ComponentReqDetails { + List derivedFrom; + String vendorName; + String vendorRelease; + + // Unsettable/unupdatable fields + + Boolean isAbstract; + Boolean isHighestVersion; + String cost; + String licenseType; + String toscaResourceName; + + private String resourceType = ResourceTypeEnum.VFC.toString(); // Default + // value + + public ResourceReqDetails() { + super(); + } + + public ResourceReqDetails(Resource resource) { + super(); + this.resourceType = resource.getResourceType().toString(); + this.name = resource.getName(); + this.description = resource.getDescription(); + this.tags = resource.getTags(); + // this.category = resource.getCategories(); + this.derivedFrom = resource.getDerivedFrom(); + this.vendorName = resource.getVendorName(); + this.vendorRelease = resource.getVendorRelease(); + this.contactId = resource.getContactId(); + this.icon = resource.getIcon(); + this.toscaResourceName = resource.getToscaResourceName(); + this.uniqueId = resource.getUniqueId(); + this.creatorUserId = resource.getCreatorUserId(); + this.creatorFullName = resource.getCreatorFullName(); + this.lastUpdaterUserId = resource.getLastUpdaterUserId(); + this.lastUpdaterFullName = resource.getLastUpdaterFullName(); + this.lifecycleState = resource.getLifecycleState(); + this.version = resource.getVersion(); + this.UUID = resource.getUUID(); + this.categories = resource.getCategories(); + this.importedToscaChecksum = resource.getImportedToscaChecksum(); + + } + + public ResourceReqDetails(String resourceName, String description, List tags, String category, + List derivedFrom, String vendorName, String vendorRelease, String contactId, String icon) { + this(resourceName, description, tags, category, derivedFrom, vendorName, vendorRelease, contactId, icon, + ResourceTypeEnum.VFC.toString()); + } + + // new + public ResourceReqDetails(String resourceName, String description, List tags, String category, + List derivedFrom, String vendorName, String vendorRelease, String contactId, String icon, + String resourceType) { + super(); + this.resourceType = resourceType; + this.name = resourceName; + this.description = description; + this.tags = tags; + // this.category = category; + this.derivedFrom = derivedFrom; + this.vendorName = vendorName; + this.vendorRelease = vendorRelease; + this.contactId = contactId; + this.icon = icon; + if (category != null) { + String[] arr = category.split("/"); + if (arr.length == 2) { + addCategoryChain(arr[0], arr[1]); + } + } + this.toscaResourceName = resourceName; + } + + public ResourceReqDetails(ResourceReqDetails originalResource, String version) { + super(); + this.name = originalResource.getName(); + this.description = originalResource.getDescription(); + this.tags = originalResource.getTags(); + // this.category = originalResource.getCategory(); + this.derivedFrom = originalResource.getDerivedFrom(); + this.vendorName = originalResource.getVendorName(); + this.vendorRelease = originalResource.getVendorRelease(); + this.contactId = originalResource.getContactId(); + this.icon = originalResource.getIcon(); + this.version = version; + this.uniqueId = originalResource.getUniqueId(); + this.categories = originalResource.getCategories(); + this.toscaResourceName = originalResource.getToscaResourceName(); + this.resourceType = originalResource.getResourceType(); + } + + public ResourceReqDetails(String resourceName, List derivedFrom, String vendorName, String vendorRelease, + String resourceVersion, Boolean isAbstract, Boolean isHighestVersion, String cost, String licenseType, + String resourceType) { + super(); + this.name = resourceName; + this.derivedFrom = derivedFrom; + this.vendorName = vendorName; + this.vendorRelease = vendorRelease; + this.version = resourceVersion; + this.isAbstract = isAbstract; + this.isHighestVersion = isHighestVersion; + this.cost = cost; + this.licenseType = licenseType; + this.resourceType = resourceType; + this.toscaResourceName = resourceName; + } + + public String getToscaResourceName() { + return toscaResourceName; + } + + public void setToscaResourceName(String toscaResourceName) { + this.toscaResourceName = toscaResourceName; + } + + public List getDerivedFrom() { + return derivedFrom; + } + + public void setDerivedFrom(List derivedFrom) { + this.derivedFrom = derivedFrom; + } + + public String getVendorName() { + return vendorName; + } + + public void setVendorName(String vendorName) { + this.vendorName = vendorName; + } + + public String getVendorRelease() { + return vendorRelease; + } + + public void setVendorRelease(String vendorRelease) { + this.vendorRelease = vendorRelease; + } + + public String getCost() { + return cost; + } + + public void setCost(String cost) { + this.cost = cost; + } + + public String getLicenseType() { + return licenseType; + } + + public void setLicenseType(String licenseType) { + this.licenseType = licenseType; + } + + // Unupdatable fields - to check that they are not updated + public void setIsAbstract(Boolean isAbstract) { + this.isAbstract = isAbstract; + } + + public void setIsHighestVersion(Boolean isHighestVersion) { + this.isHighestVersion = isHighestVersion; + } + + public Boolean getIsAbstract() { + return isAbstract; + } + + public Boolean getIsHighestVersion() { + return isHighestVersion; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + @Override + public String toString() { + return "ResourceReqDetails [name=" + name + ", derivedFrom=" + derivedFrom + ", vendorName=" + vendorName + + ", vendorRelease=" + vendorRelease + ", version=" + version + ", isAbstract=" + isAbstract + + ", isHighestVersion=" + isHighestVersion + ", cost=" + cost + ", licenseType=" + licenseType + + ", resourceType=" + resourceType + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceRespJavaObject.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceRespJavaObject.java new file mode 100644 index 0000000000..8779c49915 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceRespJavaObject.java @@ -0,0 +1,369 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +import org.openecomp.sdc.be.model.category.CategoryDefinition; + +public class ResourceRespJavaObject { + String uniqueId; + String name; + String version; + String creatorUserId; + String creatorFullName; + String lastUpdaterUserId; + String lastUpdaterFullName; + String description; + String icon; + List tags; + String isHighestVersion; + String creationDate; + String lastUpdateDate; + // String category; + String lifecycleState; + List derivedFrom; + String vendorName; + String vendorRelease; + String contactId; + String abstractt; + String highestVersion; + List artifacts; + List interfaces; + String uuid; + String cost; + String licenseType; + String resourceType; + List categories; + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + public ResourceRespJavaObject(String uniqueId, String resourceName, String resourceVersion, String creatorUserId, + String creatorFullName, String lastUpdaterUserId, String lastUpdaterFullName, String description, + String icon, List tags, String isHighestVersion, String creationDate, String lastUpdateDate, + String category, String lifecycleState, List derivedFrom, String vendorName, String vendorRelease, + String contactId, String abstractt, String highestVersion, List artifacts, List interfaces, + String uuid, String cost, String licenseType, String resourceType) { + super(); + this.uniqueId = uniqueId; + this.name = resourceName; + this.version = resourceVersion; + this.creatorUserId = creatorUserId; + this.creatorFullName = creatorFullName; + this.lastUpdaterUserId = lastUpdaterUserId; + this.lastUpdaterFullName = lastUpdaterFullName; + this.description = description; + this.icon = icon; + this.tags = tags; + this.isHighestVersion = isHighestVersion; + this.creationDate = creationDate; + this.lastUpdateDate = lastUpdateDate; + // this.category = category; + this.lifecycleState = lifecycleState; + this.derivedFrom = derivedFrom; + this.vendorName = vendorName; + this.vendorRelease = vendorRelease; + this.contactId = contactId; + this.abstractt = abstractt; + this.highestVersion = highestVersion; + this.artifacts = artifacts; + this.interfaces = interfaces; + this.uuid = uuid; + this.cost = cost; + this.licenseType = licenseType; + this.resourceType = resourceType; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getCost() { + return cost; + } + + public void setCost(String cost) { + this.cost = cost; + } + + public String getLicenseType() { + return licenseType; + } + + public void setLicenseType(String licenseType) { + this.licenseType = licenseType; + } + + public String getUuid() { + return uuid; + } + + public String setUuid() { + return uuid; + } + + public List getInterfaces() { + return interfaces; + } + + public void setInterfaces(List interfaces) { + this.interfaces = interfaces; + } + + public List getArtifacts() { + return artifacts; + } + + public void setArtifacts(List artifacts) { + this.artifacts = artifacts; + } + + public ResourceRespJavaObject() { + super(); + // TODO Auto-generated constructor stub + } + + // public ResourceRespJavaObject(String uniqueId, String resourceName, + // String resourceVersion, String creatorUserId, + // String creatorFullName, String lastUpdaterUserId, + // String lastUpdaterFullName, String description, String icon, + // List tags, String isHighestVersion, String creationDate, + // String lastUpdateDate, String category, String lifecycleState, + // List derivedFrom, String vendorName, String vendorRelease, + // String contactId, String abstractt, String highestVersion) { + // super(); + // this.uniqueId = uniqueId; + // this.resourceName = resourceName; + // this.resourceVersion = resourceVersion; + // this.creatorUserId = creatorUserId; + // this.creatorFullName = creatorFullName; + // this.lastUpdaterUserId = lastUpdaterUserId; + // this.lastUpdaterFullName = lastUpdaterFullName; + // this.description = description; + // this.icon = icon; + // this.tags = tags; + // this.isHighestVersion = isHighestVersion; + // this.creationDate = creationDate; + // this.lastUpdateDate = lastUpdateDate; + // this.category = category; + // this.lifecycleState = lifecycleState; + // this.derivedFrom = derivedFrom; + // this.vendorName = vendorName; + // this.vendorRelease = vendorRelease; + // this.contactId = contactId; + // this.abstractt = abstractt; + // this.highestVersion = highestVersion; + // } + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getName() { + return name; + } + + public void setName(String resourceName) { + this.name = resourceName; + } + + public String getVersion() { + return version; + } + + public void setVersion(String resourceVersion) { + this.version = resourceVersion; + } + + public String getCreatorUserId() { + return creatorUserId; + } + + public void setCreatorUserId(String creatorUserId) { + this.creatorUserId = creatorUserId; + } + + public String getCreatorFullName() { + return creatorFullName; + } + + public void setCreatorFullName(String creatorFullName) { + this.creatorFullName = creatorFullName; + } + + public String getLastUpdaterUserId() { + return lastUpdaterUserId; + } + + public void setLastUpdaterUserId(String lastUpdaterUserId) { + this.lastUpdaterUserId = lastUpdaterUserId; + } + + public String getLastUpdaterFullName() { + return lastUpdaterFullName; + } + + public void setLastUpdaterFullName(String lastUpdaterFullName) { + this.lastUpdaterFullName = lastUpdaterFullName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public String getIsHighestVersion() { + return isHighestVersion; + } + + public void setIsHighestVersion(String isHighestVersion) { + this.isHighestVersion = isHighestVersion; + } + + public String getCreationDate() { + return creationDate; + } + + public void setCreationDate(String creationDate) { + this.creationDate = creationDate; + } + + public String getLastUpdateDate() { + return lastUpdateDate; + } + + public void setLastUpdateDate(String lastUpdateDate) { + this.lastUpdateDate = lastUpdateDate; + } + + // public String getCategory() { + // return category; + // } + // public void setCategory(String category) { + // this.category = category; + // } + public String getLifecycleState() { + return lifecycleState; + } + + public void setLifecycleState(String lifecycleState) { + this.lifecycleState = lifecycleState; + } + + public List getDerivedFrom() { + return derivedFrom; + } + + public void setDerivedFrom(List derivedFrom) { + this.derivedFrom = derivedFrom; + } + + public String getVendorName() { + return vendorName; + } + + public void setVendorName(String vendorName) { + this.vendorName = vendorName; + } + + public String getVendorRelease() { + return vendorRelease; + } + + public void setVendorRelease(String vendorRelease) { + this.vendorRelease = vendorRelease; + } + + public String getContactId() { + return contactId; + } + + public void setContactId(String contactId) { + this.contactId = contactId; + } + + public String getAbstractt() { + return abstractt; + } + + public void setAbstractt(String abstractt) { + this.abstractt = abstractt; + } + + public String getHighestVersion() { + return highestVersion; + } + + public void setHighestVersion(String highestVersion) { + this.highestVersion = highestVersion; + } + + public List getCategories() { + return categories; + } + + public void setCategories(List categories) { + this.categories = categories; + } + + @Override + public String toString() { + return "ResourceRespJavaObject [uniqueId=" + uniqueId + ", resourceName=" + name + ", resourceVersion=" + + version + ", creatorUserId=" + creatorUserId + ", creatorFullName=" + creatorFullName + + ", lastUpdaterUserId=" + lastUpdaterUserId + ", lastUpdaterFullName=" + lastUpdaterFullName + + ", description=" + description + ", icon=" + icon + ", tags=" + tags + ", isHighestVersion=" + + isHighestVersion + ", creationDate=" + creationDate + ", lastUpdateDate=" + lastUpdateDate + + ", lifecycleState=" + lifecycleState + ", derivedFrom=" + derivedFrom + ", vendorName=" + vendorName + + ", vendorRelease=" + vendorRelease + ", contactId=" + contactId + ", abstractt=" + abstractt + + ", highestVersion=" + highestVersion + ", artifacts=" + artifacts + ", interfaces=" + interfaces + + ", uuid=" + uuid + ", cost=" + cost + ", licenseType=" + licenseType + ", resourceType=" + + resourceType + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceAssetStructure.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceAssetStructure.java new file mode 100644 index 0000000000..015d228acf --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceAssetStructure.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class ServiceAssetStructure extends AssetStructure { + + private String distributionStatus; + + public ServiceAssetStructure() { + super(); + } + + public ServiceAssetStructure(String uuid, String invariantUUID, String name, String version, String toscaModelURL, + String category, String lifecycleState, String lastUpdaterUserId) { + super(uuid, invariantUUID, name, version, toscaModelURL, category, lifecycleState, lastUpdaterUserId); + } + + @Override + public String toString() { + return "ServiceAssetStructure [distributionStatus=" + distributionStatus + "]"; + } + + public String getDistributionStatus() { + return distributionStatus; + } + + public void setDistributionStatus(String distributionStatus) { + this.distributionStatus = distributionStatus; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceDetailedAssetStructure.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceDetailedAssetStructure.java new file mode 100644 index 0000000000..cc283a3169 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceDetailedAssetStructure.java @@ -0,0 +1,78 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +public class ServiceDetailedAssetStructure extends ServiceAssetStructure { + + String lastUpdaterFullName; + List resources; + List artifacts; + + public ServiceDetailedAssetStructure() { + super(); + } + + public ServiceDetailedAssetStructure(String uuid, String invariantUUID, String name, String version, + String toscaModelURL, String category, String lifecycleState, String lastUpdaterUserId) { + super(uuid, invariantUUID, name, version, toscaModelURL, category, lifecycleState, lastUpdaterUserId); + } + + public ServiceDetailedAssetStructure(String lastUpdaterFullName, List resources, + List artifacts) { + super(); + this.lastUpdaterFullName = lastUpdaterFullName; + this.resources = resources; + this.artifacts = artifacts; + } + + public String getLastUpdaterFullName() { + return lastUpdaterFullName; + } + + public void setLastUpdaterFullName(String lastUpdaterFullName) { + this.lastUpdaterFullName = lastUpdaterFullName; + } + + public List getResources() { + return resources; + } + + public void setResources(List resources) { + this.resources = resources; + } + + public List getArtifacts() { + return artifacts; + } + + public void setArtifacts(List artifacts) { + this.artifacts = artifacts; + } + + @Override + public String toString() { + return "ServiceDetailedAssetStructure [lastUpdaterFullName=" + lastUpdaterFullName + ", resources=" + resources + + ", artifacts=" + artifacts + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceDistributionStatus.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceDistributionStatus.java new file mode 100644 index 0000000000..dde1f27cca --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceDistributionStatus.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class ServiceDistributionStatus { + + private String distributionID; + private String timestamp; + private String userId; + private String deployementStatus; + + public ServiceDistributionStatus() { + super(); + // TODO Auto-generated constructor stub + } + + public ServiceDistributionStatus(String distributionID, String timestamp, String userId, String deployementStatus) { + super(); + this.distributionID = distributionID; + this.timestamp = timestamp; + this.userId = userId; + this.deployementStatus = deployementStatus; + } + + @Override + public String toString() { + return "ServiceDistributionStatus [distributionID=" + distributionID + ", timestamp=" + timestamp + ", userId=" + userId + ", deployementStatus=" + deployementStatus + "]"; + } + + public String getDistributionID() { + return distributionID; + } + + public void setDistributionID(String distributionID) { + this.distributionID = distributionID; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getDeployementStatus() { + return deployementStatus; + } + + public void setDeployementStatus(String deployementStatus) { + this.deployementStatus = deployementStatus; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceReqDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceReqDetails.java new file mode 100644 index 0000000000..e33183ca94 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceReqDetails.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.ArrayList; + +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.category.CategoryDefinition; + +public class ServiceReqDetails extends ComponentReqDetails { + + public ServiceReqDetails(String serviceName, String category, ArrayList tags, String description, + String contactId, String icon) { + this.name = serviceName; + // this.category = category; + this.tags = tags; + this.description = description; + this.contactId = contactId; + this.icon = icon; + projectCode = "12345"; + CategoryDefinition categoryDefinition = new CategoryDefinition(); + categoryDefinition.setName(category); + categories = new ArrayList<>(); + categories.add(categoryDefinition); + + } + + public ServiceReqDetails(Service service) { + this.contactId = service.getContactId(); + this.categories = service.getCategories(); + this.creatorUserId = service.getCreatorUserId(); + this.creatorFullName = service.getCreatorFullName(); + this.description = service.getDescription(); + this.icon = service.getIcon(); + this.name = service.getName(); + this.projectCode = service.getProjectCode(); + this.tags = service.getTags(); + this.uniqueId = service.getUniqueId(); + this.UUID = service.getUUID(); + this.version = service.getVersion(); + + } + + public ServiceReqDetails() { + contactId = "aa1234"; + projectCode = "12345"; + } + + public ServiceReqDetails(ServiceReqDetails a, String newServiceName) { + a.setName(newServiceName); + } + + @Override + public String toString() { + return "ServiceDetails [name=" + name + ", category=" + getCategory() + ", tags=" + tags + ", description=" + + description + ", contactId=" + contactId + ", icon=" + icon + "]"; + } + + public ServiceReqDetails(ServiceReqDetails aService) { + this(aService.getName(), aService.getCategory(), (ArrayList) aService.getTags(), + aService.getDescription(), aService.getContactId(), aService.getIcon()); + uniqueId = aService.getUniqueId(); + version = aService.getVersion(); + } + + public String getCategory() { + if (categories != null && categories.size() >= 1) { + return categories.get(0).getName(); + } + return null; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceRespJavaObject.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceRespJavaObject.java new file mode 100644 index 0000000000..723f6a47c6 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceRespJavaObject.java @@ -0,0 +1,268 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.ArrayList; +import java.util.List; + +public class ServiceRespJavaObject { + + String category; + String creatorUserId; + String creatorFullName; + String lastUpdaterUserId; + String lastUpdaterFullName; + String serviceName; + String version; + String creationDate; + String icon; + String name; + String description; + ArrayList tags; + String uniqueId; + String lastUpdateDate; + String contactId; + String vendorName; + String vendorRelease; + String lifecycleState; + String highestVersion; + ArrayList artifacts; + ArrayList ResourceInstances; + ArrayList ResourceInstancesRelations; + + public ServiceRespJavaObject() { + super(); + // TODO Auto-generated constructor stub + } + + public ServiceRespJavaObject(String category, String creatorUserId, String creatorFullName, + String lastUpdaterUserId, String lastUpdaterFullName, String serviceName, String version, + String creationDate, String icon, String name, String description, ArrayList tags, String uniqueId, + String lastUpdateDate, String contactId, String vendorName, String vendorRelease, String lifecycleState, + String highestVersion, ArrayList artifacts, ArrayList resourceInstances, + ArrayList resourceInstancesRelations) { + super(); + this.category = category; + this.creatorUserId = creatorUserId; + this.creatorFullName = creatorFullName; + this.lastUpdaterUserId = lastUpdaterUserId; + this.lastUpdaterFullName = lastUpdaterFullName; + this.serviceName = serviceName; + this.version = version; + this.creationDate = creationDate; + this.icon = icon; + this.name = name; + this.description = description; + this.tags = tags; + this.uniqueId = uniqueId; + this.lastUpdateDate = lastUpdateDate; + this.contactId = contactId; + this.vendorName = vendorName; + this.vendorRelease = vendorRelease; + this.lifecycleState = lifecycleState; + this.highestVersion = highestVersion; + this.artifacts = artifacts; + ResourceInstances = resourceInstances; + ResourceInstancesRelations = resourceInstancesRelations; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getCreatorUserId() { + return creatorUserId; + } + + public void setCreatorUserId(String creatorUserId) { + this.creatorUserId = creatorUserId; + } + + public String getCreatorFullName() { + return creatorFullName; + } + + public void setCreatorFullName(String creatorFullName) { + this.creatorFullName = creatorFullName; + } + + public String getLastUpdaterUserId() { + return lastUpdaterUserId; + } + + public void setLastUpdaterUserId(String lastUpdaterUserId) { + this.lastUpdaterUserId = lastUpdaterUserId; + } + + public String getLastUpdaterFullName() { + return lastUpdaterFullName; + } + + public void setLastUpdaterFullName(String lastUpdaterFullName) { + this.lastUpdaterFullName = lastUpdaterFullName; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getCreationDate() { + return creationDate; + } + + public void setCreationDate(String creationDate) { + this.creationDate = creationDate; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ArrayList getTags() { + return tags; + } + + public void setTags(ArrayList tags) { + this.tags = tags; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getLastUpdateDate() { + return lastUpdateDate; + } + + public void setLastUpdateDate(String lastUpdateDate) { + this.lastUpdateDate = lastUpdateDate; + } + + public String getContactId() { + return contactId; + } + + public void setContactId(String contactId) { + this.contactId = contactId; + } + + public String getVendorName() { + return vendorName; + } + + public void setVendorName(String vendorName) { + this.vendorName = vendorName; + } + + public String getVendorRelease() { + return vendorRelease; + } + + public void setVendorRelease(String vendorRelease) { + this.vendorRelease = vendorRelease; + } + + public String getLifecycleState() { + return lifecycleState; + } + + public void setLifecycleState(String lifecycleState) { + this.lifecycleState = lifecycleState; + } + + public String getHighestVersion() { + return highestVersion; + } + + public void setHighestVersion(String highest) { + this.highestVersion = highest; + } + + public ArrayList getArtifacts() { + return artifacts; + } + + public void setArtifacts(ArrayList artifacts) { + this.artifacts = artifacts; + } + + public ArrayList getResourceInstances() { + return ResourceInstances; + } + + public void setResourceInstances(ArrayList resourceInstances) { + ResourceInstances = resourceInstances; + } + + public ArrayList getResourceInstancesRelations() { + return ResourceInstancesRelations; + } + + public void setResourceInstancesRelations(ArrayList resourceInstancesRelations) { + ResourceInstancesRelations = resourceInstancesRelations; + } + + @Override + public String toString() { + return "ServiceRespJavaObject [category=" + category + ", creatorUserId=" + creatorUserId + ", creatorFullName=" + + creatorFullName + ", lastUpdaterUserId=" + lastUpdaterUserId + ", lastUpdaterFullName=" + + lastUpdaterFullName + ", serviceName=" + serviceName + ", version=" + version + ", creationDate=" + + creationDate + ", icon=" + icon + ", name=" + name + ", description=" + description + ", tags=" + tags + + ", uniqueId=" + uniqueId + ", lastUpdateDate=" + lastUpdateDate + ", contactId=" + contactId + + ", vendorName=" + vendorName + ", vendorRelease=" + vendorRelease + ", lifecycleState=" + + lifecycleState + ", lifecycleState=" + lifecycleState + ", artifacts=" + artifacts + + ", ResourceInstances=" + ResourceInstances + ", ResourceInstancesRelations=" + + ResourceInstancesRelations + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TypeHeatMetaDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TypeHeatMetaDefinition.java new file mode 100644 index 0000000000..d0f029242f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TypeHeatMetaDefinition.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +public class TypeHeatMetaDefinition { + + String typeName; + + List groupHeatMetaDefinition; + + public TypeHeatMetaDefinition() { + super(); + } + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public List getGroupHeatMetaDefinition() { + return groupHeatMetaDefinition; + } + + public void setGroupHeatMetaDefinition(List groupHeatMetaDefinition) { + this.groupHeatMetaDefinition = groupHeatMetaDefinition; + } + + @Override + public String toString() { + return "TypeHeatMetaDefinition [typeName=" + typeName + ", groupHeatMetaDefinition=" + groupHeatMetaDefinition + + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ArtifactTypeEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ArtifactTypeEnum.java new file mode 100644 index 0000000000..4e4c87f112 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ArtifactTypeEnum.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +import java.util.ArrayList; +import java.util.List; + +/** + * Enum That Represents possible Artifacts Types. + * + */ +public enum ArtifactTypeEnum { + CHEF("CHEF"), PUPPET("PUPPET"), YANG("YANG"), SHELL_SCRIPT("SHELL_SCRIPT"), ICON("ICON"), UNKNOWN("UNKNOWN"), HEAT("HEAT"), DG_XML("DG_XML"), MURANO_PKG("MURANO_PKG"), + HEAT_ENV("HEAT_ENV"), YANG_XML("YANG_XML"), HEAT_VOL("HEAT_VOL"), HEAT_NET("HEAT_NET"), OTHER("OTHER"), WORKFLOW("WORKFLOW"), NETWORK_CALL_FLOW("NETWORK_CALL_FLOW"), + TOSCA_TEMPLATE("TOSCA_TEMPLATE"), TOSCA_CSAR("TOSCA_CSAR"), VNF_CATALOG("VNF_CATALOG"), VF_LICENSE("VF_LICENSE"), VENDOR_LICENSE("VENDOR_LICENSE"), + MODEL_INVENTORY_PROFILE("MODEL_INVENTORY_PROFILE"), MODEL_QUERY_SPEC("MODEL_QUERY_SPEC"), APPC_CONFIG("APPC_CONFIG"), HEAT_NESTED("HEAT_NESTED"), + HEAT_ARTIFACT("HEAT_ARTIFACT"), VF_MODULES_METADATA("VF_MODULES_METADATA"), + // DCAE Artifacts + DCAE_TOSCA("DCAE_TOSCA"), DCAE_JSON("DCAE_JSON"), DCAE_POLICY("DCAE_POLICY"), DCAE_DOC("DCAE_DOC"), DCAE_EVENT("DCAE_EVENT"), DCAE_INVENTORY_TOSCA("DCAE_INVENTORY_TOSCA"), + DCAE_INVENTORY_JSON("DCAE_INVENTORY_JSON"), DCAE_INVENTORY_POLICY("DCAE_INVENTORY_POLICY"), DCAE_INVENTORY_DOC("DCAE_INVENTORY_DOC"), + DCAE_INVENTORY_BLUEPRINT("DCAE_INVENTORY_BLUEPRINT"), DCAE_INVENTORY_EVENT("DCAE_INVENTORY_EVENT"), + // AAI Artifacts + AAI_SERVICE_MODEL("AAI_SERVICE_MODEL"), AAI_VF_MODEL("AAI_VF_MODEL"), AAI_VF_MODULE_MODEL("AAI_VF_MODULE_MODEL"), AAI_VF_INSTANCE_MODEL("AAI_VF_INSTANCE_MODEL"), + // MIB artifacts + SNMP_POLL ("SNMP_POLL"), SNMP_TRAP("SNMP_TRAP"), GUIDE("GUIDE") + ; + + ArtifactTypeEnum(String type) { + this.type = type; + } + + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public static ArtifactTypeEnum findType(final String type) { + for (ArtifactTypeEnum ate : ArtifactTypeEnum.values()) { + // According to Pavel/Ella + if (ate.getType().equalsIgnoreCase(type)) { + return ate; + } + } + return null; + } + + public static List getAllTypes() { + List types = new ArrayList(); + for (ArtifactTypeEnum ate : ArtifactTypeEnum.values()) { + types.add(ate.getType()); + } + return types; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AssocType.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AssocType.java new file mode 100644 index 0000000000..82e9a36780 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AssocType.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum AssocType { + + BINDABLE("tosca.capabilities.network.Bindable"), HOSTEDON("tosca.relationships.HostedOn"), LINKABLE("tosca.capabilities.network.Linkable"), + CONTAINER("tosca.capabilities.Container"), NODE("tosca.capabilities.Node"); + + private String assocType; + + private AssocType(String assocType) { + this.assocType = assocType; + + } + + public String getAssocType() { + return assocType; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AuditEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AuditEnum.java new file mode 100644 index 0000000000..a713d5089f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AuditEnum.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum AuditEnum { + + ACTION("ACTION"), RESOURCE_NAME("RESOURCE_NAME"), RESOURCE_TYPE("RESOURCE_TYPE"), PREV_VERSION("PREV_VERSION"), CURR_VERSION("CURR_VERSION"), MODIFIER("MODIFIER"), PREV_STATE("PREV_STATE"), + CURR_STATE("CURR_STATE"), STATUS("STATUS-Type"), DESC("DESC"), URL("URL"), USER("USER"), AUTH_STATUS("AUTH_STATUS"), REALM("REALM"); + + String value; + + private AuditEnum(String value) { + this.value = value; + } + + public String getValue() { + + return value.toLowerCase(); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AuditJsonKeysEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AuditJsonKeysEnum.java new file mode 100644 index 0000000000..308ea5c990 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/AuditJsonKeysEnum.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum AuditJsonKeysEnum { + + ACTION("ACTION"), RESOURCE_NAME("RESOURCE_NAME"), RESOURCE_TYPE("RESOURCE_TYPE"), PREV_VERSION("PREV_VERSION"), CURR_VERSION("CURR_VERSION"), PREV_STATE("PREV_STATE"), CURR_STATE("CURR_STATE"), + DPREV_STATUS("DPREV_STATUS"), DCURR_STATUS("DCURR_STATUS"), STATUS("STATUS"), DESCRIPTION("DESCRIPTION"), ARTIFACT_DATA("ARTIFACT_DATA"), CONSUMER_ID("CONSUMER_ID"), RESOURCE_URL("RESOURCE_URL"), + COMMENT("COMMENT"), DID("DID"), TOPIC_NAME("TOPIC_NAME"), TOSCA_NODE_TYPE("TOSCA_NODE_TYPE"), CURR_ARTIFACT_UUID("CURR_ARTIFACT_UUID"), PREV_ARTIFACT_UUID("PREV_ARTIFACT_UUID"), DETAILS("DETAILS"), + MODIFIER("MODIFIER"), SERVICE_INSTANCE_ID("SERVICE_INSTANCE_ID"), INVARIANT_UUID("INVARIANT_UUID"); + + private String auditJsonKeyName; + + private AuditJsonKeysEnum(String auditJsonKeyName) { + this.auditJsonKeyName = auditJsonKeyName; + } + + public String getAuditJsonKeyName() { + return auditJsonKeyName.toLowerCase(); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ComponentType.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ComponentType.java new file mode 100644 index 0000000000..3d242e8c52 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ComponentType.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum ComponentType { + + RESOURCE("Resource"), SERVICE("Service"), ARTIFACT("Artifact"); + + String value; + + private ComponentType(String value) { + this.value = value; + } + + public String getValue() { + + return value; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/DistributionNotificationStatusEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/DistributionNotificationStatusEnum.java new file mode 100644 index 0000000000..7042a954e7 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/DistributionNotificationStatusEnum.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum DistributionNotificationStatusEnum { + + + DEPLOY_OK("DEPLOY_OK"), + DOWNLOAD_OK("DOWNLOAD_OK"), + NOTIFIED("NOTIFIED"), + NOT_NOTIFIED("NOT_NOTIFIED"); + + private String value; + + private DistributionNotificationStatusEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static DistributionNotificationStatusEnum findState(String state) { + + for (DistributionNotificationStatusEnum distributionStatus : DistributionNotificationStatusEnum.values()) { + if (distributionStatus.name().equalsIgnoreCase(state) + || distributionStatus.getValue().equalsIgnoreCase(state)) { + return distributionStatus; + } + } + return null; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ErrorInfo.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ErrorInfo.java new file mode 100644 index 0000000000..c2a28a1edf --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ErrorInfo.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public class ErrorInfo { + + private Integer code; + private String message; + private String messageId; + + public ErrorInfo() { + super(); + // TODO Auto-generated constructor stub + } + + public ErrorInfo(Integer code, String message, String messageId) { + super(); + this.code = code; + this.message = message; + this.messageId = messageId; + } + + public ErrorInfo(Integer code, String message) { + super(); + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public String getMessageAndReplaceVariables(Object... variables) { + String formatReadyString = message.replaceAll("%[\\d]+", "%s"); + formatReadyString = String.format(formatReadyString, variables); + return formatReadyString; + } + + public String getAuditDesc(Object... variables) { + String messageAndReplaceVariables = getMessageAndReplaceVariables(variables); + String res; + if (messageId != null) { + res = messageId + ": " + messageAndReplaceVariables; + } else { + res = messageAndReplaceVariables; + } + return res; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getMessageId() { + return messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + @Override + public String toString() { + return "ErrorInfo [code=" + code + ", message=" + message + ", messageId=" + messageId + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/EsIndexTypeIdToDelete.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/EsIndexTypeIdToDelete.java new file mode 100644 index 0000000000..6bfbd8af7d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/EsIndexTypeIdToDelete.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public class EsIndexTypeIdToDelete { + + String index; + String type; + String id; + + public EsIndexTypeIdToDelete() { + super(); + } + + public EsIndexTypeIdToDelete(String index, String type, String id) { + super(); + this.index = index; + this.type = type; + this.id = id; + } + + public String getIndex() { + return index; + } + + public void setIndex(String index) { + this.index = index; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ExceptionEnumType.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ExceptionEnumType.java new file mode 100644 index 0000000000..59d1dec453 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ExceptionEnumType.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum ExceptionEnumType { + + SERVICE_EXCEPTION("serviceException"), POLICY_EXCPTION("policyException"); + + String value; + + private ExceptionEnumType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ImportTestTypesEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ImportTestTypesEnum.java new file mode 100644 index 0000000000..21901e4635 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ImportTestTypesEnum.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +import java.util.Arrays; +import java.util.List; + +import org.openecomp.sdc.be.dao.api.ActionStatus; + +public enum ImportTestTypesEnum { + + MISSING_CONTACT("tosca.nodes.missing_contact", "missing_contact", ActionStatus.COMPONENT_MISSING_CONTACT, Arrays.asList("Resource"), true), + MISSING_RESOURCE_NAME("tosca.nodes.missing_resource_name", "missing_resource_name", ActionStatus.MISSING_COMPONENT_NAME, Arrays.asList("Resource"), true), + MISSING_DESC("tosca.nodes.missing_desc", "missing_desc", ActionStatus.COMPONENT_MISSING_DESCRIPTION, Arrays.asList("Resource"), true), + MISSING_ICON("tosca.nodes.missing_icon", "missing_icon", ActionStatus.COMPONENT_MISSING_ICON, Arrays.asList("Resource"), true), + MISSING_TAGS("tosca.nodes.missing_tags", "missing_tags", ActionStatus.COMPONENT_MISSING_TAGS, null, true), + MISSING_CATEGORY("tosca.nodes.missing_category", "missing_category", ActionStatus.COMPONENT_MISSING_CATEGORY, Arrays.asList("Resource"), true), + // MISSING_PAYLOADNAME("tosca.nodes.missing_payloadName", + // "missing_payloadName", ActionStatus.INVALID_TOSCA_FILE_EXTENSION, null, + // true), + + EMPTY_RESOURCE_NAME("tosca.nodes.empty_resource_name", "missing_resource_name"/* "empty_resource_name" */, ActionStatus.MISSING_COMPONENT_NAME, Arrays.asList("Resource"), false), + EMPTY_CONTACT("tosca.nodes.empty_contact", "missing_contact"/* "empty_contact" */, ActionStatus.COMPONENT_MISSING_CONTACT, Arrays.asList("Resource"), false), + EMPTY_CATEGORY("tosca.nodes.empty_category", "missing_category"/* "empty_category" */, ActionStatus.COMPONENT_MISSING_CATEGORY, Arrays.asList("Resource"), false), + EMPTY_DESC("tosca.nodes.empty_desc", "missing_desc"/* "empty_desc" */, ActionStatus.COMPONENT_MISSING_DESCRIPTION, Arrays.asList("Resource"), false), + EMPTY_ICON("tosca.nodes.empty_icon", "missing_icon"/* "empty_icon" */, ActionStatus.COMPONENT_MISSING_ICON, Arrays.asList("Resource"), false), + EMPTY_PAYLOADNAME("tosca.nodes.empty_payloadName", "missing_payloadName"/* "empty_payloadName" */, ActionStatus.INVALID_TOSCA_FILE_EXTENSION, null, false), + EMPTY_TAG("tosca.nodes.empty_tag", "empty_tag", ActionStatus.INVALID_FIELD_FORMAT, Arrays.asList("Resource", "tag"), false), + VALIDATE_PROPORTIES_1("tosca.nodes.validateProporties_typeBoolean_valueInit", "validateProporties_typeBoolean_valueInit", ActionStatus.INVALID_DEFAULT_VALUE, Arrays.asList("validation_test", "boolean", "123456"), false), + VALIDATE_PROPORTIES_2("tosca.nodes.validateProporties_typeBoolean_valueString", "validateProporties_typeBoolean_valueString", ActionStatus.INVALID_DEFAULT_VALUE, Arrays.asList("validation_test", "boolean", "abcd"), false), + VALIDATE_PROPORTIES_3("tosca.nodes.validateProporties_typeFloat_valueBoolean", "validateProporties_typeFloat_valueBoolean", ActionStatus.INVALID_DEFAULT_VALUE, Arrays.asList("validation_test", "float", "true"), false), + VALIDATE_PROPORTIES_4("tosca.nodes.validateProporties_typeFloat_valueString", "validateProporties_typeFloat_valueString", ActionStatus.INVALID_DEFAULT_VALUE, Arrays.asList("validation_test", "float", "abcd"), false), + VALIDATE_PROPORTIES_5("tosca.nodes.validateProporties_typeInit_valueBoolean", "validateProporties_typeInit_valueBoolean", ActionStatus.INVALID_DEFAULT_VALUE, Arrays.asList("validation_test", "integer", "true"), false), + VALIDATE_PROPORTIES_6("tosca.nodes.validateProporties_typeInit_valueFloat", "validateProporties_typeInit_valueFloat", ActionStatus.INVALID_DEFAULT_VALUE, Arrays.asList("validation_test", "integer", "0.123"), false), + VALIDATE_PROPORTIES_7("tosca.nodes.validateProporties_typeInit_valueString", "validateProporties_typeInit_valueString", ActionStatus.INVALID_DEFAULT_VALUE, Arrays.asList("validation_test", "integer", "abcd"), false); + // VALIDATE_PROPORTIES_8("tosca.nodes.validateProporties_happyScenarios","validateProporties_happyScenarios", ActionStatus.OK, null, false); + + private String normativeName; + private String folderName; + private ActionStatus actionStatus; + private Boolean validateAudit; + private List errorParams; + private Boolean validateYaml; + + // private enum ActionStatus; + + private ImportTestTypesEnum(String resourceName, String folderName, ActionStatus actionStatus, + List errorParams, Boolean validateAudit) { + this.normativeName = resourceName; + this.folderName = folderName; + this.actionStatus = actionStatus; + this.errorParams = errorParams; + this.validateAudit = validateAudit; + + } + + public String getNormativeName() { + return normativeName; + } + + public String getFolderName() { + return folderName; + } + + public ActionStatus getActionStatus() { + return actionStatus; + } + + public Boolean getvalidateAudit() { + return validateAudit; + } + + public List getErrorParams() { + return errorParams; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/LifeCycleStatesEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/LifeCycleStatesEnum.java new file mode 100644 index 0000000000..9edfb9aced --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/LifeCycleStatesEnum.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +import java.util.List; + +public enum LifeCycleStatesEnum { + + CHECKOUT("checkout", "NOT_CERTIFIED_CHECKOUT"), + CHECKIN("checkin", "NOT_CERTIFIED_CHECKIN"), + CERTIFICATIONREQUEST("certificationRequest", "READY_FOR_CERTIFICATION"), + UNDOCHECKOUT("undoCheckout", ""), + CANCELCERTIFICATION("cancelCertification", ""), + STARTCERTIFICATION("startCertification", "CERTIFICATION_IN_PROGRESS"), + FAILCERTIFICATION("failCertification", ""), + CERTIFY("certify", "CERTIFIED"); + + private String state; + private String componentState; + + private LifeCycleStatesEnum(String state, String componentState) { + this.state = state; + this.componentState = componentState; + + } + + public String getState() { + return state; + } + + public String getComponentState() { + return componentState; + } + + public static LifeCycleStatesEnum findByCompState(String compState) { + + for (LifeCycleStatesEnum lifeCycleStatesEnum : LifeCycleStatesEnum.values()) { + if (lifeCycleStatesEnum.getComponentState().equals(compState)) { + return lifeCycleStatesEnum; + } + } + + return null; + + } + + public static LifeCycleStatesEnum findByState(String state) { + + for (LifeCycleStatesEnum lifeCycleStatesEnum : LifeCycleStatesEnum.values()) { + if (lifeCycleStatesEnum.name().equals(state)) { + return lifeCycleStatesEnum; + } + } + + return null; + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/MandatoryResourceArtifactTypeEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/MandatoryResourceArtifactTypeEnum.java new file mode 100644 index 0000000000..58892439b0 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/MandatoryResourceArtifactTypeEnum.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; + +public enum MandatoryResourceArtifactTypeEnum { + + TEST_SCRIPTS(null, "testscripts"), FEATURES(null, "features"), CAPACITY(null, "capacity"), VENDOR_TEST_RESULT(null, "vendortestresult"), CLOUD_QUESTIONNAIRE(null, "cloudQuestionnaire"); + + String artifactName; + String logicalName; + + private MandatoryResourceArtifactTypeEnum(String artifactName, String logicalName) { + this.artifactName = artifactName; + this.logicalName = logicalName; + } + + public String getArtifactName() { + return artifactName; + } + + public String getLogicalName() { + return logicalName; + } + + public ArtifactGroupTypeEnum getGroupType() { + return ArtifactGroupTypeEnum.INFORMATIONAL; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/MandatoryServiceArtifactTypeEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/MandatoryServiceArtifactTypeEnum.java new file mode 100644 index 0000000000..b73d5a8fee --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/MandatoryServiceArtifactTypeEnum.java @@ -0,0 +1,66 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum MandatoryServiceArtifactTypeEnum { + + MESSAGE_FLOWS(null, "messageflows".toLowerCase(), "Message Flows"), + INSTANT_FLOWS(null, "instantiationflows".toLowerCase(), "Management Flows"), + SERVICE_ART_PLAN(null, "serviceartifactplan".toLowerCase(), "Service Artifact Plan"), + SUM_OF_ELEMENTS(null, "summaryofimpactstoecompelements".toLowerCase(), "Summary of impacts to ECOMP elements,OSSs, BSSs"), + CONTROL_LOOP_FUN(null, "controlloopfunctions".toLowerCase(), "Control Loop Functions"), + DIMENSIONNING_INFO(null, "dimensioninginfo".toLowerCase(), "Dimensioning Info"), + AFFINITY_RULES(null, "affinityrules".toLowerCase(), "Affinity Rules"), + OPERATIONAL_POLICIES(null, "operationalpolicies".toLowerCase(), "Operational Policies"), + SERVICE_SPECIFIC_POLICIES(null, "servicespecificpolicies".toLowerCase(), "Service-specific Policies"), + ENGINEERING_RULES(null, "engineeringrules".toLowerCase(), "Engineering Rules (ERD)"), + DISTRIB_INSTRUCTIONS(null, "distributioninstructions".toLowerCase(), "Distribution Instructions"), + DEPLOYMENT_VOTING_REC(null, "deploymentvotingrecord".toLowerCase(), "Deployment Voting Record"), + CERTIFICATION_TEST_RESULT(null, "certificationtestresults".toLowerCase(), "TD Certification Test Results"); + // SERVICE_QUESTIONNAIRE(null, "serviceQuestionnaire".toLowerCase()); + + String artifactName; + String logicalName; + String artifactDisplayName; + + private MandatoryServiceArtifactTypeEnum(String artifactName, String logicalName, String artifactDisplayName) { + this.artifactName = artifactName; + this.logicalName = logicalName; + this.artifactDisplayName = artifactDisplayName; + } + + public String getArtifactName() { + return artifactName; + } + + public String getLogicalName() { + return logicalName; + } + + public String getArtifactDisplayName() { + return artifactDisplayName; + } + + public void setArtifactDisplayName(String artifactDisplayName) { + this.artifactDisplayName = artifactDisplayName; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/NormativeTypesEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/NormativeTypesEnum.java new file mode 100644 index 0000000000..389b962f1c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/NormativeTypesEnum.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum NormativeTypesEnum { + ROOT("tosca.nodes.Root", "root"), COMPUTE("tosca.nodes.Compute", "compute"), BLOCK_STORAGE("tosca.nodes.BlockStorage", "blockStorage"), CONTAINER_APPLICATION("tosca.nodes.Container.Application", "containerApplication"), + CONTAINER_RUNTIME("tosca.nodes.Container.Runtime","containerRuntime"), DATABASE("tosca.nodes.Database", "database"), DBMS("tosca.nodes.DBMS", "DBMS"), LOAD_BALANCER("tosca.nodes.LoadBalancer", "loadBalancer"), + OBJECT_STORAGE("tosca.nodes.ObjectStorage", "objectStorage"), NETWORK("tosca.nodes.network.Network", "network"), PORT("tosca.nodes.network.Port", "port"), SOFTWARE_COMPONENT("tosca.nodes.SoftwareComponent", "softwareComponent"), + WEB_APPLICATION("tosca.nodes.webapplication","webApplication"), WEB_SERVER("tosca.nodes.WebServer", "webServer"); + + public String normativeName; + private String folderName; + + private NormativeTypesEnum(String resourceName, String folderName) { + this.normativeName = resourceName; + this.folderName = folderName; + } + + public String getNormativeName() { + return normativeName; + } + + public String getFolderName() { + return folderName; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/OriginTypeEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/OriginTypeEnum.java new file mode 100644 index 0000000000..d85a496241 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/OriginTypeEnum.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; + +public enum OriginTypeEnum { + PRODUCT("Product", "Product", "product instance", ComponentTypeEnum.PRODUCT), + SERVICE("Service", "Service", "service instance", ComponentTypeEnum.SERVICE), + VF("VF", "VF (Virtual Function)", "resource instance", ComponentTypeEnum.RESOURCE), + VFC("VFC", "VFC (Virtual Function Component)", "resource instance", ComponentTypeEnum.RESOURCE), + CP("CP", "CP (Connection Point)", "resource instance", ComponentTypeEnum.RESOURCE), + VL("VL", "VL (Virtual Link)", "resource instance", ComponentTypeEnum.RESOURCE), + VFCMT("VFCMT", "VFCMT (VFC Monitoring Template)", "resource instance", ComponentTypeEnum.RESOURCE), + VFi("VFi", "VFi (Virtual Function Instance)", "resource instance", ComponentTypeEnum.RESOURCE_INSTANCE); + + + private String value; + private String displayValue; + private String instanceType; + private ComponentTypeEnum componentType; + + private OriginTypeEnum(String value, String displayValue, String instanceType, ComponentTypeEnum componentType) { + this.value = value; + this.displayValue = displayValue; + this.instanceType = instanceType; + this.componentType = componentType; + } + + public String getValue() { + return value; + } + + public String getDisplayValue() { + return displayValue; + } + + public String getInstanceType() { + return instanceType; + } + + public ComponentTypeEnum getComponentType() { + return componentType; + } + + public static OriginTypeEnum findByValue(String value) { + OriginTypeEnum ret = null; + for (OriginTypeEnum curr : OriginTypeEnum.values()) { + if (curr.getValue().equals(value)) { + ret = curr; + break; + } + } + return ret; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/PropertyTypeEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/PropertyTypeEnum.java new file mode 100644 index 0000000000..8a1dc84684 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/PropertyTypeEnum.java @@ -0,0 +1,107 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; + +public enum PropertyTypeEnum { + INTEGER("defaultIntegerPropName1", "integer", "125", "default integer type property description", null), + STRING("defaultStringPropName1", "string", "string", "default string type property description", null), + BOOLEAN("defaultBooleanPropName1", "boolean", "true", "default boolean type property description", null), + FLOAT("defaultBooleanPropName1", "float", "1.2", "default float type property description", null), + STRING_LIST("defaultStringListPropName", "list", "[a,b]", "outer description", getDefaultStringSchema(ToscaPropertyType.STRING.getType())), + INTEGER_LIST("defaultIntegerListPropName", "list", "[1,2]", "outer description", getDefaultStringSchema(ToscaPropertyType.INTEGER.getType())), + BOOLEAN_LIST("defaultBooleanListPropName", "list", "[true,false]", "outer description", getDefaultStringSchema(ToscaPropertyType.BOOLEAN.getType())), + FLOAT_LIST("defaultFloatMapPropName", "list", "[1.0,2.0]", "outer description", getDefaultStringSchema(ToscaPropertyType.FLOAT.getType())), + STRING_MAP("defaultStringMapPropName", "map", "{\"key1\":val1 , \"key2\":val2}", "outer description", getDefaultStringSchema(ToscaPropertyType.STRING.getType())), + INTEGER_MAP("defaultIntegerMapPropName", "map", "{\"key1\":123 , \"key2\":-456}", "outer description", getDefaultStringSchema(ToscaPropertyType.INTEGER.getType())), + BOOLEAN_MAP("defaultBooleanMapPropName", "map", "{\"key1\":true , \"key2\":false}", "outer description", getDefaultStringSchema(ToscaPropertyType.BOOLEAN.getType())), + FLOAT_MAP("defaultFloatMapPropName", "map", "{\"key1\":0.2123 , \"key2\":43.545f}", "outer description", getDefaultStringSchema(ToscaPropertyType.FLOAT.getType())); + + private String name; + private String type; + private String value; + private String description; + private SchemaDefinition schemaDefinition; + + private PropertyTypeEnum(String name, String type, String value, String description, + SchemaDefinition schemaDefinition) { + this.name = name; + this.type = type; + this.value = value; + this.description = description; + this.schemaDefinition = schemaDefinition; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public SchemaDefinition getSchemaDefinition() { + return schemaDefinition; + } + + public void setSchemaDefinition(SchemaDefinition schemaDefinition) { + this.schemaDefinition = schemaDefinition; + } + + private static SchemaDefinition getDefaultStringSchema(String innerType) { + SchemaDefinition schema = new SchemaDefinition(); + String description = "inner description"; + PropertyDefinition property = new PropertyDefinition(); + property.setType(innerType); + property.setDescription(description); + schema.setProperty(property); + return schema; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ResourceCategoryEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ResourceCategoryEnum.java new file mode 100644 index 0000000000..47123a61e7 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ResourceCategoryEnum.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum ResourceCategoryEnum { + + NETWORK_L2_3_ROUTERS("Network L2-3", "Router"), NETWORK_L2_3_GETEWAY("Network L2-3","Gateway"), NETWORK_L2_3_WAN_CONNECTORS("Network L2-3", "WAN Connectors"), NETWORK_L2_3_LAN_CONNECTORS("Network L2-3", "LAN Connectors"), + NETWORK_L2_3_INFRASTRUCTURE("Network L2-3", "Infrastructure"), NETWORK_L4("Network L4+", "Common Network Resources"), APPLICATION_L4_BORDER("Application L4+", "Border Element"), + APPLICATION_L4_APP_SERVER("Application L4+", "Application Server"), APPLICATION_L4_WEB_SERVERS("Application L4+", "Web Server"), APPLICATION_L4_CALL_CONTROL("Application L4+","Call Control"), + APPLICATION_L4_MEDIA_SERVER("Application L4+", "Media Servers"), APPLICATION_L4_LOAD_BALANCER("Application L4+", "Load Balancer"), APPLICATION_L4_DATABASE("Application L4+","Database"), + APPLICATION_L4_FIREWALL("Application L4+", "Firewall"), GENERIC_INFRASTRUCTURE("Generic", "Infrastructure"), GENERIC_ABSTRACT("Generic", "Abstract"), GENERIC_NETWORK_ELEMENTS("Generic","Network Elements"), + GENERIC_DATABASE("Generic", "Database"), NETWORK_CONNECTIVITY_CON_POINT("Network Connectivity", "Connection Points"), NETWORK_CONNECTIVITY_VIRTUAL_LINK("Network Connectivity","Virtual Links"), + TEMPLATE_MONITORING_TEMPLATE("Template", "Monitoring Template"), ALLOTTED_RESOURCE("Allotted Resource", "Allotted Resource"); + + private String category; + private String subCategory; + + ResourceCategoryEnum(String category, String subCategory) { + this.category = category; + this.subCategory = subCategory; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getSubCategory() { + return subCategory; + } + + public void setSubCategory(String subCategory) { + this.subCategory = subCategory; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/RespJsonKeysEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/RespJsonKeysEnum.java new file mode 100644 index 0000000000..a977e38fe2 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/RespJsonKeysEnum.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum RespJsonKeysEnum { + + IS_ABSTRACT("abstract"), UNIQUE_ID("uniqueId"), RESOURCE_NAME("name"), RESOURCE_VERSION("version"), TAGS("tags"), LIFE_CYCLE_STATE("lifecycleState"), DERIVED_FROM("derivedFrom"), RESOURCE_DESC("description"), + VENDOR_NAME("vendorName"), VENDOR_RELEASE("vendorRelease"), CONTACT_ID("contactId"), ICON("icon"), HIGHEST_VERSION("highestVersion"), CREATOR_ATT_UID("creatorUserId"), CREATOR_FULL_NAME("creatorFullName"), + LAST_UPDATER_ATT_UID("lastUpdaterUserId"), LAST_UPDATER_FULL_NAME("lastUpdaterFullName"), ARTIFACTS("artifacts"), DESCRIPTION("description"), UUID("uuid"), COST("cost"), LICENSE_TYPE("licenseType"), + RESOURCE_TYPE("resourceType"), CATEGORIES("categories"); + + private String respJsonKeyName; + + private RespJsonKeysEnum(String respJsonKeyName) { + this.respJsonKeyName = respJsonKeyName; + } + + public String getRespJsonKeyName() { + return respJsonKeyName; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/SearchCriteriaEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/SearchCriteriaEnum.java new file mode 100644 index 0000000000..f26423a35d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/SearchCriteriaEnum.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + + + +public enum SearchCriteriaEnum { + + RESOURCE_TYPE("resourceType"), CATEGORY("category"), SUBCATEGORY("subCategory"); + + private String value; + + private SearchCriteriaEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ServiceApiArtifactEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ServiceApiArtifactEnum.java new file mode 100644 index 0000000000..4cfcc8a558 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ServiceApiArtifactEnum.java @@ -0,0 +1,35 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum ServiceApiArtifactEnum { + CONFIGURATION("Configuration".toLowerCase()), INSTANTIATION("Instantiation".toLowerCase()), MONITORING("Monitoring".toLowerCase()), REPORTING("Reporting".toLowerCase()), LOGGING("Logging".toLowerCase()), TESTING("Testing".toLowerCase()); + + String logicalName; + + private ServiceApiArtifactEnum(String logicalName) { + this.logicalName = logicalName; + } + + public String getLogicalName() { + return logicalName; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ServiceCategoriesEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ServiceCategoriesEnum.java new file mode 100644 index 0000000000..61d4e487e2 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ServiceCategoriesEnum.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum ServiceCategoriesEnum { + + VOIP("VoIP Call Control"), MOBILITY("Mobility"), NETWORK_L4("Network L4+"), NETWORK_L3("Network L1-3"); + String value; + + private ServiceCategoriesEnum(String value) { + this.value = value; + } + + public String getValue() { + + return value; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ToscaKeysEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ToscaKeysEnum.java new file mode 100644 index 0000000000..b8635b3bda --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/ToscaKeysEnum.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum ToscaKeysEnum { + + TOSCA_DEFINITION_VERSION("tosca_definitions_version"), METADATA("metadata"), IMPORTS("imports"), NODE_TYPES("node_types"), TOPOLOGY_TEMPLATE("topology_template"); + + private String toscaKey; + + public String getToscaKey() { + return toscaKey; + } + + private ToscaKeysEnum(String toscaKey) { + this.toscaKey = toscaKey; + } + + public static ToscaKeysEnum findToscaKey(final String toscaKey) { + for (ToscaKeysEnum toscaKeyEnum : ToscaKeysEnum.values()) { + if (toscaKeyEnum.getToscaKey().equalsIgnoreCase(toscaKey)) { + return toscaKeyEnum; + } + } + return null; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/UserRoleEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/UserRoleEnum.java new file mode 100644 index 0000000000..fb04f6a68b --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/enums/UserRoleEnum.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.enums; + +public enum UserRoleEnum { + + ADMIN("jh0003", "Jimmy", "Hendrix"), DESIGNER("cs0008", "Carlos", "Santana"), DESIGNER2("me0009", "Melissa","Etheridge"), TESTER("jm0007", "Joni", "Mitchell"), ADMIN4("km2000", "Kot", "May"), + GOVERNOR("gv0001","David", "Shadmi"), OPS("op0001", "Steve", "Regev"), PRODUCT_STRATEGIST1("ps0001", "Eden","Rozin"), PRODUCT_STRATEGIST2("ps0002", "Ella", "Kvetny"), PRODUCT_STRATEGIST3("ps0003", "Geva", "Alon"), + PRODUCT_MANAGER1("pm0001", "Teddy", "Isashar"), PRODUCT_MANAGER2("pm0002", "Sarah", "Bettens"); + private String userId; + private String firstName; + private String lastName; + private String userName; + + private UserRoleEnum(String userId, String userName) { + this.userId = userId; + this.userName = userName; + } + + private UserRoleEnum(String userId, String firstName, String lastName) { + this.userId = userId; + this.firstName = firstName; + this.lastName = lastName; + this.userName = firstName + " " + lastName; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedArtifactAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedArtifactAudit.java new file mode 100644 index 0000000000..344f353348 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedArtifactAudit.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedArtifactAudit { + + private String action; + private String resourceName; + private String resourceType; + private String prevVersion; + private String currVersion; + private String modifier; + private String prevState; + private String currState; + private String prevArtifactUuid; + private String currArtifactUuid; + private String artifactData; + private String status; + private String desc; + + public ExpectedArtifactAudit(String action, String resourceName, String resourceType, String prevVersion, + String currVersion, String modifier, String prevState, String currState, String prevArtifactUuid, + String currArtifactUuid, String artifactData, String status, String desc) { + super(); + this.action = action; + this.resourceName = resourceName; + this.resourceType = resourceType; + this.prevVersion = prevVersion; + this.currVersion = currVersion; + this.modifier = modifier; + this.prevState = prevState; + this.currState = currState; + this.prevArtifactUuid = prevArtifactUuid; + this.currArtifactUuid = currArtifactUuid; + this.artifactData = artifactData; + this.status = status; + this.desc = desc; + } + + public ExpectedArtifactAudit() { + super(); + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getResourceName() { + return resourceName; + } + + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + public String getPrevVersion() { + return prevVersion; + } + + public void setPrevVersion(String prevVersion) { + this.prevVersion = prevVersion; + } + + public String getCurrVersion() { + return currVersion; + } + + public void setCurrVersion(String currVersion) { + this.currVersion = currVersion; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public String getPrevState() { + return prevState; + } + + public void setPrevState(String prevState) { + this.prevState = prevState; + } + + public String getCurrState() { + return currState; + } + + public void setCurrState(String currState) { + this.currState = currState; + } + + public String getPrevArtifactUuid() { + return prevArtifactUuid; + } + + public void setPrevArtifactUuid(String prevArtifactUuid) { + this.prevArtifactUuid = prevArtifactUuid; + } + + public String getCurrArtifactUuid() { + return currArtifactUuid; + } + + public void setCurrArtifactUuid(String currArtifactUuid) { + this.currArtifactUuid = currArtifactUuid; + } + + public String getArtifactData() { + return artifactData; + } + + public void setArtifactData(String artifactData) { + this.artifactData = artifactData; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedAuthenticationAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedAuthenticationAudit.java new file mode 100644 index 0000000000..0d6a5f3b3c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedAuthenticationAudit.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedAuthenticationAudit { + + private String url; + private String realm; + private String user; + private String action; + private String authStatus; + + public ExpectedAuthenticationAudit(String url, String user, String action, String authStatus) { + super(); + this.url = url; + this.user = user; + this.action = action; + this.authStatus = authStatus; + this.realm = "ASDC"; + } + + public ExpectedAuthenticationAudit() { + + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getRealm() { + return realm; + } + + public void setRealm(String realm) { + this.realm = realm; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getAuthStatus() { + return authStatus; + } + + public void setAuthStatus(String authStatus) { + this.authStatus = authStatus; + } + + @Override + public String toString() { + return "ExpectedAuthenticationAudit [url=" + url + ", realm=" + realm + ", user=" + user + ", action=" + action + + ", authStatus=" + authStatus + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedCategoryAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedCategoryAudit.java new file mode 100644 index 0000000000..b11f7f585a --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedCategoryAudit.java @@ -0,0 +1,151 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedCategoryAudit { + String action; + String modifier; + String modifierUid; + String modifierName; + String categoryName; + String subCategoryName; + String groupingName; + String resourceType; + String status; + String desc; + String details; + + public ExpectedCategoryAudit(String action, String modifier, String categoryName, String subCategoryName, + String groupingName, String resourceType, String status, String desc) { + super(); + this.action = action; + this.modifier = modifier; + this.categoryName = categoryName; + this.subCategoryName = subCategoryName; + this.groupingName = groupingName; + this.resourceType = resourceType; + this.status = status; + this.desc = desc; + } + + public ExpectedCategoryAudit() { + action = null; + modifier = null; + categoryName = null; + subCategoryName = null; + groupingName = null; + resourceType = null; + status = null; + desc = null; + details = null; + modifierName = null; + modifierUid = null; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public String getCategoryName() { + return categoryName; + } + + public void setCategoryName(String categoryName) { + this.categoryName = categoryName; + } + + public String getSubCategoryName() { + return subCategoryName; + } + + public void setSubCategoryName(String subCategoryName) { + this.subCategoryName = subCategoryName; + } + + public String getGroupingName() { + return groupingName; + } + + public void setGroupingName(String groupingName) { + this.groupingName = groupingName; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getDetails() { + return details; + } + + public void setDetails(String details) { + this.details = details; + } + + public String getModifierUid() { + return modifierUid; + } + + public void setModifierUid(String modifierUid) { + this.modifierUid = modifierUid; + } + + public String getModifierName() { + return modifierName; + } + + public void setModifierName(String modifierName) { + this.modifierName = modifierName; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedDistDownloadAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedDistDownloadAudit.java new file mode 100644 index 0000000000..4b135f66f6 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedDistDownloadAudit.java @@ -0,0 +1,79 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedDistDownloadAudit { + + String action; + String consumerId; + String resourceUrl; + String status; + String desc; + + public ExpectedDistDownloadAudit(String action, String consumerId, String resourceUrl, String status, String desc) { + super(); + this.action = action; + this.consumerId = consumerId; + this.resourceUrl = resourceUrl; + this.status = status; + this.desc = desc; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getConsumerId() { + return consumerId; + } + + public void setConsumerId(String consumerId) { + this.consumerId = consumerId; + } + + public String getResourceUrl() { + return resourceUrl; + } + + public void setResourceUrl(String resourceUrl) { + this.resourceUrl = resourceUrl; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedEcomConsumerAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedEcomConsumerAudit.java new file mode 100644 index 0000000000..1414742423 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedEcomConsumerAudit.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedEcomConsumerAudit { + + String action; + String modifier; + String ecomUser; + String status; + String desc; + + public ExpectedEcomConsumerAudit(String action, String modifier, String ecomUser, String status, String desc) { + super(); + this.action = action; + this.modifier = modifier; + this.ecomUser = ecomUser; + this.status = status; + this.desc = desc; + } + + public ExpectedEcomConsumerAudit() { + action = null; + modifier = null; + ecomUser = null; + status = null; + desc = null; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public String getEcomUser() { + return ecomUser; + } + + public void setEcomUser(String ecomUser) { + this.ecomUser = ecomUser; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedExternalAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedExternalAudit.java new file mode 100644 index 0000000000..e689a3921b --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedExternalAudit.java @@ -0,0 +1,179 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedExternalAudit { + + String ACTION; + String CONSUMER_ID; + String RESOURCE_URL; + String STATUS; + String DESC; + String RESOURCE_NAME; + String RESOURCE_TYPE; + String SERVICE_INSTANCE_ID;// resource/ service UUID + String MODIFIER; + String PREV_ARTIFACT_UUID; + String CURR_ARTIFACT_UUID; + String ARTIFACT_DATA; + + public ExpectedExternalAudit() { + super(); + // TODO Auto-generated constructor stub + } + + public String getRESOURCE_NAME() { + return RESOURCE_NAME; + } + + public void setRESOURCE_NAME(String rESOURCE_NAME) { + RESOURCE_NAME = rESOURCE_NAME; + } + + public String getRESOURCE_TYPE() { + return RESOURCE_TYPE; + } + + public void setRESOURCE_TYPE(String rESOURCE_TYPE) { + RESOURCE_TYPE = rESOURCE_TYPE; + } + + public String getSERVICE_INSTANCE_ID() { + return SERVICE_INSTANCE_ID; + } + + public void setSERVICE_INSTANCE_ID(String sERVICE_INSTANCE_ID) { + SERVICE_INSTANCE_ID = sERVICE_INSTANCE_ID; + } + + public ExpectedExternalAudit(String aCTION, String cONSUMER_ID, String rESOURCE_URL, String sTATUS, String dESC, + String rESOURCE_NAME, String rESOURCE_TYPE, String sERVICE_INSTANCE_ID) { + super(); + ACTION = aCTION; + CONSUMER_ID = cONSUMER_ID; + RESOURCE_URL = rESOURCE_URL; + STATUS = sTATUS; + DESC = dESC; + RESOURCE_NAME = rESOURCE_NAME; + RESOURCE_TYPE = rESOURCE_TYPE; + SERVICE_INSTANCE_ID = sERVICE_INSTANCE_ID; + } + + public ExpectedExternalAudit(String aCTION, String cONSUMER_ID, String rESOURCE_URL, String sTATUS, String dESC) { + super(); + ACTION = aCTION; + CONSUMER_ID = cONSUMER_ID; + RESOURCE_URL = rESOURCE_URL; + STATUS = sTATUS; + DESC = dESC; + } + + public ExpectedExternalAudit(String aCTION, String cONSUMER_ID, String rESOURCE_URL, String sTATUS, String dESC, + String rESOURCE_NAME, String rESOURCE_TYPE, String sERVICE_INSTANCE_ID, String mODIFIER, + String pREV_ARTIFACT_UUID, String cURR_ARTIFACT_UUID, String aRTIFACT_DATA) { + super(); + ACTION = aCTION; + CONSUMER_ID = cONSUMER_ID; + RESOURCE_URL = rESOURCE_URL; + STATUS = sTATUS; + DESC = dESC; + RESOURCE_NAME = rESOURCE_NAME; + RESOURCE_TYPE = rESOURCE_TYPE; + SERVICE_INSTANCE_ID = sERVICE_INSTANCE_ID; + MODIFIER = mODIFIER; + PREV_ARTIFACT_UUID = pREV_ARTIFACT_UUID; + CURR_ARTIFACT_UUID = cURR_ARTIFACT_UUID; + ARTIFACT_DATA = aRTIFACT_DATA; + } + + public String getACTION() { + return ACTION; + } + + public void setACTION(String aCTION) { + ACTION = aCTION; + } + + public String getCONSUMER_ID() { + return CONSUMER_ID; + } + + public void setCONSUMER_ID(String cONSUMER_ID) { + CONSUMER_ID = cONSUMER_ID; + } + + public String getRESOURCE_URL() { + return RESOURCE_URL; + } + + public void setRESOURCE_URL(String rESOURCE_URL) { + RESOURCE_URL = rESOURCE_URL; + } + + public String getSTATUS() { + return STATUS; + } + + public void setSTATUS(String sTATUS) { + STATUS = sTATUS; + } + + public String getDESC() { + return DESC; + } + + public void setDESC(String dESC) { + DESC = dESC; + } + + public String getMODIFIER() { + return MODIFIER; + } + + public void setMODIFIER(String mODIFIER) { + MODIFIER = mODIFIER; + } + + public String getPREV_ARTIFACT_UUID() { + return PREV_ARTIFACT_UUID; + } + + public void setPREV_ARTIFACT_UUID(String pREV_ARTIFACT_UUID) { + PREV_ARTIFACT_UUID = pREV_ARTIFACT_UUID; + } + + public String getCURR_ARTIFACT_UUID() { + return CURR_ARTIFACT_UUID; + } + + public void setCURR_ARTIFACT_UUID(String cURR_ARTIFACT_UUID) { + CURR_ARTIFACT_UUID = cURR_ARTIFACT_UUID; + } + + public String getARTIFACT_DATA() { + return ARTIFACT_DATA; + } + + public void setARTIFACT_DATA(String aRTIFACT_DATA) { + ARTIFACT_DATA = aRTIFACT_DATA; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedGetUserListAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedGetUserListAudit.java new file mode 100644 index 0000000000..561b92a317 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedGetUserListAudit.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedGetUserListAudit { + + String action; + String modifier; + String status; + String desc; + String details; + + public ExpectedGetUserListAudit(String action, String modifier, String status, String desc, String details) { + super(); + this.action = action; + this.modifier = modifier; + this.status = status; + this.desc = desc; + this.details = details; + } + + public ExpectedGetUserListAudit() { + action = null; + modifier = null; + details = null; + status = null; + desc = null; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getDetails() { + return details; + } + + public void setDetails(String details) { + this.details = details; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedGroupingAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedGroupingAudit.java new file mode 100644 index 0000000000..b481cb77af --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedGroupingAudit.java @@ -0,0 +1,121 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedGroupingAudit { + String action; + String modifier; + String categoryName; + String subCategoryName; + String groupingName; + String resourceType; + String status; + String desc; + + public ExpectedGroupingAudit(String action, String modifier, String categoryName, String subCategoryName, + String groupingName, String resourceType, String status, String desc) { + super(); + this.action = action; + this.modifier = modifier; + this.categoryName = categoryName; + this.subCategoryName = subCategoryName; + this.groupingName = groupingName; + this.resourceType = resourceType; + this.status = status; + this.desc = desc; + } + + public ExpectedGroupingAudit() { + action = null; + modifier = null; + categoryName = null; + subCategoryName = null; + groupingName = null; + resourceType = null; + status = null; + desc = null; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public String getCategoryName() { + return categoryName; + } + + public void setCategoryName(String categoryName) { + this.categoryName = categoryName; + } + + public String getSubCategoryName() { + return subCategoryName; + } + + public void setSubCategoryName(String subCategoryName) { + this.subCategoryName = subCategoryName; + } + + public String getGroupingName() { + return groupingName; + } + + public void setGroupingName(String groupingName) { + this.groupingName = groupingName; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedProductAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedProductAudit.java new file mode 100644 index 0000000000..40b86fa528 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedProductAudit.java @@ -0,0 +1,142 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedProductAudit { + + String ACTION; + String MODIFIER; + String STATUS; + String DESC; + String RESOURCE_NAME; + String RESOURCE_TYPE; + String PREV_VERSION; + String CURR_VERSION; + String PREV_STATE; + String CURR_STATE; + String TIMESTAMP; + String SERVICE_INSTANCE_ID; + String COMMENT; + + public String getCOMMENT() { + return COMMENT; + } + + public void setCOMMENT(String cOMMENT) { + COMMENT = cOMMENT; + } + + public String getSERVICE_INSTANCE_ID() { + return SERVICE_INSTANCE_ID; + } + + public void setSERVICE_INSTANCE_ID(String sERVICE_INSTANCE_ID) { + SERVICE_INSTANCE_ID = sERVICE_INSTANCE_ID; + } + + public String getACTION() { + return ACTION; + } + + public void setACTION(String aCTION) { + ACTION = aCTION; + } + + public String getMODIFIER() { + return MODIFIER; + } + + public void setMODIFIER(String mODIFIER) { + MODIFIER = mODIFIER; + } + + public String getSTATUS() { + return STATUS; + } + + public void setSTATUS(String sTATUS) { + STATUS = sTATUS; + } + + public String getDESC() { + return DESC; + } + + public void setDESC(String dESC) { + DESC = dESC; + } + + public String getRESOURCE_NAME() { + return RESOURCE_NAME; + } + + public void setRESOURCE_NAME(String rESOURCE_NAME) { + RESOURCE_NAME = rESOURCE_NAME; + } + + public String getRESOURCE_TYPE() { + return RESOURCE_TYPE; + } + + public void setRESOURCE_TYPE(String rESOURCE_TYPE) { + RESOURCE_TYPE = rESOURCE_TYPE; + } + + public String getPREV_VERSION() { + return PREV_VERSION; + } + + public void setPREV_VERSION(String pREV_VERSION) { + PREV_VERSION = pREV_VERSION; + } + + public String getCURR_VERSION() { + return CURR_VERSION; + } + + public void setCURR_VERSION(String cURR_VERSION) { + CURR_VERSION = cURR_VERSION; + } + + public String getPREV_STATE() { + return PREV_STATE; + } + + public void setPREV_STATE(String pREV_STATE) { + PREV_STATE = pREV_STATE; + } + + public String getCURR_STATE() { + return CURR_STATE; + } + + public void setCURR_STATE(String cURR_STATE) { + CURR_STATE = cURR_STATE; + } + + public String getTIMESTAMP() { + return TIMESTAMP; + } + + public void setTIMESTAMP(String tIMESTAMP) { + TIMESTAMP = tIMESTAMP; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedResourceAuditJavaObject.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedResourceAuditJavaObject.java new file mode 100644 index 0000000000..7fdc899317 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedResourceAuditJavaObject.java @@ -0,0 +1,311 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedResourceAuditJavaObject { + + String ACTION; + String MODIFIER_NAME; + String MODIFIER_UID; + String STATUS; + String DESC; + String RESOURCE_NAME; + String RESOURCE_TYPE; + String PREV_VERSION; + String CURR_VERSION; + String PREV_STATE; + String CURR_STATE; + String TIMESTAMP; + String ARTIFACT_DATA; + String DPREV_STATUS; + String DCURR_STATUS; + String COMMENT; + String DID; + String TOPIC_NAME; + String TOSCA_NODE_TYPE; + String CURR_ARTIFACT_UUID; + String PREV_ARTIFACT_UUID; + String ARTIFACT_TIMEOUT; + String MODIFIER; + String SERVICE_INSTANCE_ID; + String CONSUMER_ID; + String RESOURCE_URL; + + // TODO: Remove comment +// String INVARIANT_UUID; +// +// public String getINVARIANT_UUID() { +// return INVARIANT_UUID; +// } +// +// public void setINVARIANT_UUID(String invariant_uuid) { +// INVARIANT_UUID = invariant_uuid; +// } + + public String getCONSUMER_ID() { + return CONSUMER_ID; + } + + public void setCONSUMER_ID(String consumer_id) { + CONSUMER_ID = consumer_id; + } + + public String getRESOURCE_URL() { + return RESOURCE_URL; + } + + public void setRESOURCE_URL(String resource_url) { + RESOURCE_URL = resource_url; + } + + public String getSERVICE_INSTANCE_ID() { + return SERVICE_INSTANCE_ID; + } + + public void setSERVICE_INSTANCE_ID(String sERVICE_INSTANCE_ID) { + SERVICE_INSTANCE_ID = sERVICE_INSTANCE_ID; + } + + public String getMODIFIER() { + return MODIFIER; + } + + public void setMODIFIER(String mODIFIER) { + MODIFIER = mODIFIER; + } + + public String getArtifactTimeout() { + return ARTIFACT_TIMEOUT; + } + + public void setArtifactTimeout(String artifactTimeout) { + this.ARTIFACT_TIMEOUT = artifactTimeout; + } + + public String getCurrArtifactUuid() { + return CURR_ARTIFACT_UUID; + } + + public void setCurrArtifactUuid(String currArtifactUuid) { + this.CURR_ARTIFACT_UUID = currArtifactUuid; + } + + public String getPrevArtifactUuid() { + return PREV_ARTIFACT_UUID; + } + + public void setPrevArtifactUuid(String prevArtifactUuid) { + this.PREV_ARTIFACT_UUID = prevArtifactUuid; + } + + public String getToscaNodeType() { + return TOSCA_NODE_TYPE; + } + + public void setToscaNodeType(String ToscaNodeType) { + this.TOSCA_NODE_TYPE = ToscaNodeType; + } + + public String getTopicName() { + return TOPIC_NAME; + } + + public void setTopicName(String topicName) { + this.TOPIC_NAME = topicName; + } + + public String getDistributionId() { + return DID; + } + + public void setDistributionId(String did) { + this.DID = did; + } + + public ExpectedResourceAuditJavaObject() { + super(); + // TODO Auto-generated constructor stub + } + + public ExpectedResourceAuditJavaObject(String action, String modifierName, String modifierUid, String status, + String desc, String resourceName, String resourceType, String prevVersion, String currVersion, + String prevState, String currState, String timestamp, String toscaNodesType, String timeout, + String modifier, String serviceInstanceId) { + super(); + this.ACTION = action; + this.MODIFIER_NAME = modifierName; + this.MODIFIER_UID = modifierUid; + this.STATUS = status; + this.DESC = desc; + this.RESOURCE_NAME = resourceName; + this.RESOURCE_TYPE = resourceType; + this.PREV_VERSION = prevVersion; + this.CURR_VERSION = currVersion; + this.PREV_STATE = prevState; + this.CURR_STATE = currState; + this.TIMESTAMP = timestamp; + this.TOSCA_NODE_TYPE = toscaNodesType; + this.ARTIFACT_TIMEOUT = timeout; + this.MODIFIER = modifier; + this.SERVICE_INSTANCE_ID = serviceInstanceId; + } + + public String getAction() { + return ACTION; + } + + public void setAction(String action) { + this.ACTION = action; + } + + public String getModifierName() { + return MODIFIER_NAME; + } + + public void setModifierName(String modifierName) { + this.MODIFIER_NAME = modifierName; + } + + public String getModifierUid() { + return MODIFIER_UID; + } + + public void setModifierUid(String modifierUid) { + this.MODIFIER_UID = modifierUid; + } + + public String getStatus() { + return STATUS; + } + + public void setStatus(String status) { + this.STATUS = status; + } + + public String getDesc() { + return DESC; + } + + public void setDesc(String desc) { + this.DESC = desc; + } + + public String getResourceName() { + return RESOURCE_NAME; + } + + public void setResourceName(String resourceName) { + this.RESOURCE_NAME = resourceName; + } + + public String getResourceType() { + return RESOURCE_TYPE; + } + + public void setResourceType(String resourceType) { + this.RESOURCE_TYPE = resourceType; + } + + public String getPrevVersion() { + return PREV_VERSION; + } + + public void setPrevVersion(String prevVersion) { + this.PREV_VERSION = prevVersion; + } + + public String getCurrVersion() { + return CURR_VERSION; + } + + public void setCurrVersion(String currVersion) { + this.CURR_VERSION = currVersion; + } + + public String getPrevState() { + return PREV_STATE; + } + + public void setPrevState(String prevState) { + this.PREV_STATE = prevState; + } + + public String getCurrState() { + return CURR_STATE; + } + + public void setCurrState(String currState) { + this.CURR_STATE = currState; + } + + public String getTimestamp() { + return TIMESTAMP; + } + + public void setTimestamp(String timestamp) { + this.TIMESTAMP = timestamp; + } + + public String getArtifactData() { + return ARTIFACT_DATA; + } + + public void setArtifactData(String artifactData) { + this.ARTIFACT_DATA = artifactData; + } + + public String getDprevStatus() { + return DPREV_STATUS; + } + + public void setDprevStatus(String dprevStatus) { + this.DPREV_STATUS = dprevStatus; + } + + public String getDcurrStatus() { + return DCURR_STATUS; + } + + public void setDcurrStatus(String dcurrStatus) { + this.DCURR_STATUS = dcurrStatus; + } + + public String getComment() { + return COMMENT; + } + + public void setComment(String comment) { + this.COMMENT = comment; + } + + @Override + public String toString() { + return "ExpectedResourceAuditJavaObject [ACTION=" + ACTION + ", STATUS=" + STATUS + ", DESC=" + DESC + + ", RESOURCE_NAME=" + RESOURCE_NAME + ", RESOURCE_TYPE=" + RESOURCE_TYPE + ", PREV_VERSION=" + + PREV_VERSION + ", CURR_VERSION=" + CURR_VERSION + ", PREV_STATE=" + PREV_STATE + ", CURR_STATE=" + + CURR_STATE + ", TIMESTAMP=" + TIMESTAMP + ", ARTIFACT_DATA=" + ARTIFACT_DATA + ", DPREV_STATUS=" + + DPREV_STATUS + ", DCURR_STATUS=" + DCURR_STATUS + ", COMMENT=" + COMMENT + ", DID=" + DID + + ", TOPIC_NAME=" + TOPIC_NAME + ", TOSCA_NODE_TYPE=" + TOSCA_NODE_TYPE + ", CURR_ARTIFACT_UUID=" + + CURR_ARTIFACT_UUID + ", PREV_ARTIFACT_UUID=" + PREV_ARTIFACT_UUID + ", ARTIFACT_TIMEOUT=" + + ARTIFACT_TIMEOUT + ", MODIFIER=" + MODIFIER + ", SERVICE_INSTANCE_ID=" + SERVICE_INSTANCE_ID + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedUserCRUDAudit.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedUserCRUDAudit.java new file mode 100644 index 0000000000..2bc8625057 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/expected/ExpectedUserCRUDAudit.java @@ -0,0 +1,98 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.expected; + +public class ExpectedUserCRUDAudit { + String action; + String modifier; + String status; + String desc; + String userBefore; + String userAfter; + + public ExpectedUserCRUDAudit(String action, String modifier, String status, String desc, String userBefore, + String userAfter) { + super(); + this.action = action; + this.modifier = modifier; + this.status = status; + this.desc = desc; + this.userBefore = userBefore; + this.userAfter = userAfter; + } + + public ExpectedUserCRUDAudit() { + action = null; + modifier = null; + userBefore = null; + userAfter = null; + status = null; + desc = null; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getModifier() { + return modifier; + } + + public void setModifier(String modifier) { + this.modifier = modifier; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getUserBefore() { + return userBefore; + } + + public void setUserBefore(String userBefore) { + this.userBefore = userBefore; + } + + public String getUserAfter() { + return userAfter; + } + + public void setUserAfter(String userAfter) { + this.userAfter = userAfter; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HeaderData.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HeaderData.java new file mode 100644 index 0000000000..2c23b08717 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HeaderData.java @@ -0,0 +1,114 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.http; + +public class HeaderData { + String contentMd5; + String contentType; + String HttpCspUserId; + String HttpCspFirstName; + String HttpCspLastName; + String HttpCspWsType; + String HttpIvRemoteAddress; + String HttpIvUser; + + public HeaderData() { + super(); + } + + public HeaderData(String contentMd5, String contentType, String httpCspUserId, String httpCspFirstName, + String httpCspLastName, String httpCspWsType, String httpIvRemoteAddress, String httpIvUser) { + super(); + this.contentMd5 = contentMd5; + this.contentType = contentType; + HttpCspUserId = httpCspUserId; + HttpCspFirstName = httpCspFirstName; + HttpCspLastName = httpCspLastName; + HttpCspWsType = httpCspWsType; + HttpIvRemoteAddress = httpIvRemoteAddress; + HttpIvUser = httpIvUser; + } + + public String getContentMd5() { + return contentMd5; + } + + public void setContentMd5(String contentMd5) { + this.contentMd5 = contentMd5; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getHttpCspUserId() { + return HttpCspUserId; + } + + public void setHttpCspUserId(String httpCspUserId) { + HttpCspUserId = httpCspUserId; + } + + public String getHttpCspFirstName() { + return HttpCspFirstName; + } + + public void setHttpCspFirstName(String httpCspFirstName) { + HttpCspFirstName = httpCspFirstName; + } + + public String getHttpCspLastName() { + return HttpCspLastName; + } + + public void setHttpCspLastName(String httpCspLastName) { + HttpCspLastName = httpCspLastName; + } + + public String getHttpCspWsType() { + return HttpCspWsType; + } + + public void setHttpCspWsType(String httpCspWsType) { + HttpCspWsType = httpCspWsType; + } + + public String getHttpIvRemoteAddress() { + return HttpIvRemoteAddress; + } + + public void setHttpIvRemoteAddress(String httpIvRemoteAddress) { + HttpIvRemoteAddress = httpIvRemoteAddress; + } + + public String getHttpIvUser() { + return HttpIvUser; + } + + public void setHttpIvUser(String httpIvUser) { + HttpIvUser = httpIvUser; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HeaderValue.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HeaderValue.java new file mode 100644 index 0000000000..4a2ad9ab82 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HeaderValue.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.http; + +public enum HeaderValue { + + APPLICATION_JSON("application/json"); + + String value; + + private HeaderValue(String value) { + this.value = value; + } + + public String getValue() { + + return value; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HttpHeaderEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HttpHeaderEnum.java new file mode 100644 index 0000000000..cd3beee150 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HttpHeaderEnum.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.http; + +public enum HttpHeaderEnum { + + Content_MD5("Content-MD5"), + USER_ID("USER_ID"), + HTTP_CSP_FIRSTNAME("HTTP_CSP_FIRSTNAME"), + HTTP_CSP_LASTNAME("HTTP_CSP_LASTNAME"), + HTTP_CSP_WSTYPE("HTTP_CSP_WSTYPE"), + HTTP_IV_REMOTE_ADDRESS("HTTP_IV_REMOTE_ADDRESS"), + HTTP_IV_USER("HTTP_IV_USER"), + HTTP_CSP_EMAIL("HTTP_CSP_EMAIL"), + CONTENT_TYPE("Content-Type"), + ACCEPT("Accept"), + X_ECOMP_REQUEST_ID_HEADER("X-ECOMP-RequestID"), + CACHE_CONTROL("Cache-Control"), + X_ECOMP_INSTANCE_ID("X-ECOMP-InstanceID"), + AUTHORIZATION("Authorization"), + CONTENT_LENGTH("Content-Length"), + CONTENT_DISPOSITION("Content-Disposition"), + HOST("Host"), + X_ECOMP_SERVICE_ID_HEADER("X-ECOMP-ServiceID"), + WWW_AUTHENTICATE("WWW-Authenticate"), + ECOMP_PASSWORD("password"), + ECOMP_USERNAME("username"); + + String value; + + private HttpHeaderEnum(String value) { + this.value = value; + } + + public String getValue() { + + return value; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HttpRequest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HttpRequest.java new file mode 100644 index 0000000000..c1f559a870 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/HttpRequest.java @@ -0,0 +1,889 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.http; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Scanner; + +import javax.net.ssl.HttpsURLConnection; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.annotation.NotThreadSafe; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.entity.mime.content.StringBody; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +public class HttpRequest { + static Logger logger = LoggerFactory.getLogger(HttpRequest.class.getName()); + + public RestResponse httpSendGet(String url, Map headers) throws IOException { + + RestResponse restResponse = new RestResponse(); + url = url.replaceAll("\\s", "%20"); + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + // optional default is GET + con.setRequestMethod("GET"); + // add request header + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + + } + + int responseCode = con.getResponseCode(); + logger.debug("Send GET http request, url: {}",url); + logger.debug("Response Code: {}",responseCode); + + StringBuffer response = new StringBuffer(); + String result; + + try { + + result = IOUtils.toString(con.getInputStream()); + response.append(result); + + } catch (Exception e) { + } + + try { + + result = IOUtils.toString(con.getErrorStream()); + response.append(result); + + } catch (Exception e) { + } + + logger.debug("Response body: {}" ,response); + + // print result + + restResponse.setErrorCode(responseCode); + + if (response != null) { + restResponse.setResponse(response.toString()); + } + + restResponse.setErrorCode(responseCode); + Map> headerFields = con.getHeaderFields(); + restResponse.setHeaderFields(headerFields); + String responseMessage = con.getResponseMessage(); + restResponse.setResponseMessage(responseMessage); + + con.disconnect(); + + return restResponse; + } + + public RestResponse httpsSendGet(String url, Map headers) throws IOException { + + RestResponse restResponse = new RestResponse(); + URL obj = new URL(url); + HttpsURLConnection con = (HttpsURLConnection) obj.openConnection(); + // optional default is GET + con.setRequestMethod("GET"); + // add request header + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + + } + + int responseCode = con.getResponseCode(); + logger.debug("Send GET http request, url: {}",url); + logger.debug("Response Code: {}",responseCode); + + StringBuffer response = new StringBuffer(); + try { + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + } catch (Exception e) { + logger.debug("response body is null"); + } + + String result; + + try { + + result = IOUtils.toString(con.getErrorStream()); + response.append(result); + + } catch (Exception e2) { + // result = null; + } + logger.debug("Response body: {}",response); + + // print result + + restResponse.setErrorCode(responseCode); + + if (response != null) { + restResponse.setResponse(response.toString()); + } + + restResponse.setErrorCode(responseCode); + // restResponse.setResponse(result); + Map> headerFields = con.getHeaderFields(); + restResponse.setHeaderFields(headerFields); + String responseMessage = con.getResponseMessage(); + restResponse.setResponseMessage(responseMessage); + + con.disconnect(); + + return restResponse; + } + + public RestResponse httpSendByMethod(String url, String method, String body, Map headers) + throws IOException { + + RestResponse restResponse = new RestResponse(); + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + + // add request method + con.setRequestMethod(method); + + // add request headers + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + + } + if (body != null && !body.isEmpty() && !method.equals("DELETE")) { + // Send post request + con.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(con.getOutputStream()); + wr.writeBytes(body); + wr.flush(); + wr.close(); + } + + // con.connect(); + + int responseCode = con.getResponseCode(); + logger.debug("Send {} http request, url: {}",method,url); + logger.debug("Response Code: {}",responseCode); + + StringBuffer response = new StringBuffer(); + + try { + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + } catch (Exception e) { + // response = null; + logger.debug("response body is null"); + } + + String result; + try { + + result = IOUtils.toString(con.getErrorStream()); + response.append(result); + + } catch (Exception e2) { + result = null; + } + logger.debug("Response body: {}",response); + + // print result + + restResponse.setErrorCode(responseCode); + // if (response == null) { + // restResponse.setResponse(null); + // } else { + // restResponse.setResponse(response.toString()); + // } + + if (response != null) { + restResponse.setResponse(response.toString()); + } + Map> headerFields = con.getHeaderFields(); + restResponse.setHeaderFields(headerFields); + String responseMessage = con.getResponseMessage(); + restResponse.setResponseMessage(responseMessage); + + con.disconnect(); + return restResponse; + + } + + public RestResponse sendHttpPost(String url, String body, Map headers) throws IOException { + + RestResponse restResponse = new RestResponse(); + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + + // add request method + con.setRequestMethod("POST"); + + // add request headers + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + } + + // Send post request + if (body != null) { + con.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(con.getOutputStream()); + wr.writeBytes(body); + wr.flush(); + wr.close(); + } + + // con.connect(); + + int responseCode = con.getResponseCode(); + logger.debug("Send POST http request, url: {}",url); + logger.debug("Response Code: {}",responseCode); + + StringBuffer response = new StringBuffer(); + try { + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + } catch (Exception e) { + logger.debug("response body is null"); + } + + String result; + + try { + + result = IOUtils.toString(con.getErrorStream()); + response.append(result); + + } catch (Exception e2) { + result = null; + } + logger.debug("Response body: {}",response); + + // print result + + restResponse.setErrorCode(responseCode); + + if (response != null) { + restResponse.setResponse(response.toString()); + } + + Map> headerFields = con.getHeaderFields(); + restResponse.setHeaderFields(headerFields); + String responseMessage = con.getResponseMessage(); + restResponse.setResponseMessage(responseMessage); + + con.disconnect(); + return restResponse; + + } + + public RestResponse httpSendPost(String url, String body, Map headers) throws IOException { + return httpSendPost(url, body, headers, "POST"); + } + + public RestResponse httpSendPut(String url, String body, Map headers) throws IOException { + return httpSendPost(url, body, headers, "PUT"); + } + + public RestResponse httpSendPost(String url, String body, Map headers, String methodType) + throws IOException { + + RestResponse restResponse = new RestResponse(); + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + + // add request method + con.setRequestMethod(methodType); + + // add request headers + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + } + + // Send post request + if (body != null) { + con.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(con.getOutputStream()); + wr.writeBytes(body); + wr.flush(); + wr.close(); + } + + // con.connect(); + + int responseCode = con.getResponseCode(); + logger.debug("Send POST http request, url: {}",url); + logger.debug("Response Code: {}",responseCode); + + StringBuffer response = new StringBuffer(); + try { + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + } catch (Exception e) { + logger.debug("response body is null"); + } + + String result; + + try { + + result = IOUtils.toString(con.getErrorStream()); + response.append(result); + + } catch (Exception e2) { + result = null; + } + logger.debug("Response body: {}",response); + + // print result + + restResponse.setErrorCode(responseCode); + + if (response != null) { + restResponse.setResponse(response.toString()); + } + + Map> headerFields = con.getHeaderFields(); + restResponse.setHeaderFields(headerFields); + String responseMessage = con.getResponseMessage(); + restResponse.setResponseMessage(responseMessage); + + con.disconnect(); + return restResponse; + + } + + public RestResponse httpSendDeleteWithBody2(String url, String body, Map headers) + throws ClientProtocolException, IOException { + + CloseableHttpClient httpclient = HttpClients.createDefault(); + RestResponse restResponse = new RestResponse(); + HttpDeleteWithBody httpDelete = new HttpDeleteWithBody(url); + + // add request headers + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + httpDelete.addHeader(key, value); + } + } + + // add body to request + StringEntity input = new StringEntity(body, ContentType.APPLICATION_JSON); + httpDelete.setEntity(input); + + // execute request + CloseableHttpResponse response = httpclient.execute(httpDelete); + + restResponse.setErrorCode(response.getStatusLine().getStatusCode()); + + return restResponse; + } + + public RestResponse httpSendDeleteWithBody(String url, String body, Map headers) + throws IOException { + + RestResponse restResponse = new RestResponse(); + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + + // add request method + con.setRequestMethod("DELETE"); + + // add request headers + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + } + + // Send post request + con.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(con.getOutputStream()); + wr.writeBytes(body); + wr.flush(); + wr.close(); + + // con.connect(); + + int responseCode = con.getResponseCode(); + logger.debug("Send DELETE http request, url: {}",url); + logger.debug("Response Code: {}",responseCode); + + StringBuffer response = new StringBuffer(); + try { + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + } catch (Exception e) { + logger.debug("response body is null"); + } + + String result; + + try { + + result = IOUtils.toString(con.getErrorStream()); + response.append(result); + + } catch (Exception e2) { + result = null; + } + logger.debug("Response body: {}", response); + + // print result + + restResponse.setErrorCode(responseCode); + + if (response != null) { + restResponse.setResponse(response.toString()); + } + + Map> headerFields = con.getHeaderFields(); + restResponse.setHeaderFields(headerFields); + String responseMessage = con.getResponseMessage(); + restResponse.setResponseMessage(responseMessage); + + con.disconnect(); + return restResponse; + + } + + public RestResponse httpSendPostWithOutBody(String url, Map headers) throws IOException { + + RestResponse restResponse = new RestResponse(); + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + + // add request method + con.setRequestMethod("POST"); + + // add request headers + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + } + + // con.connect(); + + int responseCode = con.getResponseCode(); + logger.debug("Send POST http request, url: {}",url); + logger.debug("Response Code: {}",responseCode); + + StringBuffer response = new StringBuffer(); + + try { + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + } catch (Exception e) { + // response = null; + logger.debug("response body is null"); + } + + String result; + try { + + result = IOUtils.toString(con.getErrorStream()); + response.append(result); + + } catch (Exception e2) { + result = null; + } + logger.debug("Response body: {}",response); + + // print result + + restResponse.setErrorCode(responseCode); + // if (response == null) { + // restResponse.setResponse(null); + // } else { + // restResponse.setResponse(response.toString()); + // } + + if (response != null) { + restResponse.setResponse(response.toString()); + } + + Map> headerFields = con.getHeaderFields(); + restResponse.setHeaderFields(headerFields); + String responseMessage = con.getResponseMessage(); + restResponse.setResponseMessage(responseMessage); + + con.disconnect(); + return restResponse; + + } + + public RestResponse httpSendPostMultipart(String url, Map headers, String jsonLocation, + String zipLocation) throws IOException { + + Gson gson = new Gson(); + String gsonToSend = null; + RestResponse restResponse = new RestResponse(); + BufferedReader br = null; + // + // + // + // + // try { + // + // String sCurrentLine; + // + // br = new BufferedReader(new FileReader(jsonLocation)); + // + // while ((sCurrentLine = br.readLine()) != null) { + // System.out.println(sCurrentLine); + // } + // + // } catch (IOException e) { + // e.printStackTrace(); + // } finally { + // try { + // if (br != null)br.close(); + // gsonToSend = br.toString(); + // } catch (IOException ex) { + // ex.printStackTrace(); + // } + // } + + gsonToSend = new Scanner(new File(jsonLocation)).useDelimiter("\\Z").next(); + logger.debug("gsonToSend: {}",gsonToSend); + + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + mpBuilder.addPart("resourceZip", new FileBody(new File(zipLocation))); + mpBuilder.addPart("resourceMetadata", new StringBody(gsonToSend, ContentType.APPLICATION_JSON)); + + HttpPost httpPost = new HttpPost(url); + httpPost.addHeader("USER_ID", "adminid"); + httpPost.setEntity(mpBuilder.build()); + + CloseableHttpClient client = HttpClients.createDefault(); + CloseableHttpResponse response = client.execute(httpPost); + try { + logger.debug("----------------------------------------"); + logger.debug("response.getStatusLine(): {}",response.getStatusLine()); + HttpEntity resEntity = response.getEntity(); + if (resEntity != null) { + logger.debug("Response content length: {}",resEntity.getContentLength()); + } + EntityUtils.consume(resEntity); + } finally { + + response.close(); + client.close(); + } + + restResponse.setErrorCode(response.getStatusLine().getStatusCode()); + restResponse.setResponse(response.getEntity().toString()); + + return restResponse; + + } + + public RestResponse httpSendPostWithAuth(String url, String body, Map headers, String username, + String password) throws IOException { + + String userPassword = username + ":" + password; + String encoding = Base64.encodeBase64String(userPassword.getBytes()); + RestResponse restResponse = new RestResponse(); + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + + // add request method + con.setRequestMethod("POST"); + + con.setRequestProperty("Authorization", "Basic " + encoding); + + // add request headers + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + + } + + // Send post request + con.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(con.getOutputStream()); + wr.writeBytes(body); + wr.flush(); + wr.close(); + + // con.connect(); + + int responseCode = con.getResponseCode(); + logger.debug("Send POST http request, url: {}",url); + logger.debug("Response Code: {}",responseCode); + + StringBuffer response = new StringBuffer(); + try { + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + } catch (Exception e) { + response = null; + + } + logger.debug("Response body: {}",response); + + // print result + + restResponse.setErrorCode(responseCode); + if (response == null) { + restResponse.setResponse(null); + } else { + restResponse.setResponse(response.toString()); + } + + Map> headerFields = con.getHeaderFields(); + restResponse.setHeaderFields(headerFields); + String responseMessage = con.getResponseMessage(); + restResponse.setResponseMessage(responseMessage); + + con.disconnect(); + return restResponse; + + } + + public RestResponse httpSendDelete(String url, Map headers) throws IOException { + + RestResponse restResponse = new RestResponse(); + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + + if (headers != null) { + for (Entry header : headers.entrySet()) { + String key = header.getKey(); + String value = header.getValue(); + con.setRequestProperty(key, value); + } + + } + + con.setDoOutput(true); + con.setRequestMethod("DELETE"); + int responseCode = con.getResponseCode(); + logger.debug("Send DELETE http request, url: {}",url); + logger.debug("Response Code: {}",responseCode); + + StringBuffer response = new StringBuffer(); + + try { + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + } catch (Exception e) { + logger.debug("response body is null"); + } + + String result; + + try { + + result = IOUtils.toString(con.getErrorStream()); + response.append(result); + + } catch (Exception e2) { + result = null; + } + logger.debug("Response body: {}",response); + + // print result + + restResponse.setErrorCode(responseCode); + + if (response != null) { + restResponse.setResponse(response.toString()); + } + + restResponse.setErrorCode(con.getResponseCode()); + Map> headerFields = con.getHeaderFields(); + restResponse.setHeaderFields(headerFields); + String responseMessage = con.getResponseMessage(); + restResponse.setResponseMessage(responseMessage); + + con.disconnect(); + + return restResponse; + } + + public static RestResponse sendHttpPostWithEntity(HttpEntity requestEntity, String url, Map headers) + throws IOException, ClientProtocolException { + CloseableHttpResponse response = null; + CloseableHttpClient client = HttpClients.createDefault(); + try { + HttpPost httpPost = new HttpPost(url); + RestResponse restResponse = new RestResponse(); + for (Entry entry : headers.entrySet()) { + httpPost.addHeader(entry.getKey(), entry.getValue()); + } + + httpPost.setEntity(requestEntity); + response = client.execute(httpPost); + HttpEntity responseEntity = response.getEntity(); + String responseBody = null; + if (responseEntity != null) { + InputStream instream = responseEntity.getContent(); + StringWriter writer = new StringWriter(); + IOUtils.copy(instream, writer); + responseBody = writer.toString(); + try { + + } finally { + instream.close(); + } + } + + restResponse.setErrorCode(response.getStatusLine().getStatusCode()); + restResponse.setResponse(responseBody); + + return restResponse; + + } finally { + closeResponse(response); + closeHttpClient(client); + + } + } + + private static void closeHttpClient(CloseableHttpClient client) { + try { + if (client != null) { + client.close(); + } + } catch (IOException e) { + logger.debug("failed to close client or response: ", e); + } + } + + private static void closeResponse(CloseableHttpResponse response) { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + logger.debug("failed to close client or response: ", e); + } + } + + @NotThreadSafe + class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase { + public static final String METHOD_NAME = "DELETE"; + + public String getMethod() { + return METHOD_NAME; + } + + public HttpDeleteWithBody(final String uri) { + super(); + setURI(URI.create(uri)); + } + + public HttpDeleteWithBody(final URI uri) { + super(); + setURI(uri); + } + + public HttpDeleteWithBody() { + super(); + } + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/MustHeaders.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/MustHeaders.java new file mode 100644 index 0000000000..6937608d2a --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/MustHeaders.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.http; + +import java.util.HashMap; +import java.util.Map; + +public class MustHeaders { + + private Map headers = new HashMap(); + + public MustHeaders(HeaderData headerData) { + + super(); + headers.put(HttpHeaderEnum.Content_MD5.getValue(), headerData.getContentMd5()); + headers.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), headerData.getContentType()); + headers.put(HttpHeaderEnum.ACCEPT.getValue(), headerData.getContentType()); + headers.put(HttpHeaderEnum.USER_ID.getValue(), headerData.getHttpCspUserId()); + headers.put(HttpHeaderEnum.HTTP_CSP_FIRSTNAME.getValue(), headerData.getHttpCspFirstName()); + headers.put(HttpHeaderEnum.HTTP_CSP_LASTNAME.getValue(), headerData.getHttpCspLastName()); + headers.put(HttpHeaderEnum.HTTP_CSP_WSTYPE.getValue(), headerData.getHttpCspWsType()); + headers.put(HttpHeaderEnum.HTTP_IV_REMOTE_ADDRESS.getValue(), headerData.getHttpIvRemoteAddress()); + headers.put(HttpHeaderEnum.HTTP_IV_USER.getValue(), headerData.getHttpIvUser()); + + } + + public MustHeaders() { + super(); + } + + public Map getMap() { + return headers; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/RestResponse.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/RestResponse.java new file mode 100644 index 0000000000..f11d35a646 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/http/RestResponse.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes.http; + +import java.util.List; +import java.util.Map; + +public class RestResponse { + + Integer errorCode; + String response; + Map> headerFields; + String responseMessage; + + public RestResponse() { + super(); + } + + public RestResponse(Integer errorCode, String response, Map> headerFields, + String responseMessage) { + super(); + this.errorCode = errorCode; + this.response = response; + this.headerFields = headerFields; + this.responseMessage = responseMessage; + } + + public Integer getErrorCode() { + return errorCode; + } + + public void setErrorCode(Integer errorCode) { + this.errorCode = errorCode; + } + + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + public Map> getHeaderFields() { + return headerFields; + } + + public void setHeaderFields(Map> headerFields) { + this.headerFields = headerFields; + } + + public String getResponseMessage() { + return responseMessage; + } + + public void setResponseMessage(String responseMessage) { + this.responseMessage = responseMessage; + } + + @Override + public String toString() { + return "RestResponse [errorCode=" + errorCode + ", response=" + response + ", headerFields=" + headerFields + + ", responseMessage=" + responseMessage + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/TODO/ImportCapabilityTypeCITest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/TODO/ImportCapabilityTypeCITest.java new file mode 100644 index 0000000000..71e75c9a1e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/TODO/ImportCapabilityTypeCITest.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.TODO; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; +import org.testng.AssertJUnit; +import java.io.File; +import java.io.IOException; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.DbUtils.TitanState; + +import fj.data.Either; + +public class ImportCapabilityTypeCITest { + public static final DbUtils DbUtils = new DbUtils(); + + @AfterClass + public static void afterClass() { + DbUtils.shutDowntitan(); + } + + static Config config = Config.instance(); + + // private final String IMPORT_CAPABILITY_TYPES_PATH = + // "src/test/resources/CI/importResourceTests/import_capabilitiesTypes/"; + + @Test + public void testAddingCapabilityTypes() throws IOException { + TitanState originalState = DbUtils.getCurrentTitanState(); + + String importResourceDir = config.getImportResourceConfigDir(); + + String capabilityTypes = importResourceDir + File.separator + "capabilityTypesCi.zip"; + // importCapabilityType("src/test/resources/CI/importResource/capabilityTypesCi.zip"); + importCapabilityType(capabilityTypes); + Either eitherVertex = DbUtils.getVertexByUId("tosca.capabilities.Test.Ci"); + AssertJUnit.assertTrue(eitherVertex.isLeft()); + DbUtils.restoreToTitanState(originalState); + eitherVertex = DbUtils.getVertexByUId("tosca.capabilities.Test.Ci"); + AssertJUnit.assertTrue(eitherVertex.isRight()); + } + + @Test + public void AddingCapabilityNotFound() throws IOException { + TitanState originalState = DbUtils.getCurrentTitanState(); + String importResourceTestsDir = config.getImportResourceTestsConfigDir(); + String capabilitiesTests = importResourceTestsDir + File.separator + "capabilityTypesCi.zip"; + importCapabilityType(capabilitiesTests); + Either eitherVertex = DbUtils.getVertexByUId("tosca.capabilities.NonExsitingCapability"); + AssertJUnit.assertTrue(eitherVertex.isRight()); + DbUtils.restoreToTitanState(originalState); + } + + public static Integer importAllCapabilityTypes() throws IOException { + + String importResourceDir = config.getImportResourceConfigDir() + File.separator + "capabilityTypes.zip"; + // return + // importCapabilityType("src/test/resources/CI/importResource/capabilityTypes.zip"); + return importCapabilityType(importResourceDir); + } + + private static Integer importCapabilityType(String filePath) throws IOException { + Config config = Utils.getConfig(); + CloseableHttpResponse response = null; + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + + mpBuilder.addPart("capabilityTypeZip", new FileBody(new File(filePath))); + + String url = String.format(Urls.IMPORT_CAPABILITY_TYPE, config.getCatalogBeHost(), config.getCatalogBePort()); + + CloseableHttpClient client = HttpClients.createDefault(); + try { + HttpPost httpPost = new HttpPost(url); + httpPost.addHeader("USER_ID", "jh0003"); + httpPost.setEntity(mpBuilder.build()); + response = client.execute(httpPost); + return response.getStatusLine().getStatusCode(); + } finally { + closeResponse(response); + closeHttpClient(client); + + } + } + + private static void closeHttpClient(CloseableHttpClient client) { + try { + if (client != null) { + client.close(); + } + } catch (IOException e) { + System.out.println("failed to close client or response: " + e.getMessage()); + } + } + + private static void closeResponse(CloseableHttpResponse response) { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + System.out.println("failed to close client or response: " + e.getMessage()); + } + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ArtifactServletTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ArtifactServletTest.java new file mode 100644 index 0000000000..7e363202bb --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ArtifactServletTest.java @@ -0,0 +1,658 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.artifacts; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.codehaus.jackson.map.ObjectMapper; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ArtifactUiDownloadData; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.general.FileUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +import fj.data.Either; + +public class ArtifactServletTest extends ComponentBaseTest { + + private static Logger log = LoggerFactory.getLogger(ArtifactServletTest.class.getName()); + protected static final String UPLOAD_ARTIFACT_PAYLOAD = "UHVUVFktVXNlci1LZXktRmlsZS0yOiBzc2gtcnNhDQpFbmNyeXB0aW9uOiBhZXMyNTYtY2JjDQpDb21tZW5wOA0K"; + protected static final String UPLOAD_ARTIFACT_NAME = "TLV_prv.ppk"; + protected Config config = Config.instance(); + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json"; + protected Gson gson = new Gson(); + protected JSONParser jsonParser = new JSONParser(); + protected String serviceVersion; + protected Resource resourceDetailsVFCcomp; + protected Service defaultService1; + + protected User sdncUserDetails; + + @Rule + public static TestName name = new TestName(); + + public ArtifactServletTest() { + super(name, ArtifactServletTest.class.getName()); + + } + + @BeforeMethod + public void create() throws Exception { + + sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + Either resourceDetailsVFCcompE = AtomicOperationUtils + .createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.COMPUTE, + ResourceCategoryEnum.APPLICATION_L4_APP_SERVER, UserRoleEnum.DESIGNER, true); + resourceDetailsVFCcomp = resourceDetailsVFCcompE.left().value(); + Either defaultService1e = AtomicOperationUtils + .createDefaultService(UserRoleEnum.DESIGNER, true); + defaultService1 = defaultService1e.left().value(); + } + + @Test + public void upadteArtifactWithPayLoadToResourcseTest() throws Exception { + + ArtifactReqDetails defaultArtifact = ElementFactory.getDefaultArtifact(); + + RestResponse response = ArtifactRestUtils.addInformationalArtifactToResource(defaultArtifact, sdncUserDetails, + resourceDetailsVFCcomp.getUniqueId()); + int status = response.getErrorCode(); + AssertJUnit.assertEquals("add informational artifact request returned status: " + response.getErrorCode(), 200, + status); + + defaultArtifact.setDescription("kjglkh"); + defaultArtifact.setArtifactName("install_apache.sh"); + defaultArtifact.setArtifactType("SHELL"); + defaultArtifact.setPayload("new payload"); + + response = ArtifactRestUtils.updateInformationalArtifactToResource(defaultArtifact, sdncUserDetails, + resourceDetailsVFCcomp.getUniqueId()); + status = response.getErrorCode(); + AssertJUnit.assertEquals("failed to update artifact metatdata: " + response.getErrorCode(), 200, status); + + response = ArtifactRestUtils.deleteInformationalArtifactFromResource(resourceDetailsVFCcomp.getUniqueId(), + defaultArtifact, sdncUserDetails); + status = response.getErrorCode(); + AssertJUnit.assertEquals("failed to remove artifact: " + response.getErrorCode(), 200, status); + + } + + @Test + public void createAndUpdateArtifactToInterface() throws Exception { + + CloseableHttpResponse response; + int status; + CloseableHttpClient httpclient = HttpClients.createDefault(); + + try { + // upload artifact to interface + String interfaceName = "Standard"; + String operationName = "configure"; + + String userBodyJson = createUploadArtifactBodyJson(); + String url = String.format(Urls.UPLOAD_ARTIFACT_BY_INTERFACE_TO_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId(), interfaceName, operationName); + + HttpPost httpPost = createPostAddArtifactRequeast(userBodyJson, url, true); + response = httpclient.execute(httpPost); + status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("response code is not 200, returned :" + status, status, 200); + + // get artifact uniqueId + String artifactId = getLifecycleArtifactUid(response); + + Map jsonBody = new HashMap(); + jsonBody.put("artifactName", "TLV_prv.ppk"); + jsonBody.put("artifactDisplayName", "configure"); + jsonBody.put("artifactType", "SHELL"); + jsonBody.put("mandatory", "false"); + String newDescription = "new something"; + jsonBody.put("description", newDescription); + jsonBody.put("artifactLabel", "configure"); + userBodyJson = gson.toJson(jsonBody); + + url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_BY_INTERFACE_TO_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId(), interfaceName, operationName, + artifactId); + + httpPost = createPostAddArtifactRequeast(userBodyJson, url, false); + + response = httpclient.execute(httpPost); + status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("response code is not 200, returned :" + status, 200, status); + + url = String.format(Urls.GET_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceDetailsVFCcomp.getUniqueId()); + HttpGet httpGet = createGetRequest(url); + response = httpclient.execute(httpGet); + AssertJUnit.assertTrue(response.getStatusLine().getStatusCode() == 200); + String responseString = new BasicResponseHandler().handleResponse(response); + + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + responseMap = (JSONObject) responseMap.get("interfaces"); + responseMap = (JSONObject) responseMap.get(interfaceName.toLowerCase()); + responseMap = (JSONObject) responseMap.get("operations"); + responseMap = (JSONObject) responseMap.get(operationName.toLowerCase()); + responseMap = (JSONObject) responseMap.get("implementation"); + String description = (String) responseMap.get("description"); + + AssertJUnit.assertEquals("the new description value was not set", newDescription, description); + + // delete artifact + url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_BY_INTERFACE_TO_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId(), interfaceName, operationName, + artifactId); + HttpDelete httpDelete = createDeleteArtifactRequest(url); + + response = httpclient.execute(httpDelete); + status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("response code is not 200, returned :" + status, status, 200); + } finally { + httpclient.close(); + } + + } + + protected String createUploadArtifactBodyJson() { + Map jsonBody = new HashMap(); + jsonBody.put("artifactName", UPLOAD_ARTIFACT_NAME); + jsonBody.put("artifactDisplayName", "configure"); + jsonBody.put("artifactType", "SHELL"); + jsonBody.put("mandatory", "false"); + jsonBody.put("description", "ff"); + jsonBody.put("payloadData", UPLOAD_ARTIFACT_PAYLOAD); + jsonBody.put("artifactLabel", "configure"); + return gson.toJson(jsonBody); + } + + protected ArtifactDefinition getArtifactDataFromJson(String json) { + Gson gson = new Gson(); + ArtifactDefinition artifact = new ArtifactDefinition(); + artifact = gson.fromJson(json, ArtifactDefinition.class); + + /* + * atifact.setArtifactName(UPLOAD_ARTIFACT_NAME); + * artifact.setArtifactDisplayName("configure"); + * artifact.setArtifactType("SHELL"); artifact.setMandatory(false); + * artifact.setDescription("ff"); + * artifact.setPayloadData(UPLOAD_ARTIFACT_PAYLOAD); + * artifact.setArtifactLabel("configure"); + */ + return artifact; + } + + protected HttpGet createGetRequest(String url) { + HttpGet httpGet = new HttpGet(url); + httpGet.addHeader(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + httpGet.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + httpGet.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + return httpGet; + } + + protected String getArtifactUid(HttpResponse response) throws HttpResponseException, IOException, ParseException { + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + String artifactId = (String) responseMap.get("uniqueId"); + return artifactId; + } + + protected String getArtifactEsId(HttpResponse response) throws HttpResponseException, IOException, ParseException { + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + String esId = (String) responseMap.get("EsId"); + return esId; + } + + protected ArtifactDefinition addArtifactDataFromResponse(HttpResponse response, ArtifactDefinition artifact) + throws HttpResponseException, IOException, ParseException { + // String responseString = new + // BasicResponseHandler().handleResponse(response); + HttpEntity entity = response.getEntity(); + String responseString = EntityUtils.toString(entity); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + artifact.setEsId((String) responseMap.get("esId")); + artifact.setUniqueId((String) responseMap.get("uniqueId")); + artifact.setArtifactGroupType(ArtifactGroupTypeEnum.findType((String) responseMap.get("artifactGroupType"))); + artifact.setTimeout(((Long) responseMap.get("timeout")).intValue()); + return artifact; + } + + protected String getLifecycleArtifactUid(CloseableHttpResponse response) + throws HttpResponseException, IOException, ParseException { + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + responseMap = (JSONObject) responseMap.get("implementation"); + String artifactId = (String) responseMap.get("uniqueId"); + return artifactId; + } + + protected HttpDelete createDeleteArtifactRequest(String url) { + HttpDelete httpDelete = new HttpDelete(url); + httpDelete.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + httpDelete.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + return httpDelete; + } + + protected HttpPost createPostAddArtifactRequeast(String jsonBody, String url, boolean addMd5Header) + throws UnsupportedEncodingException { + HttpPost httppost = new HttpPost(url); + httppost.addHeader(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + httppost.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + httppost.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + if (addMd5Header) { + httppost.addHeader(HttpHeaderEnum.Content_MD5.getValue(), GeneralUtility.calculateMD5ByString(jsonBody)); + } + StringEntity input = new StringEntity(jsonBody); + input.setContentType("application/json"); + httppost.setEntity(input); + log.debug("Executing request {}", httppost.getRequestLine()); + return httppost; + } + + protected String createLoadArtifactBody() { + Map json = new HashMap(); + json.put("artifactName", "install_apache2.sh"); + json.put("artifactType", "SHELL"); + json.put("description", "ddd"); + json.put("payloadData", "UEsDBAoAAAAIAAeLb0bDQz"); + json.put("artifactLabel", "name123"); + + String jsonStr = gson.toJson(json); + return jsonStr; + } + + protected void checkDeleteResponse(RestResponse response) { + BaseRestUtils.checkStatusCode(response, "delete request failed", false, 204, 404); + } + + protected ArtifactUiDownloadData getArtifactUiDownloadData(String artifactUiDownloadDataStr) throws Exception { + + ObjectMapper mapper = new ObjectMapper(); + try { + ArtifactUiDownloadData artifactUiDownloadData = mapper.readValue(artifactUiDownloadDataStr, + ArtifactUiDownloadData.class); + return artifactUiDownloadData; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + // TODO + // @Ignore("") + @Test + public void addArtifactNoPayLoadToResourcseTest() throws Exception { + ArtifactReqDetails defaultArtifact = ElementFactory.getDefaultArtifact(); + defaultArtifact.setPayload(null); + + RestResponse response = ArtifactRestUtils.addInformationalArtifactToResource(defaultArtifact, sdncUserDetails, + resourceDetailsVFCcomp.getUniqueId()); + int status = response.getErrorCode(); + AssertJUnit.assertTrue(status == 400); + + } + + @Test + public void upadteArtifactNoPayLoadToResourcseTest() throws Exception { + + ArtifactReqDetails defaultArtifact = ElementFactory.getDefaultArtifact(); + + RestResponse response = ArtifactRestUtils.addInformationalArtifactToResource(defaultArtifact, sdncUserDetails, + resourceDetailsVFCcomp.getUniqueId()); + int status = response.getErrorCode(); + AssertJUnit.assertEquals("add informational artifact request returned status: " + response.getErrorCode(), 200, + status); + + defaultArtifact.setDescription("kjglkh"); + defaultArtifact.setArtifactName("install_apache.sh"); + defaultArtifact.setArtifactType("SHELL"); + defaultArtifact.setPayload(null); + + response = ArtifactRestUtils.updateInformationalArtifactToResource(defaultArtifact, sdncUserDetails, + resourceDetailsVFCcomp.getUniqueId()); + status = response.getErrorCode(); + AssertJUnit.assertEquals("failed to update artifact metatdata: " + response.getErrorCode(), 200, status); + + response = ArtifactRestUtils.deleteInformationalArtifactFromResource(resourceDetailsVFCcomp.getUniqueId(), + defaultArtifact, sdncUserDetails); + status = response.getErrorCode(); + AssertJUnit.assertEquals("failed to remove artifact: " + response.getErrorCode(), 200, status); + + } + + // TODO + @Test(enabled = false) + public void updateDeploymentArtifactToResourcseTest() throws Exception { + + ArtifactReqDetails defaultArtifact = ElementFactory.getDefaultDeploymentArtifactForType("HEAT"); + + RestResponse response = ArtifactRestUtils.addInformationalArtifactToResource(defaultArtifact, sdncUserDetails, + resourceDetailsVFCcomp.getUniqueId()); + int status = response.getErrorCode(); + AssertJUnit.assertEquals("add informational artifact request returned status: " + response.getErrorCode(), 200, + status); + + response = ArtifactRestUtils.updateInformationalArtifactToResource(defaultArtifact, sdncUserDetails, + resourceDetailsVFCcomp.getUniqueId()); + status = response.getErrorCode(); + AssertJUnit.assertEquals("failed to update artifact metatdata: " + response.getErrorCode(), 200, status); + + response = ArtifactRestUtils.deleteInformationalArtifactFromResource(resourceDetailsVFCcomp.getUniqueId(), + defaultArtifact, sdncUserDetails); + status = response.getErrorCode(); + AssertJUnit.assertEquals("failed to remove artifact: " + response.getErrorCode(), 200, status); + + } + + // -------------------- + @Test + public void addArtifactToResourcse_AlreadyExistsTest() throws Exception { + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + String jsonBody = createLoadArtifactBody(); + + String url = String.format(Urls.ADD_ARTIFACT_TO_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId()); + HttpPost httppost = createPostAddArtifactRequeast(jsonBody, url, true); + CloseableHttpResponse response = httpclient.execute(httppost); + int status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertTrue("failed to add artifact", status == 200); + + String artifactId = getArtifactUid(response); + + httppost = createPostAddArtifactRequeast(jsonBody, url, true); + response = httpclient.execute(httppost); + status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("the returned status code is in correct", status, 400); + + url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId(), artifactId); + HttpDelete httpDelete = createDeleteArtifactRequest(url); + response = httpclient.execute(httpDelete); + status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertTrue("failed to remove artifact", status == 200); + } finally { + httpclient.close(); + } + + } + + @Test + public void addArtifactToResourcse_MissingContentTest() throws Exception { + + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + Map json = new HashMap(); + json.put("description", "desc"); + json.put("payloadData", "UEsDBAoAAAAIAAeLb0bDQz"); + json.put("Content-MD5", "YTg2Mjg4MWJhNmI5NzBiNzdDFkMWI="); + + String jsonBody = gson.toJson(json); + + String url = String.format(Urls.ADD_ARTIFACT_TO_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId()); + HttpPost httppost = createPostAddArtifactRequeast(jsonBody, url, true); + CloseableHttpResponse response = httpclient.execute(httppost); + int status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("the returned status code is in correct", status, 400); + } finally { + httpclient.close(); + } + + } + + @Test + public void addArtifactToResourcse_MissingMd5Test() throws Exception { + + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + HashMap json = new HashMap(); + json.put("artifactName", "install_apache.sh"); + json.put("artifactType", "SHELL"); + json.put("description", "kjglkh"); + json.put("payloadData", "UEsDBYTEIWUYIFHWFMABCNAoAAAAIAAeLb0bDQz"); + json.put("artifactLabel", "name123"); + String url = String.format(Urls.ADD_ARTIFACT_TO_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId()); + String jsonBody = gson.toJson(json); + HttpPost httppost = createPostAddArtifactRequeast(jsonBody, url, false); + CloseableHttpResponse response = httpclient.execute(httppost); + int status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertTrue("failed to update artifact metatdata", status == 400); + } finally { + httpclient.close(); + } + + } + + @Test + public void deleteArtifact_NotExistsTest() throws Exception { + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + String url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId(), "someFakeId"); + HttpDelete httpDelete = createDeleteArtifactRequest(url); + CloseableHttpResponse response = httpclient.execute(httpDelete); + int status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("the returned status code is in correct", status, 404); + } finally { + httpclient.close(); + } + + } + + @Test + public void createAndRemoveArtifactToInterface() throws Exception { + CloseableHttpResponse response; + int status; + CloseableHttpClient httpclient = HttpClients.createDefault(); + + try { + // upload artifact to interface + String interfaceName = "Standard"; + String operationName = "configure"; + + String userBodyJson = createUploadArtifactBodyJson(); + String url = String.format(Urls.UPLOAD_ARTIFACT_BY_INTERFACE_TO_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId(), interfaceName, operationName); + + HttpPost httpPost = createPostAddArtifactRequeast(userBodyJson, url, true); + response = httpclient.execute(httpPost); + status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("response code is not 200, returned :" + status, status, 200); + + // get artifact uniqueId + String artifactId = getLifecycleArtifactUid(response); + + // delete artifact + url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_BY_INTERFACE_TO_RESOURCE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetailsVFCcomp.getUniqueId(), interfaceName, operationName, + artifactId); + HttpDelete httpDelete = createDeleteArtifactRequest(url); + + response = httpclient.execute(httpDelete); + status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("response code is not 200, returned :" + status, status, 200); + } finally { + httpclient.close(); + } + + } + + @Test + public void addArtifactToServiceTest() throws Exception { + + CloseableHttpClient httpclient = HttpClients.createDefault(); + + try { + String jsonStr = createLoadArtifactBody(); + + String url = String.format(Urls.ADD_ARTIFACT_TO_SERVICE, config.getCatalogBeHost(), + config.getCatalogBePort(), defaultService1.getUniqueId()); + HttpPost httpPost = createPostAddArtifactRequeast(jsonStr, url, true); + CloseableHttpResponse result = httpclient.execute(httpPost); + int status = result.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("response code is not 200, returned :" + status, 200, status); + + String artifactId = getArtifactUid(result); + + url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_SERVICE, config.getCatalogBeHost(), + config.getCatalogBePort(), defaultService1.getUniqueId(), artifactId); + HttpDelete httpDelete = createDeleteArtifactRequest(url); + + result = httpclient.execute(httpDelete); + status = result.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("response code is not 200, returned :" + status, 200, status); + } finally { + RestResponse response = ServiceRestUtils.deleteService(defaultService1.getName(), serviceVersion, + sdncUserDetails); + checkDeleteResponse(response); + httpclient.close(); + } + } + + @Test + public void addArtifactNotSupportedTypeToServiceTest() throws Exception { + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + Map json = new HashMap(); + json.put("artifactName", "install_apache.sh"); + json.put("artifactType", "SHELL11"); + json.put("description", "fff"); + json.put("payloadData", "UEsDBAoAAAAIAAeLb0bDQz"); + json.put("artifactLabel", "name123"); + + String jsonStr = gson.toJson(json); + + String url = String.format(Urls.ADD_ARTIFACT_TO_SERVICE, config.getCatalogBeHost(), + config.getCatalogBePort(), defaultService1.getUniqueId()); + + HttpPost httpPost = createPostAddArtifactRequeast(jsonStr, url, true); + CloseableHttpResponse result = httpclient.execute(httpPost); + int status = result.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("response code is not 400, returned :" + status, 400, status); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name()); + + String responseString = EntityUtils.toString(result.getEntity()); + + JSONObject map = (JSONObject) jsonParser.parse(responseString); + JSONObject requestError = (JSONObject) map.get("requestError"); + JSONObject serviceException = (JSONObject) requestError.get("serviceException"); + + String msgId = (String) serviceException.get("messageId"); + AssertJUnit.assertEquals("message id did not match expacted", errorInfo.getMessageId(), msgId); + + String text = (String) serviceException.get("text"); + AssertJUnit.assertEquals("text did not match expacted", errorInfo.getMessage(), text); + + JSONArray variables = (JSONArray) serviceException.get("variables"); + String type = (String) variables.get(0); + AssertJUnit.assertEquals("variable did not match expacted", "SHELL11", type); + } finally { + RestResponse response = ServiceRestUtils.deleteService(defaultService1.getName(), serviceVersion, + sdncUserDetails); + checkDeleteResponse(response); + httpclient.close(); + } + + } + + @Test + public void addArtifactToResourceTest() throws Exception { + + ArtifactReqDetails defaultArtifact = ElementFactory.getDefaultArtifact(); + + RestResponse response = ArtifactRestUtils.addInformationalArtifactToResource(defaultArtifact, sdncUserDetails, + resourceDetailsVFCcomp.getUniqueId()); + int status = response.getErrorCode(); + AssertJUnit.assertEquals("add informational artifact request returned status: " + response.getErrorCode(), 200, + status); + + RestResponse resourceResp = ResourceRestUtils.getResource(resourceDetailsVFCcomp.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(resourceResp.getResponse()); + AssertJUnit.assertNotNull(resource); + + Map artifacts = resource.getArtifacts(); + boolean isExist = false; + for (Map.Entry entry : artifacts.entrySet()) { + if (entry.getKey().equals(defaultArtifact.getArtifactLabel())) { + isExist = true; + + } + } + AssertJUnit.assertTrue(isExist); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/CrudArt.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/CrudArt.java new file mode 100644 index 0000000000..ff99a6bb10 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/CrudArt.java @@ -0,0 +1,1799 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.artifacts; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.tuple.Pair; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.general.FileUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ArtifactValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.BaseValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class CrudArt extends ComponentBaseTest { + + private static Logger logger = LoggerFactory.getLogger(CrudArt.class.getName()); + private static final User sdncDesignerDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + private static final String HEAT_NET_LABEL = "heatnet"; + private static final String HEAT_LABEL = "heat"; + + protected String testResourcesPath; + protected String testResourcesInstancesPath; + + protected static final String dcaeInventoryToscaFile = "toscaSampleArtifact.yml"; + protected static final String dcaeInventoryJsonFile = "jsonSampleArtifact.json"; + protected static final String dcaeInventoryPolicyFile = "emfSampleArtifact.emf"; + protected static final String dcaeInventoryDocFile = "docSampleArtifact.doc"; + protected static final String dcaeInventoryBlueprintFile = "bluePrintSampleArtifact.xml"; + protected static final String dcaeInventoryEventFile = "eventSampleArtifact.xml"; + + protected static final String heatSuccessFile = "asc_heat 0 2.yaml"; + protected static final String heatNetSuccessFile = "asc_heat_net 0 2.yaml"; + protected static final String yangFile = "addYangXmlArtifactToResource.xml"; + protected static final String jsonFile = "jsonArtifact.json"; + protected static final String invalidJsonFile = "invalidJson.json"; + protected static final String invalidYangFile = "invalidYangXml.xml"; + protected static final String otherFile = "other.txt"; + protected static final String muranoFile = "asc_heat 0 2.zip"; + protected static final String heatSuccessMiniFile = "heat_mini.yaml"; + protected static final String heatInvalidFormat = "heatInvalidFormat.yaml"; + protected static final String yamlInvalidFormat = "invalidYamlFormat.yaml"; + protected static final String heatEnvfile = "heatEnvfile.env"; + + protected ServiceReqDetails serviceDetails; + protected ResourceReqDetails vfResourceDetails; + protected ResourceReqDetails cpResourceDetails; + protected ResourceReqDetails vfcResourceDetails; + protected ResourceReqDetails vlResourceDetails; + + @Rule + public static TestName name = new TestName(); + + public CrudArt() { + super(name, CrudArt.class.getName()); + } + + @DataProvider + private static final Object[][] getDepArtByType() throws IOException, Exception { + return new Object[][] { { ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()) }, { ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT_VOL.getType()) }, + { ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT_NET.getType()) }, { ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.DCAE_INVENTORY_TOSCA.getType()) }, + { ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.DCAE_INVENTORY_JSON.getType()) }, { ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.DCAE_INVENTORY_POLICY.getType()) }, + { ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.DCAE_INVENTORY_DOC.getType()) }, { ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.DCAE_INVENTORY_BLUEPRINT.getType()) }, + { ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.DCAE_INVENTORY_EVENT.getType()) } }; + } + + @DataProvider + private static final Object[][] getServiceDepArtByType() throws IOException, Exception { + return new Object[][] { { ArtifactTypeEnum.OTHER.getType() }, { ArtifactTypeEnum.YANG_XML.getType() }, }; + } + + @BeforeMethod + public void init() throws Exception { + // Set files working directory + String sourceDir = config.getResourceConfigDir(); + String workDir = "HeatDeploymentArtifacts"; + testResourcesPath = sourceDir + File.separator + workDir; + String workDirResourceInstanceArtifacts = "ResourceInstanceArtifacts"; + testResourcesInstancesPath = sourceDir + File.separator + workDirResourceInstanceArtifacts; + + // Build the components + Service serviceObj = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + serviceDetails = new ServiceReqDetails(serviceObj); + + Resource vfcResourceObj = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + vfcResourceDetails = new ResourceReqDetails(vfcResourceObj); + + Resource vfResourceObj = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + vfResourceDetails = new ResourceReqDetails(vfResourceObj); + + Resource cpResourceObj = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.CP, UserRoleEnum.DESIGNER, true).left().value(); + cpResourceDetails = new ResourceReqDetails(cpResourceObj); + + Resource vlResourceObj = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VL, UserRoleEnum.DESIGNER, true).left().value(); + vlResourceDetails = new ResourceReqDetails(vlResourceObj); + } + + // ---------------------------------Resource + // success-------------------------------- + @Test + public void addHeatArtifactToResourceAndCertify() throws Exception { + + String fileName = heatSuccessFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // certified resource + RestResponse changeResourceState = LifecycleRestUtils.certifyResource(vfResourceDetails); + int status = changeResourceState.getErrorCode(); + assertEquals("certify resource request returned status:" + status, BaseRestUtils.STATUS_CODE_SUCCESS, status); + + Resource resourceJavaObject = ResponseParser.convertResourceResponseToJavaObject(changeResourceState.getResponse()); + Map artifactsMap = resourceJavaObject.getDeploymentArtifacts(); + boolean flag = false; + if (artifactsMap != null) { + for (Entry art : artifactsMap.entrySet()) { + if (art.getValue().getArtifactName().equals(heatArtifactDetails.getArtifactName())) { + assertTrue("expected artifact type is " + ArtifactGroupTypeEnum.DEPLOYMENT.getType() + " but was " + art.getValue().getArtifactGroupType(), art.getValue().getArtifactGroupType().equals(ArtifactGroupTypeEnum.DEPLOYMENT)); + flag = true; + break; + } + } + assertTrue("expected artifact not found", flag == true); + } + + } + + // ---------------------------------Resource + // success-------------------------------- + @Test + public void addDcaeInventoryToscaArtifactToResourceInstanceAndCertify() throws Exception { + String artifactFileName = dcaeInventoryToscaFile; + String artifactName = dcaeInventoryToscaFile; + String artifactLabel = "dcae inv tosca label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.DCAE_INVENTORY_TOSCA; + RestResponse addArtifactToResourceInstanceResponse = addArtifactToResourceInstanceAndCertify(artifactFileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addArtifactToResourceInstanceResponse.getErrorCode(), addArtifactToResourceInstanceResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + @Test + public void addDcaeInventoryJsonArtifactToResourceInstanceAndCertify() throws Exception { + String artifactFileName = dcaeInventoryJsonFile; + String artifactName = dcaeInventoryJsonFile; + String artifactLabel = "dcae inv json label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.DCAE_INVENTORY_JSON; + RestResponse addArtifactToResourceInstanceResponse = addArtifactToResourceInstanceAndCertify(artifactFileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addArtifactToResourceInstanceResponse.getErrorCode(), addArtifactToResourceInstanceResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + @Test + public void addDcaeInventoryPolicyArtifactToResourceInstanceAndCertify() throws Exception { + String artifactFileName = dcaeInventoryPolicyFile; + String artifactName = dcaeInventoryPolicyFile; + String artifactLabel = "dcae inv policy label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.DCAE_INVENTORY_POLICY; + RestResponse addArtifactToResourceInstanceResponse = addArtifactToResourceInstanceAndCertify(artifactFileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addArtifactToResourceInstanceResponse.getErrorCode(), addArtifactToResourceInstanceResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + @Test + public void addDcaeInventoryDocArtifactToResourceInstanceAndCertify() throws Exception { + String artifactFileName = dcaeInventoryDocFile; + String artifactName = dcaeInventoryDocFile; + String artifactLabel = "dcae inv doc label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.DCAE_INVENTORY_DOC; + RestResponse addArtifactToResourceInstanceResponse = addArtifactToResourceInstanceAndCertify(artifactFileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addArtifactToResourceInstanceResponse.getErrorCode(), addArtifactToResourceInstanceResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + @Test + public void addDcaeInventoryBluePrintArtifactToResourceInstanceAndCertify() throws Exception { + String artifactFileName = dcaeInventoryBlueprintFile; + String artifactName = dcaeInventoryBlueprintFile; + String artifactLabel = "dcae inv blueprint label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.DCAE_INVENTORY_BLUEPRINT; + RestResponse addArtifactToResourceInstanceResponse = addArtifactToResourceInstanceAndCertify(artifactFileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addArtifactToResourceInstanceResponse.getErrorCode(), addArtifactToResourceInstanceResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + @Test + public void addDcaeInventoryEventArtifactToResourceInstanceAndCertify() throws Exception { + String artifactFileName = dcaeInventoryEventFile; + String artifactName = dcaeInventoryEventFile; + String artifactLabel = "dcae inv event label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.DCAE_INVENTORY_EVENT; + RestResponse addArtifactToResourceInstanceResponse = addArtifactToResourceInstanceAndCertify(artifactFileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addArtifactToResourceInstanceResponse.getErrorCode(), addArtifactToResourceInstanceResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + private RestResponse addArtifactToResourceInstanceAndCertify(String artifactFileName, String artifactName, String artifactLabel, ArtifactTypeEnum artifactType) throws Exception { + + // Get the resource + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + + // Certify VF + Pair changeComponentState = AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + changeComponentState.getRight().getErrorCode(), changeComponentState.getRight().getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // Add VF instance to service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource, service, UserRoleEnum.DESIGNER, true); + + // Get the VF instance + getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ComponentInstance VfInstance = service.getComponentInstances().get(0); + + // Create the artifact + RestResponse addArtifactToResourceInstanceResponse = addArtifactToResourceInstance(artifactFileName, artifactName, artifactLabel, artifactType, VfInstance, serviceDetails); + logger.debug("addInformationalArtifactToResource response: {}",addArtifactToResourceInstanceResponse.getResponseMessage()); + return addArtifactToResourceInstanceResponse; + } + + @Test + public void updateArtifactDescriptionToResourceInstance() throws Exception { + String artifactFileName = dcaeInventoryToscaFile; + String artifactName = dcaeInventoryToscaFile; + String artifactLabel = "dcae inv tosca label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.DCAE_INVENTORY_TOSCA; + RestResponse addArtifactToResourceInstanceResponse = addArtifactToResourceInstanceAndCertify(artifactFileName, artifactName, artifactLabel, artifactType); + logger.debug("addInformationalArtifactToResource response: {}" ,addArtifactToResourceInstanceResponse.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addArtifactToResourceInstanceResponse.getErrorCode(), addArtifactToResourceInstanceResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // Get the artifact from VF instance and change his description. + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ComponentInstance vfInstance = service.getComponentInstances().get(0); + Map deploymentArtifacts = vfInstance.getDeploymentArtifacts(); + ArtifactDefinition artifactDefinition = deploymentArtifacts.get("dcaeinvtoscalabel"); + artifactDefinition.setDescription("My new description"); + + // Update the artifact + RestResponse updateDeploymentArtifactToRI = ArtifactRestUtils.updateArtifactToResourceInstance(artifactDefinition, sdncDesignerDetails1, vfInstance.getUniqueId(), service.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",updateDeploymentArtifactToRI.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + updateDeploymentArtifactToRI.getErrorCode(), updateDeploymentArtifactToRI.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + @Test + public void deleteArtifactToResourceInstance() throws Exception { + String artifactFileName = dcaeInventoryToscaFile; + String artifactName = dcaeInventoryToscaFile; + String artifactLabel = "dcae inv tosca label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.DCAE_INVENTORY_TOSCA; + RestResponse addArtifactToResourceInstanceResponse = addArtifactToResourceInstanceAndCertify(artifactFileName, artifactName, artifactLabel, artifactType); + logger.debug("addInformationalArtifactToResource response: {}",addArtifactToResourceInstanceResponse.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addArtifactToResourceInstanceResponse.getErrorCode(), addArtifactToResourceInstanceResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // Get the artifact from VF instance and change his description. + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ComponentInstance vfInstance = service.getComponentInstances().get(0); + Map deploymentArtifacts = vfInstance.getDeploymentArtifacts(); + ArtifactDefinition artifactDefinition = deploymentArtifacts.get("dcaeinvtoscalabel"); + + // Delete the artifact + RestResponse deleteInformationalArtifactFromResource = ArtifactRestUtils.deleteArtifactFromResourceInstance(artifactDefinition, sdncDesignerDetails1, vfInstance.getUniqueId(), service.getUniqueId()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + deleteInformationalArtifactFromResource.getErrorCode(), deleteInformationalArtifactFromResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + @Test + public void addHeatArtifactToResource() throws Exception { + + String fileName = heatSuccessFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + } + + @Test + public void addHeatAndHeatNetArtifactsToResource() throws Exception { + + String fileName = heatSuccessFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + + // Add HEAT + logger.debug("listFileName: {}",listFileName.toString()); + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // Add HEAT_NET + String payloadNet = FileUtils.loadPayloadFile(listFileName, heatNetSuccessFile, true); + ArtifactReqDetails heatNetArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT_NET.getType()); + heatNetArtifactDetails.setPayload(payloadNet); + heatNetArtifactDetails.setArtifactLabel(HEAT_NET_LABEL); + + RestResponse addInformationalArtifactToResource1 = ArtifactRestUtils.uploadArtifactToPlaceholderOnResource(heatNetArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId(), HEAT_NET_LABEL); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource1.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource1.getErrorCode(), addInformationalArtifactToResource1.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + RestResponse resourceGetResponse = ResourceRestUtils.getResource(vfResourceDetails, sdncDesignerDetails1); + Resource resourceRespJavaObject = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + + ArtifactDefinition artifactDefinition = deploymentArtifacts.get(HEAT_LABEL); + assertNotNull(artifactDefinition); + String heatEsId = artifactDefinition.getEsId(); + assertNotNull(heatEsId); + + ArtifactDefinition artifactDefinitionNet = deploymentArtifacts.get(HEAT_NET_LABEL); + assertNotNull(artifactDefinitionNet); + String heatNetEsId = artifactDefinitionNet.getEsId(); + assertNotNull(heatNetEsId); + assertFalse(heatEsId.equalsIgnoreCase(heatNetEsId)); + } + + @Test + public void addDeleteAddHeatArtifactToResource() throws Exception { + + String fileName = heatSuccessFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + RestResponse deleteInformationalArtifactFromResource = ArtifactRestUtils.deleteInformationalArtifactFromResource(vfResourceDetails.getUniqueId(), heatArtifactDetails, sdncDesignerDetails1); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + deleteInformationalArtifactFromResource.getErrorCode(), deleteInformationalArtifactFromResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + @Test + public void addYangXmlArtifactToResource() throws Exception { + + String fileName = yangFile; + String artifactName = "asc_heat 0 2.XML"; + String artifactLabel = "Label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.YANG_XML; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addOtherTypeDeploymentArtifactToResource() throws Exception { + + String fileName = otherFile; + String artifactName = "other.txt"; + String artifactLabel = "Label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.OTHER; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addYangXmlArtifactSameName() throws Exception { + + String fileName = yangFile; + String artifactName = "asc_heat_0_2.XML"; + String artifactLabel = "Label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.YANG_XML; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + // Changing label but not name + artifactLabel = "Label1"; + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is not 400, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == 400); + BaseValidationUtils.checkErrorResponse(addInformationalArtifactToResource, ActionStatus.DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS, new String[] { "Resource", vfResourceDetails.getName(), artifactName }); + + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addInvalidYangXmlFormat() throws Exception { + + String fileName = invalidYangFile; + String artifactName = "asc_heat_0_2.XML"; + String artifactLabel = "Label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.YANG_XML; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is not 400, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == 400); + BaseValidationUtils.checkErrorResponse(addInformationalArtifactToResource, ActionStatus.INVALID_XML, new String[] { "YANG_XML" }); + + } + + @Test + public void addSeveralYangXmlArtifacts() throws Exception { + + // Adding 4 artifacts + String fileName = yangFile; + String artifactName = "asc_heat_0_2.XML"; + String artifactLabel = "Label"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.YANG_XML; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + // Changing label and name + artifactLabel = "Label1"; + artifactName = "asc_heat_0_3.XML"; + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // Changing label and name + artifactLabel = "Label2"; + artifactName = "asc_heat_0_4.XML"; + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType); + + // Changing label and name + artifactLabel = "Label3"; + artifactName = "asc_heat_0_5.XML"; + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 4); + } + + @Test(dataProvider = "getDepArtByType") + public void updateHeatArtifactToResource(ArtifactReqDetails heatTypeArtifactDetails) throws Exception, Exception { + + String fileName = heatSuccessFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + heatTypeArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // update + heatTypeArtifactDetails.setArtifactName("UPDATE.yaml"); + heatTypeArtifactDetails.setPayloadData(null); + RestResponse updateInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",updateInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + updateInformationalArtifactToResource.getErrorCode(), updateInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + } + + @Test(dataProvider = "getDepArtByType") + public void updateHeatArtifactTimeOutToResource(ArtifactReqDetails heatTypeArtifactDetails) throws Exception, Exception { + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + Resource resource = getResourceByResDetails(vfResourceDetails, sdncDesignerDetails1); + int actualTimeout = resource.getDeploymentArtifacts().get(heatTypeArtifactDetails.getArtifactLabel().toLowerCase()).getTimeout(); + assertTrue("verify " + heatTypeArtifactDetails.getArtifactLabel().toLowerCase() + " artifact timout, expected " + heatTypeArtifactDetails.getTimeout() + ", but was " + actualTimeout, heatTypeArtifactDetails.getTimeout() == actualTimeout); + + // update + heatTypeArtifactDetails.setTimeout(35); + RestResponse updateInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",updateInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + updateInformationalArtifactToResource.getErrorCode(), updateInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + resource = getResourceByResDetails(vfResourceDetails, sdncDesignerDetails1); + actualTimeout = resource.getDeploymentArtifacts().get(heatTypeArtifactDetails.getArtifactLabel().toLowerCase()).getTimeout(); + assertTrue("verify " + heatTypeArtifactDetails.getArtifactLabel().toLowerCase() + " artifact timout, expected " + heatTypeArtifactDetails.getTimeout() + ", but was " + actualTimeout, heatTypeArtifactDetails.getTimeout() == actualTimeout); + } + + @Test(dataProvider = "getDepArtByType") + public void updateHeatArtifactDescriptionToResource(ArtifactReqDetails heatTypeArtifactDetails) throws Exception, Exception { + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + Resource resource = getResourceByResDetails(vfResourceDetails, sdncDesignerDetails1); + String actualDescription = resource.getDeploymentArtifacts().get(heatTypeArtifactDetails.getArtifactLabel().toLowerCase()).getDescription(); + assertTrue("verify " + heatTypeArtifactDetails.getArtifactLabel().toLowerCase() + " artifact Description, expected " + heatTypeArtifactDetails.getDescription() + ", but was " + actualDescription, heatTypeArtifactDetails.getDescription().equals(actualDescription)); + + // update + heatTypeArtifactDetails.setDescription("the best description was ever"); + RestResponse updateInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",updateInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + updateInformationalArtifactToResource.getErrorCode(), updateInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + resource = getResourceByResDetails(vfResourceDetails, sdncDesignerDetails1); + actualDescription = resource.getDeploymentArtifacts().get(heatTypeArtifactDetails.getArtifactLabel().toLowerCase()).getDescription(); + assertTrue("verify " + heatTypeArtifactDetails.getArtifactLabel().toLowerCase() + " artifact Description, expected " + heatTypeArtifactDetails.getDescription() + ", but was " + actualDescription, heatTypeArtifactDetails.getDescription().equals(actualDescription)); + } + + private Resource getResourceByResDetails(ResourceReqDetails resDetails, User userDetails) throws IOException { + RestResponse response = ResourceRestUtils.getResource(resDetails, userDetails); + assertTrue("response code on get resource not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + response.getErrorCode(), response.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + return resource; + } + + // ---------------------------------Service + // success-------------------------------- + @Test() + public void addAllTypesDepArtifactToService() throws Exception, Exception { + + // String fileName = heatSuccessFile; + // List listFileName = + // FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + // logger.debug("listFileName: {}",listFileName.toString()); + + // String payload = FileUtils.loadPayloadFile(listFileName, fileName, + // true); + ArtifactReqDetails otherArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.OTHER.getType()); + // otherArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(otherArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToService response: {}",addInformationalArtifactToService.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToService.getErrorCode(), addInformationalArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + ArtifactReqDetails yangXmlArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.YANG_XML.getType()); + + addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(yangXmlArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToService response: {}",addInformationalArtifactToService.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToService.getErrorCode(), addInformationalArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + } + + @Test(enabled = false) + public void addMuranoPkgArtifactToService() throws Exception, Exception { + + String fileName = muranoFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}" ,listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.MURANO_PKG.getType()); + heatArtifactDetails.setPayload(payload); + heatArtifactDetails.setArtifactName("asc_heat 0 2.zip"); + heatArtifactDetails.setArtifactLabel("Label"); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(heatArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToService response: {}",addInformationalArtifactToService.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToService.getErrorCode(), addInformationalArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + } + + @Test(dataProvider = "getServiceDepArtByType") + public void addHeatArtifactToServiceAndCertify(String artType) throws Exception, Exception { + + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(artType); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(heatArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToService response: {}",addInformationalArtifactToService.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToService.getErrorCode(), addInformationalArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // certified service + RestResponse changeServiceState = LifecycleRestUtils.certifyService(serviceDetails); + int status = changeServiceState.getErrorCode(); + assertEquals("certify service request returned status:" + status, BaseRestUtils.STATUS_CODE_SUCCESS, status); + + Service resourceJavaObject = ResponseParser.convertServiceResponseToJavaObject(changeServiceState.getResponse()); + Map artifactsMap = resourceJavaObject.getDeploymentArtifacts(); + boolean flag = false; + if (artifactsMap != null) { + for (Entry art : artifactsMap.entrySet()) { + if (art.getValue().getArtifactName().equals(heatArtifactDetails.getArtifactName())) { + assertTrue("expected artifact type is " + ArtifactGroupTypeEnum.DEPLOYMENT.getType() + " but was " + art.getValue().getArtifactGroupType(), art.getValue().getArtifactGroupType().equals(ArtifactGroupTypeEnum.DEPLOYMENT)); + flag = true; + break; + } + } + assertTrue("expected artifact not found", flag == true); + } + + } + + @Test(enabled = false, dataProvider = "getServiceDepArtByType") + public void updateHeatArtifactToService(String artType) throws Exception, Exception { + + String fileName = heatSuccessFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(artType); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(heatArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToService.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToService.getErrorCode(), addInformationalArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // update + heatArtifactDetails.setPayloadData(payload); + RestResponse updateInformationalArtifactToService = ArtifactRestUtils.updateInformationalArtifactOfServiceByMethod(heatArtifactDetails, serviceDetails.getUniqueId(), sdncDesignerDetails1, "POST"); + logger.debug("updateInformationalArtifactToService response: {}",updateInformationalArtifactToService.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + updateInformationalArtifactToService.getErrorCode(), updateInformationalArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + } + + // --------------------------------------Resource Negative + // Tests------------------------------------- + + // TODO Andrey the method of DEPLOYMENT artifact is update and not add + @Test(dataProvider = "getServiceDepArtByType") + public void addTheSameAdditionalHeatArtifactToResource(String artType) throws Exception, Exception { + + ArtifactReqDetails artifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(artType); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(artifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // add the same artifact one more time + artifactDetails.setArtifactLabel("the second artifact"); + addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(artifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToResource.getErrorCode()); + + List variables = Arrays.asList("Resource", vfResourceDetails.getName(), artifactDetails.getArtifactName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS.name(), variables, addInformationalArtifactToResource.getResponse()); + + } + + @Test + public void addHeatArtifactTwiceSameNameToResource() throws Exception, Exception { + + String filename1 = heatSuccessFile; + // String filename2 = heatSuccessMiniFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, filename1, true); + + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // Add HEAT_NET + String payloadNet = FileUtils.loadPayloadFile(listFileName, heatNetSuccessFile, true); + ArtifactReqDetails heatNetArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT_NET.getType()); + heatNetArtifactDetails.setPayload(payloadNet); + heatNetArtifactDetails.setArtifactLabel(HEAT_NET_LABEL); + heatNetArtifactDetails.setArtifactName(heatArtifactDetails.getArtifactName()); + + RestResponse addInformationalArtifactToResource1 = ArtifactRestUtils.uploadArtifactToPlaceholderOnResource(heatNetArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId(), HEAT_NET_LABEL); + logger.debug("addInformationalArtifactToResource response: {}" ,addInformationalArtifactToResource1.getResponseMessage()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToResource1.getErrorCode()); + + List variables = Arrays.asList("Resource", vfResourceDetails.getName(), heatNetArtifactDetails.getArtifactName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS.name(), variables, addInformationalArtifactToResource1.getResponse()); + + } + + @Test(dataProvider = "getDepArtByType") + public void addHeatArtifactTwiceToResource(ArtifactReqDetails heatTypeArtifactDetails) throws Exception, Exception { + + String filename1 = heatSuccessFile; + String filename2 = heatSuccessMiniFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, filename1, true); + heatTypeArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}" ,addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // add the second artifact + payload = FileUtils.loadPayloadFile(listFileName, heatSuccessMiniFile, true); + heatTypeArtifactDetails.setPayload(payload); + heatTypeArtifactDetails.setArtifactName(filename2); + heatTypeArtifactDetails.setArtifactLabel("the second artifact"); + + addInformationalArtifactToResource = ArtifactRestUtils.explicitAddInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToResource.getErrorCode()); + + List variables = Arrays.asList("Resource", vfResourceDetails.getName(), heatTypeArtifactDetails.getArtifactType(), heatTypeArtifactDetails.getArtifactType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS.name(), variables, addInformationalArtifactToResource.getResponse()); + + } + + @Test(dataProvider = "getDepArtByType") + public void addHeatArtifactInvalidHeatFormatToResource(ArtifactReqDetails heatTypeArtifactDetails) throws Exception, Exception { + + String fileName = heatInvalidFormat; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + heatTypeArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_DEPLOYMENT_ARTIFACT_HEAT.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToResource.getErrorCode()); + + List variables = Arrays.asList(heatTypeArtifactDetails.getArtifactType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_DEPLOYMENT_ARTIFACT_HEAT.name(), variables, addInformationalArtifactToResource.getResponse()); + + } + + @Test(dataProvider = "getDepArtByType") + public void addHeatArtifactInvalidYamlFormatToResource(ArtifactReqDetails heatTypeArtifactDetails) throws Exception, Exception { + + String fileName = yamlInvalidFormat; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + heatTypeArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_YAML.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToResource.getErrorCode()); + + List variables = Arrays.asList(heatTypeArtifactDetails.getArtifactType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_YAML.name(), variables, addInformationalArtifactToResource.getResponse()); + + } + + @Test(dataProvider = "getDepArtByType") + public void addHeatArtifactInvalidFileExtensionToResource(ArtifactReqDetails heatTypeArtifactDetails) throws Exception, Exception { + + String fileName = yangFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + + heatTypeArtifactDetails.setPayload(payload); + heatTypeArtifactDetails.setArtifactName(fileName); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.WRONG_ARTIFACT_FILE_EXTENSION.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToResource.getErrorCode()); + + List variables = Arrays.asList(heatTypeArtifactDetails.getArtifactType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.WRONG_ARTIFACT_FILE_EXTENSION.name(), variables, addInformationalArtifactToResource.getResponse()); + + } + + @Test(dataProvider = "getDepArtByType") + public void addHeatArtifactToResourceCertifyAndAddAdditionalHeatArtifact(ArtifactReqDetails heatTypeArtifactDetails) throws Exception, Exception { + + String fileName = heatSuccessFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + heatTypeArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // certified resource + RestResponse changeResourceState = LifecycleRestUtils.certifyResource(vfResourceDetails); + int status = changeResourceState.getErrorCode(); + assertEquals("certify resource request returned status:" + status, BaseRestUtils.STATUS_CODE_SUCCESS, status); + + // add second HEAT artifact to the certified resource + changeResourceState = LifecycleRestUtils.changeResourceState(vfResourceDetails, sdncDesignerDetails1, LifeCycleStatesEnum.CHECKOUT); + assertTrue("expected code response on change resource state to CHECKOUT BaseRestUtils.STATUS_CODE_SUCCESS, but was " + changeResourceState.getErrorCode(), changeResourceState.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // ArtifactReqDetails heatArtifactDetails1 = + // ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatTypeArtifactDetails.setPayload(payload); + heatTypeArtifactDetails.setArtifactName(fileName); + heatTypeArtifactDetails.setArtifactLabel("the second artifact"); + + addInformationalArtifactToResource = ArtifactRestUtils.explicitAddInformationalArtifactToResource(heatTypeArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToResource.getErrorCode()); + + List variables = Arrays.asList("Resource", vfResourceDetails.getName(), heatTypeArtifactDetails.getArtifactType(), heatTypeArtifactDetails.getArtifactType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS.name(), variables, addInformationalArtifactToResource.getResponse()); + + } + + // -----------------Service Negative + // Tests-------------------------------------------------------- + + // Absolute + @Test(enabled = false) + public void addHeatArtifactTwiceToService() throws Exception, Exception { + + String fileName1 = heatSuccessFile; + String fileName2 = heatSuccessMiniFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName1, true); + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.OTHER.getType()); + heatArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(heatArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToService response: {}",addInformationalArtifactToService.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToService.getErrorCode(), addInformationalArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // add the second artifact + payload = FileUtils.loadPayloadFile(listFileName, fileName2, true); + + ArtifactReqDetails heatArtifactDetails1 = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.OTHER.getType()); + heatArtifactDetails1.setPayload(payload); + heatArtifactDetails1.setArtifactName(fileName2); + heatArtifactDetails1.setArtifactLabel("the second artifact"); + + addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(heatArtifactDetails1, sdncDesignerDetails1, serviceDetails.getUniqueId()); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToService.getErrorCode()); + + List variables = Arrays.asList("Service", serviceDetails.getName(), ArtifactTypeEnum.OTHER.getType(), ArtifactTypeEnum.OTHER.getType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS.name(), variables, addInformationalArtifactToService.getResponse()); + + } + + // TODO Andrey Obsolete + @Test(enabled = false) + public void addHeatArtifactInvalidHeatFormatToService() throws Exception, Exception { + + String fileName = heatInvalidFormat; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(heatArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToService response: {}",addInformationalArtifactToService.getResponseMessage()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_DEPLOYMENT_ARTIFACT_HEAT.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToService.getErrorCode()); + + List variables = Arrays.asList(ArtifactTypeEnum.HEAT.getType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_DEPLOYMENT_ARTIFACT_HEAT.name(), variables, addInformationalArtifactToService.getResponse()); + + } + + // TODO Andrey Obsolete + @Test(enabled = false) + public void addHeatArtifactInvalidYamlFormatToService() throws Exception, Exception { + + String fileName = yamlInvalidFormat; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(heatArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToService response: {}",addInformationalArtifactToService.getResponseMessage()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_YAML.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToService.getErrorCode()); + + List variables = Arrays.asList(ArtifactTypeEnum.HEAT.getType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_YAML.name(), variables, addInformationalArtifactToService.getResponse()); + + } + + @Test + public void addHeatArtifactInvalidFileExtensionToService() throws Exception, Exception { + + String fileName = muranoFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.YANG_XML.getType()); + heatArtifactDetails.setPayload(payload); + heatArtifactDetails.setArtifactName(fileName); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(heatArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + logger.debug("addInformationalArtifactToService response: {}",addInformationalArtifactToService.getResponseMessage()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.WRONG_ARTIFACT_FILE_EXTENSION.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToService.getErrorCode()); + + List variables = Arrays.asList(ArtifactTypeEnum.YANG_XML.getType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.WRONG_ARTIFACT_FILE_EXTENSION.name(), variables, addInformationalArtifactToService.getResponse()); + + } + + @Test(dataProvider = "getDepArtByType") + public void addHeatEnvArtifactToResourceNotSupportedType(ArtifactReqDetails heatTypeArtifactDetails) throws Exception, Exception { + + String fileName = heatEnvfile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT_ENV.getType()); + heatArtifactDetails.setPayload(payload); + heatArtifactDetails.setArtifactName("asc_heat 0 2.env"); + heatArtifactDetails.setArtifactLabel(heatTypeArtifactDetails.getArtifactLabel()); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToResource.getErrorCode()); + + List variables = Arrays.asList(ArtifactTypeEnum.HEAT_ENV.getType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name(), variables, addInformationalArtifactToResource.getResponse()); + } + + // TODO Andrey + @Test + public void addHeatArtifactToServiceNotSupportDeploymentArt() throws Exception, Exception { + + String fileName = heatSuccessFile; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}",listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, fileName, true); + + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(payload); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(heatArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), addInformationalArtifactToService.getErrorCode()); + + List variables = Arrays.asList(ArtifactTypeEnum.HEAT.getType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name(), variables, addInformationalArtifactToService.getResponse()); + + } + + protected RestResponse addArtifactToResourceInstance(String artifactFileName, String artifactName, String artifactLabel, ArtifactTypeEnum artifactType, ComponentInstance componentInstance, ServiceReqDetails serviceDetails) throws Exception { + ArtifactReqDetails dcaeArtifactDetails = buildArtifactReqDetailsObject(testResourcesInstancesPath, artifactFileName, artifactName, artifactLabel, artifactType); + RestResponse addArtifactToResourceInstance = ArtifactRestUtils.addArtifactToResourceInstance(dcaeArtifactDetails, sdncDesignerDetails1, componentInstance.getUniqueId(), serviceDetails.getUniqueId()); + return addArtifactToResourceInstance; + } + + protected RestResponse addDeploymentArtifactToResource(String artifactFileName, String artifactName, String artifactLabel, ArtifactTypeEnum artifactType) throws Exception { + ArtifactReqDetails heatArtifactDetails = buildArtifactReqDetailsObject(testResourcesPath, artifactFileName, artifactName, artifactLabel, artifactType); + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, vfResourceDetails.getUniqueId()); + return addInformationalArtifactToResource; + } + + protected RestResponse addDeploymentArtifactToResource(String artifactFileName, String artifactName, String artifactLabel, ArtifactTypeEnum artifactType, ResourceReqDetails resource) throws Exception { + ArtifactReqDetails heatArtifactDetails = buildArtifactReqDetailsObject(testResourcesPath, artifactFileName, artifactName, artifactLabel, artifactType); + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, resource.getUniqueId()); + return addInformationalArtifactToResource; + } + + // US672293 - Support new artifact type : BEVF_LICENSE , VENDOR_LICENSE + @Test + public void addNewArtifactsToVFResource() throws Exception { + + String fileName = yangFile; + String artifactName = "artifact1.xml"; + String artifactLabel = "Label1"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VNF_CATALOG; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response:{}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + artifactName = "artifact2.xml"; + artifactLabel = "Label2"; + artifactType = ArtifactTypeEnum.VF_LICENSE; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact3.xml"; + artifactLabel = "Label3"; + artifactType = ArtifactTypeEnum.VENDOR_LICENSE; + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact4.xml"; + artifactLabel = "Label4"; + artifactType = ArtifactTypeEnum.MODEL_INVENTORY_PROFILE; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact5.xml"; + artifactLabel = "Label5"; + artifactType = ArtifactTypeEnum.MODEL_QUERY_SPEC; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact6.xml"; + artifactLabel = "Label6"; + artifactType = ArtifactTypeEnum.APPC_CONFIG; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}",addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + fileName = jsonFile; + artifactName = "artifact7.json"; + artifactLabel = "Label7"; + artifactType = ArtifactTypeEnum.APPC_CONFIG; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 2); + + //MIB artifacts: SNMP_POLL, SNMP_TRAP + fileName = jsonFile; + artifactName = "artifact8.json"; + artifactLabel = "Label8"; + artifactType = ArtifactTypeEnum.SNMP_POLL; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + fileName = jsonFile; + artifactName = "artifact9.json"; + artifactLabel = "Label9"; + artifactType = ArtifactTypeEnum.SNMP_TRAP; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + //MIB artifacts: SNMP_POLL, SNMP_TRAP + fileName = jsonFile; + artifactName = "artifact8.json"; + artifactLabel = "Label8"; + artifactType = ArtifactTypeEnum.SNMP_POLL; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + fileName = jsonFile; + artifactName = "artifact9.json"; + artifactLabel = "Label9"; + artifactType = ArtifactTypeEnum.SNMP_TRAP; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addNewArtifactsToVFCResource() throws Exception { + + String fileName = yangFile; + String artifactName = "artifact1.xml"; + String artifactLabel = "Label1"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VNF_CATALOG; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact2.xml"; + artifactLabel = "Label2"; + artifactType = ArtifactTypeEnum.VF_LICENSE; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact3.xml"; + artifactLabel = "Label3"; + artifactType = ArtifactTypeEnum.VENDOR_LICENSE; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact4.xml"; + artifactLabel = "Label4"; + artifactType = ArtifactTypeEnum.MODEL_INVENTORY_PROFILE; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifac5.xml"; + artifactLabel = "Label5"; + artifactType = ArtifactTypeEnum.MODEL_QUERY_SPEC; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addNewArtifactsToVfc() throws Exception { + String fileName = yangFile; + String artifactName = "artifact2.xml"; + String artifactLabel = "Label2"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VF_LICENSE; + RestResponse addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}",addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + artifactName = "artifact3.xml"; + artifactLabel = "Label3"; + artifactType = ArtifactTypeEnum.VENDOR_LICENSE; + addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addNewArtifactsToCp() throws Exception { + String fileName = yangFile; + String artifactName = "artifact2.xml"; + String artifactLabel = "Label2"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VF_LICENSE; + RestResponse addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, cpResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(cpResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + artifactName = "artifact3.xml"; + artifactLabel = "Label3"; + artifactType = ArtifactTypeEnum.VENDOR_LICENSE; + addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, cpResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(cpResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addNewArtifactsToVl() throws Exception { + String fileName = yangFile; + String artifactName = "artifact2.xml"; + String artifactLabel = "Label2"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VF_LICENSE; + RestResponse addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vlResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vlResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + artifactName = "artifact3.xml"; + artifactLabel = "Label3"; + artifactType = ArtifactTypeEnum.VENDOR_LICENSE; + addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vlResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vlResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addVfInstanceWithNewArtifactsToService() throws Exception { + String fileName = yangFile; + String artifactName = "artifact2.xml"; + String artifactLabel = "Label2"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VF_LICENSE; + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + artifactName = "artifact3.xml"; + artifactLabel = "Label3"; + artifactType = ArtifactTypeEnum.VENDOR_LICENSE; + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + // Certify VF + Pair changeComponentState = AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + changeComponentState.getRight().getErrorCode(), changeComponentState.getRight().getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + // Add VF instance to service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource, service, UserRoleEnum.DESIGNER, true); + // get service and verify VF instance contain the Artifacts :VF_LICENSE + // and VENDOR_LICENSE + getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ComponentInstance VfInstance = service.getComponentInstances().get(0); + ArtifactValidationUtils.validateArtifactsNumberInComponentInstance(VfInstance, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.VENDOR_LICENSE, 1); + ArtifactValidationUtils.validateArtifactsNumberInComponentInstance(VfInstance, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.VF_LICENSE, 1); + } + + @Test + public void addNotSupportedArtifactsTypeToService01() throws Exception, Exception { + // Artifact type : VF_LICENSE + ArtifactReqDetails deploymentArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.VF_LICENSE.getType()); + RestResponse addDeploymentArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(deploymentArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + assertTrue("response code eturned :" + addDeploymentArtifactToService.getErrorCode(), addDeploymentArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add("VF_LICENSE"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name(), variables, addDeploymentArtifactToService.getResponse()); + } + + @Test + public void addNotSupportedArtifactsTypeToService02() throws Exception, Exception { + // Artifact type : VENDOR_LICENSE + ArtifactReqDetails deploymentArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.VENDOR_LICENSE.getType()); + RestResponse addDeploymentArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(deploymentArtifactDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + assertTrue("response code eturned :" + addDeploymentArtifactToService.getErrorCode(), addDeploymentArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add("VENDOR_LICENSE"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name(), variables, addDeploymentArtifactToService.getResponse()); + } + + @Test + public void addInvalidFileForArtifactTypeVendorLicenseToResource() throws Exception { + String fileName = yangFile; + String NonXmlFile = heatSuccessFile; + String artifactName = "artifact2.xml"; + String artifactLabel = "Label2"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VF_LICENSE; + RestResponse addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + // Artifact type VENDOR_LICENSE must be XML file + artifactName = "artifact3.xml"; + artifactLabel = "Label3"; + artifactType = ArtifactTypeEnum.VENDOR_LICENSE; + addDeploymentArtifactToResource = addDeploymentArtifactToResource(NonXmlFile, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code 400 returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add("VENDOR_LICENSE"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_XML.name(), variables, addDeploymentArtifactToResource.getResponse()); + // get resource and verify that file not exist within + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 0); + } + + @Test + public void addInvalidFileForArtifactTypeVfLicenseToResource() throws Exception { + String fileName = yangFile; + String NonXmlFile = heatSuccessFile; + String artifactName = "artifact2.xml"; + String artifactLabel = "Label2"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VENDOR_LICENSE; + RestResponse addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + // Artifact type VF_LICENSE must be XML file + artifactName = "artifact3.xml"; + artifactLabel = "Label3"; + artifactType = ArtifactTypeEnum.VF_LICENSE; + addDeploymentArtifactToResource = addDeploymentArtifactToResource(NonXmlFile, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code 400 returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add("VF_LICENSE"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_XML.name(), variables, addDeploymentArtifactToResource.getResponse()); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 0); + } + + @Test + public void addVendorLicenseArtifactAlreadyExistsInResource() throws Exception { + String fileName = yangFile; + String artifactName = "artifact2.xml"; + String artifactLabel = "Label2"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VENDOR_LICENSE; + RestResponse addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + // Add same file again to resource + addDeploymentArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addDeploymentArtifactToResource.getResponseMessage()); + assertTrue("response code is not 400, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add(artifactLabel.toLowerCase()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.ARTIFACT_EXIST.name(), variables, addDeploymentArtifactToResource.getResponse()); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + // US672294 + + @Test() + public void addVnfCatalogArtifactsToService() throws Exception, Exception { + + ArtifactReqDetails artDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.VNF_CATALOG.getType()); + RestResponse resp = ArtifactRestUtils.addInformationalArtifactToService(artDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + resp.getErrorCode(), resp.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + // get service and verify the Artifacts :VNF_CATALOG + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(service, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.VNF_CATALOG, 1); + } + + @Test() + public void addModelInventoryProfileArtifactsToService() throws Exception, Exception { + + ArtifactReqDetails artDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.MODEL_INVENTORY_PROFILE.getType()); + RestResponse resp = ArtifactRestUtils.addInformationalArtifactToService(artDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + resp.getErrorCode(), resp.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + // get service and verify the Artifacts :VNF_CATALOG + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(service, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.MODEL_INVENTORY_PROFILE, 1); + } + + @Test() + public void addModelQuerySpecArtifactsToService() throws Exception, Exception { + + ArtifactReqDetails artDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.MODEL_QUERY_SPEC.getType()); + RestResponse resp = ArtifactRestUtils.addInformationalArtifactToService(artDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + resp.getErrorCode(), resp.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + // get service and verify the Artifacts :VNF_CATALOG + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(service, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.MODEL_QUERY_SPEC, 1); + } + + @Test + public void addVfInstanceWithNewArtifactsToService02() throws Exception { + + String fileName = yangFile; + String artifactName = "artifact1.xml"; + String artifactLabel = "Label1"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VNF_CATALOG; + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + fileName = yangFile; + artifactName = "artifact2.xml"; + artifactLabel = "Label2"; + artifactType = ArtifactTypeEnum.APPC_CONFIG; + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact4.xml"; + artifactLabel = "Label4"; + artifactType = ArtifactTypeEnum.MODEL_INVENTORY_PROFILE; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifac5.xml"; + artifactLabel = "Label5"; + artifactType = ArtifactTypeEnum.MODEL_QUERY_SPEC; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + // Certify VF + Pair changeComponentState = AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + changeComponentState.getRight().getErrorCode(), changeComponentState.getRight().getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // Add VF instance to service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource, service, UserRoleEnum.DESIGNER, true); + + // get service and verify VF instance contain the Artifacts :VF_LICENSE + // and VENDOR_LICENSE + getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ComponentInstance VfInstance = service.getComponentInstances().get(0); + ArtifactValidationUtils.validateArtifactsNumberInComponentInstance(VfInstance, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.VNF_CATALOG, 1); + ArtifactValidationUtils.validateArtifactsNumberInComponentInstance(VfInstance, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.MODEL_INVENTORY_PROFILE, 1); + ArtifactValidationUtils.validateArtifactsNumberInComponentInstance(VfInstance, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.MODEL_QUERY_SPEC, 1); + ArtifactValidationUtils.validateArtifactsNumberInComponentInstance(VfInstance, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.APPC_CONFIG, 1); + } + + @Test + public void addAppcConfigArtifactToVfc() throws Exception { + String fileName = jsonFile; + String artifactName = "artifact7.json"; + String artifactLabel = "Label7"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.APPC_CONFIG; + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code 400, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add(artifactName); + variables.add("[VF]"); + variables.add("VFC (Virtual Function Component)"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISMATCH_BETWEEN_ARTIFACT_TYPE_AND_COMPONENT_TYPE.name(), variables, addInformationalArtifactToResource.getResponse()); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 0); + } + + @Test + public void addAppcConfigArtifactToCp() throws Exception { + String fileName = jsonFile; + String artifactName = "artifact7.json"; + String artifactLabel = "Label7"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.APPC_CONFIG; + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, cpResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code 400, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add(artifactName); + variables.add("[VF]"); + variables.add("CP (Connection Point)"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISMATCH_BETWEEN_ARTIFACT_TYPE_AND_COMPONENT_TYPE.name(), variables, addInformationalArtifactToResource.getResponse()); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 0); + } + + @Test + public void addAppcConfigArtifactToVl() throws Exception { + String fileName = jsonFile; + String artifactName = "artifact7.json"; + String artifactLabel = "Label7"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.APPC_CONFIG; + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vlResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code 400, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add(artifactName); + variables.add("[VF]"); + variables.add("VL (Virtual Link)"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISMATCH_BETWEEN_ARTIFACT_TYPE_AND_COMPONENT_TYPE.name(), variables, addInformationalArtifactToResource.getResponse()); + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 0); + } + + @Test() + public void addAppcConfigArtifactsToService() throws Exception, Exception { + ArtifactReqDetails artDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.APPC_CONFIG.getType()); + RestResponse addDeploymentArtifactToResource = ArtifactRestUtils.addInformationalArtifactToService(artDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + assertTrue("response code 400, returned :" + addDeploymentArtifactToResource.getErrorCode(), addDeploymentArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add(ArtifactTypeEnum.APPC_CONFIG.toString()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name(), variables, addDeploymentArtifactToResource.getResponse()); + } + + @Test + public void addAppcConfigInvalidJsonToVFResourceFailed() throws Exception { + + String fileName = invalidJsonFile; + String artifactName = "invalidJson.json"; + String artifactLabel = "Label7"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.APPC_CONFIG; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is 400, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + + ArrayList variables = new ArrayList<>(); + variables.add(ArtifactTypeEnum.APPC_CONFIG.toString()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_JSON.name(), variables, addInformationalArtifactToResource.getResponse()); + + RestResponse getResource = ResourceRestUtils.getResource(vfResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 0); + + } + + @Test + public void addNewArtifactsToCp02() throws Exception { + + String fileName = yangFile; + String artifactName = "artifact1.xml"; + String artifactLabel = "Label1"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VNF_CATALOG; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, cpResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(cpResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact4.xml"; + artifactLabel = "Label4"; + artifactType = ArtifactTypeEnum.MODEL_INVENTORY_PROFILE; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, cpResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(cpResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifac5.xml"; + artifactLabel = "Label5"; + artifactType = ArtifactTypeEnum.MODEL_QUERY_SPEC; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, cpResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(cpResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addNewArtifactsToVl02() throws Exception { + + String fileName = yangFile; + String artifactName = "artifact1.xml"; + String artifactLabel = "Label1"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VNF_CATALOG; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vlResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vlResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact4.xml"; + artifactLabel = "Label4"; + artifactType = ArtifactTypeEnum.MODEL_INVENTORY_PROFILE; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vlResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vlResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifac5.xml"; + artifactLabel = "Label5"; + artifactType = ArtifactTypeEnum.MODEL_QUERY_SPEC; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vlResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vlResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addNewArtifactsToVfc02() throws Exception { + + String fileName = yangFile; + String artifactName = "artifact1.xml"; + String artifactLabel = "Label1"; + ArtifactTypeEnum artifactType = ArtifactTypeEnum.VNF_CATALOG; + + RestResponse addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifact4.xml"; + artifactLabel = "Label4"; + artifactType = ArtifactTypeEnum.MODEL_INVENTORY_PROFILE; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + + artifactName = "artifac5.xml"; + artifactLabel = "Label5"; + artifactType = ArtifactTypeEnum.MODEL_QUERY_SPEC; + + addInformationalArtifactToResource = addDeploymentArtifactToResource(fileName, artifactName, artifactLabel, artifactType, vfcResourceDetails); + logger.debug("addInformationalArtifactToResource response: {}", addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addInformationalArtifactToResource.getErrorCode(), addInformationalArtifactToResource.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + getResource = ResourceRestUtils.getResource(vfcResourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(resource, ArtifactGroupTypeEnum.DEPLOYMENT, artifactType, 1); + } + + @Test + public void addNewArtifactAlreadyExistsInService() throws Exception { + ArtifactReqDetails artDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.MODEL_QUERY_SPEC.getType()); + RestResponse addDeploymentArtifactoService = ArtifactRestUtils.addInformationalArtifactToService(artDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + addDeploymentArtifactoService.getErrorCode(), addDeploymentArtifactoService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + // get service and verify the Artifacts :VNF_CATALOG + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(service, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.MODEL_QUERY_SPEC, 1); + // Add same file again to resource + addDeploymentArtifactoService = ArtifactRestUtils.addInformationalArtifactToService(artDetails, sdncDesignerDetails1, serviceDetails.getUniqueId()); + assertTrue("response code is 400, returned :" + addDeploymentArtifactoService.getErrorCode(), addDeploymentArtifactoService.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + ArrayList variables = new ArrayList<>(); + variables.add(artDetails.getArtifactLabel().toLowerCase()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.ARTIFACT_EXIST.name(), variables, addDeploymentArtifactoService.getResponse()); + // get service and verify the Artifacts :VNF_CATALOG is still exist and + // has one occurrences + getServiceResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails1); + service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + ArtifactValidationUtils.validateArtifactsNumberInComponent(service, ArtifactGroupTypeEnum.DEPLOYMENT, ArtifactTypeEnum.MODEL_QUERY_SPEC, 1); + } + + private ArtifactReqDetails buildArtifactReqDetailsObject(String filesPath, String artifactFileName, String artifactName, String artifactLabel, ArtifactTypeEnum artifactType) throws IOException, Exception { + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(filesPath); + logger.debug("listFileName: {}", listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, artifactFileName, true); + + ArtifactReqDetails dcaeArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(artifactType.getType()); + dcaeArtifactDetails.setPayload(payload); + dcaeArtifactDetails.setArtifactName(artifactName); + dcaeArtifactDetails.setArtifactLabel(artifactLabel); + return dcaeArtifactDetails; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/DownloadComponentArt.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/DownloadComponentArt.java new file mode 100644 index 0000000000..bb2b662009 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/DownloadComponentArt.java @@ -0,0 +1,665 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.artifacts; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.codehaus.jackson.map.ObjectMapper; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ArtifactUiDownloadData; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Decoder; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.Convertor; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ServiceValidationUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.testng.internal.Yaml; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.typesafe.config.ConfigException.Null; + +import fj.data.Either; +import fj.data.List; + +public class DownloadComponentArt extends ComponentBaseTest { + + private static Logger log = LoggerFactory.getLogger(DownloadComponentArt.class.getName()); + protected static final String UPLOAD_ARTIFACT_PAYLOAD = "UHVUVFktVXNlci1LZXktRmlsZS0yOiBzc2gtcnNhDQpFbmNyeXB0aW9uOiBhZXMyNTYtY2JjDQpDb21tZW5wOA0K"; + protected static final String UPLOAD_ARTIFACT_NAME = "TLV_prv.ppk"; + + protected Config config = Config.instance(); + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json"; + + + + protected Gson gson = new Gson(); + protected JSONParser jsonParser = new JSONParser(); + + + protected String serviceVersion; + protected ResourceReqDetails resourceDetails; + protected User sdncUserDetails; + protected ServiceReqDetails serviceDetails; + + + @BeforeMethod + public void init() throws Exception{ + sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + Resource resourceObj = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + Service serviceObj = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + + + resourceDetails = new ResourceReqDetails(resourceObj); + serviceDetails = new ServiceReqDetails(serviceObj); + } + + @Rule + public static TestName name = new TestName(); + + public DownloadComponentArt() { + super(name, DownloadComponentArt.class.getName()); + + } + + + + // External API - Download artifact for resource + @Test + public void downloadArtifactFromResourceViaExternalAPI() throws Exception { + Resource resourceDetailsVF; + Either createdResource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + resourceDetailsVF = createdResource.left().value(); + ArtifactDefinition heatArtifact = AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVF, UserRoleEnum.DESIGNER, true, true).left().value(); + resourceDetails = new ResourceReqDetails(resourceDetailsVF); + + String resourceUUID = resourceDetailsVF.getUUID(); + String artifactUUID = heatArtifact.getArtifactUUID(); + + System.out.println("Resource UUID: " + resourceUUID); + System.out.println("Artifact UUID: " + artifactUUID); + + RestResponse restResponse = ArtifactRestUtils.getResourceDeploymentArtifactExternalAPI(resourceUUID, artifactUUID, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), "Resource"); + + Integer responseCode = restResponse.getErrorCode(); + Integer expectedCode = 200; + Assert.assertEquals(responseCode,expectedCode, "Response code is not correct."); + + String response = restResponse.getResponse(); + + String payloadData = "aGVhdF90ZW1wbGF0ZV92ZXJzaW9uOiAyMDEzLTA1LTIzDQoNCmRlc2NyaXB0aW9uOiBTaW1wbGUgdGVtcGxhdGUgdG8gZGVwbG95IGEgc3RhY2sgd2l0aCB0d28gdmlydHVhbCBtYWNoaW5lIGluc3RhbmNlcw0KDQpwYXJhbWV0ZXJzOg0KICBpbWFnZV9uYW1lXzE6DQogICAgdHlwZTogc3RyaW5nDQogICAgbGFiZWw6IEltYWdlIE5hbWUNCiAgICBkZXNjcmlwdGlvbjogU0NPSU1BR0UgU3BlY2lmeSBhbiBpbWFnZSBuYW1lIGZvciBpbnN0YW5jZTENCiAgICBkZWZhdWx0OiBjaXJyb3MtMC4zLjEteDg2XzY0DQogIGltYWdlX25hbWVfMjoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogSW1hZ2UgTmFtZQ0KICAgIGRlc2NyaXB0aW9uOiBTQ09JTUFHRSBTcGVjaWZ5IGFuIGltYWdlIG5hbWUgZm9yIGluc3RhbmNlMg0KICAgIGRlZmF1bHQ6IGNpcnJvcy0wLjMuMS14ODZfNjQNCiAgbmV0d29ya19pZDoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogTmV0d29yayBJRA0KICAgIGRlc2NyaXB0aW9uOiBTQ09ORVRXT1JLIE5ldHdvcmsgdG8gYmUgdXNlZCBmb3IgdGhlIGNvbXB1dGUgaW5zdGFuY2UNCiAgICBoaWRkZW46IHRydWUNCiAgICBjb25zdHJhaW50czoNCiAgICAgIC0gbGVuZ3RoOiB7IG1pbjogNiwgbWF4OiA4IH0NCiAgICAgICAgZGVzY3JpcHRpb246IFBhc3N3b3JkIGxlbmd0aCBtdXN0IGJlIGJldHdlZW4gNiBhbmQgOCBjaGFyYWN0ZXJzLg0KICAgICAgLSByYW5nZTogeyBtaW46IDYsIG1heDogOCB9DQogICAgICAgIGRlc2NyaXB0aW9uOiBSYW5nZSBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3ZhbHVlczoNCiAgICAgICAgLSBtMS5zbWFsbA0KICAgICAgICAtIG0xLm1lZGl1bQ0KICAgICAgICAtIG0xLmxhcmdlDQogICAgICAgIGRlc2NyaXB0aW9uOiBBbGxvd2VkIHZhbHVlcyBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbYS16QS1aMC05XSsiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IGNvbnNpc3Qgb2YgY2hhcmFjdGVycyBhbmQgbnVtYmVycyBvbmx5Lg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbQS1aXStbYS16QS1aMC05XSoiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IHN0YXJ0IHdpdGggYW4gdXBwZXJjYXNlIGNoYXJhY3Rlci4NCiAgICAgIC0gY3VzdG9tX2NvbnN0cmFpbnQ6IG5vdmEua2V5cGFpcg0KICAgICAgICBkZXNjcmlwdGlvbjogQ3VzdG9tIGRlc2NyaXB0aW9uDQoNCnJlc291cmNlczoNCiAgbXlfaW5zdGFuY2UxOg0KICAgIHR5cGU6IE9TOjpOb3ZhOjpTZXJ2ZXINCiAgICBwcm9wZXJ0aWVzOg0KICAgICAgaW1hZ2U6IHsgZ2V0X3BhcmFtOiBpbWFnZV9uYW1lXzEgfQ0KICAgICAgZmxhdm9yOiBtMS5zbWFsbA0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9DQogIG15X2luc3RhbmNlMjoNCiAgICB0eXBlOiBPUzo6Tm92YTo6U2VydmVyDQogICAgcHJvcGVydGllczoNCiAgICAgIGltYWdlOiB7IGdldF9wYXJhbTogaW1hZ2VfbmFtZV8yIH0NCiAgICAgIGZsYXZvcjogbTEudGlueQ0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9"; + String decodedPaypload = Decoder.decode(payloadData); + + Assert.assertEquals(response, decodedPaypload, "Response deployment artifact not correct."); + + String auditAction = "DownloadArtifact"; + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setResourceName(resourceDetails.getName()); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + + expectedResourceAuditJavaObject.setCONSUMER_ID("ci"); + String resource_url = String.format("/sdc/v1/catalog/resources/%s/artifacts/%s", resourceUUID, artifactUUID); + expectedResourceAuditJavaObject.setRESOURCE_URL(resource_url); + + AuditValidationUtils.validateAuditDownloadExternalAPI(expectedResourceAuditJavaObject, auditAction, null, false); + } + + + // External API - Download artifact for resource - negative test + @Test + public void downloadArtifactFromResourceViaExternalAPINegativeTest() throws Exception { + Resource resourceDetailsVF; + Either createdResource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + resourceDetailsVF = createdResource.left().value(); + ArtifactDefinition heatArtifact = AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVF, UserRoleEnum.DESIGNER, true, true).left().value(); + resourceDetails = new ResourceReqDetails(resourceDetailsVF); + + String resourceUUID = resourceDetailsVF.getUUID(); + String artifactUUID = heatArtifact.getArtifactUUID(); + + System.out.println("Resource UUID: " + resourceUUID); + System.out.println("Artifact UUID: " + artifactUUID); + + RestResponse restResponse = ArtifactRestUtils.getResourceDeploymentArtifactExternalAPI(resourceUUID, "dfsgfdsg324", ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), "Resource"); + + Integer responseCode = restResponse.getErrorCode(); + Integer expectedCode = 200; + Assert.assertEquals(responseCode,expectedCode, "Response code is not correct."); + } + + + + + + // External API - Download artifact for service - negative test + @Test + public void downloadArtifactFromServiceViaExternalAPI() throws Exception { + + Service resourceDetailsService; + Either createdResource = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + resourceDetailsService = createdResource.left().value(); + + ArtifactDefinition heatArtifact = AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, resourceDetailsService, UserRoleEnum.DESIGNER, true, true).left().value(); + + String resourceUUID = resourceDetailsService.getUUID(); + String artifactUUID = heatArtifact.getArtifactUUID(); + + System.out.println("Resource UUID: " + resourceUUID); + System.out.println("Artifact UUID: " + artifactUUID); + + RestResponse restResponse = ArtifactRestUtils.getResourceDeploymentArtifactExternalAPI(resourceUUID, artifactUUID, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), "Service"); + + Integer responseCode = restResponse.getErrorCode(); + Integer expectedCode = 200; + Assert.assertEquals(responseCode,expectedCode, "Response code is not correct."); + + String response = restResponse.getResponse(); + + String payloadData = "aGVhdF90ZW1wbGF0ZV92ZXJzaW9uOiAyMDEzLTA1LTIzDQoNCmRlc2NyaXB0aW9uOiBTaW1wbGUgdGVtcGxhdGUgdG8gZGVwbG95IGEgc3RhY2sgd2l0aCB0d28gdmlydHVhbCBtYWNoaW5lIGluc3RhbmNlcw0KDQpwYXJhbWV0ZXJzOg0KICBpbWFnZV9uYW1lXzE6DQogICAgdHlwZTogc3RyaW5nDQogICAgbGFiZWw6IEltYWdlIE5hbWUNCiAgICBkZXNjcmlwdGlvbjogU0NPSU1BR0UgU3BlY2lmeSBhbiBpbWFnZSBuYW1lIGZvciBpbnN0YW5jZTENCiAgICBkZWZhdWx0OiBjaXJyb3MtMC4zLjEteDg2XzY0DQogIGltYWdlX25hbWVfMjoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogSW1hZ2UgTmFtZQ0KICAgIGRlc2NyaXB0aW9uOiBTQ09JTUFHRSBTcGVjaWZ5IGFuIGltYWdlIG5hbWUgZm9yIGluc3RhbmNlMg0KICAgIGRlZmF1bHQ6IGNpcnJvcy0wLjMuMS14ODZfNjQNCiAgbmV0d29ya19pZDoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogTmV0d29yayBJRA0KICAgIGRlc2NyaXB0aW9uOiBTQ09ORVRXT1JLIE5ldHdvcmsgdG8gYmUgdXNlZCBmb3IgdGhlIGNvbXB1dGUgaW5zdGFuY2UNCiAgICBoaWRkZW46IHRydWUNCiAgICBjb25zdHJhaW50czoNCiAgICAgIC0gbGVuZ3RoOiB7IG1pbjogNiwgbWF4OiA4IH0NCiAgICAgICAgZGVzY3JpcHRpb246IFBhc3N3b3JkIGxlbmd0aCBtdXN0IGJlIGJldHdlZW4gNiBhbmQgOCBjaGFyYWN0ZXJzLg0KICAgICAgLSByYW5nZTogeyBtaW46IDYsIG1heDogOCB9DQogICAgICAgIGRlc2NyaXB0aW9uOiBSYW5nZSBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3ZhbHVlczoNCiAgICAgICAgLSBtMS5zbWFsbA0KICAgICAgICAtIG0xLm1lZGl1bQ0KICAgICAgICAtIG0xLmxhcmdlDQogICAgICAgIGRlc2NyaXB0aW9uOiBBbGxvd2VkIHZhbHVlcyBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbYS16QS1aMC05XSsiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IGNvbnNpc3Qgb2YgY2hhcmFjdGVycyBhbmQgbnVtYmVycyBvbmx5Lg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbQS1aXStbYS16QS1aMC05XSoiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IHN0YXJ0IHdpdGggYW4gdXBwZXJjYXNlIGNoYXJhY3Rlci4NCiAgICAgIC0gY3VzdG9tX2NvbnN0cmFpbnQ6IG5vdmEua2V5cGFpcg0KICAgICAgICBkZXNjcmlwdGlvbjogQ3VzdG9tIGRlc2NyaXB0aW9uDQoNCnJlc291cmNlczoNCiAgbXlfaW5zdGFuY2UxOg0KICAgIHR5cGU6IE9TOjpOb3ZhOjpTZXJ2ZXINCiAgICBwcm9wZXJ0aWVzOg0KICAgICAgaW1hZ2U6IHsgZ2V0X3BhcmFtOiBpbWFnZV9uYW1lXzEgfQ0KICAgICAgZmxhdm9yOiBtMS5zbWFsbA0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9DQogIG15X2luc3RhbmNlMjoNCiAgICB0eXBlOiBPUzo6Tm92YTo6U2VydmVyDQogICAgcHJvcGVydGllczoNCiAgICAgIGltYWdlOiB7IGdldF9wYXJhbTogaW1hZ2VfbmFtZV8yIH0NCiAgICAgIGZsYXZvcjogbTEudGlueQ0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9"; + String decodedPaypload = Decoder.decode(payloadData); + + Assert.assertEquals(response, decodedPaypload, "Response deployment artifact not correct."); + + String auditAction = "DownloadArtifact"; + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setResourceName(resourceDetailsService.getName()); + expectedResourceAuditJavaObject.setResourceType("Service"); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + + expectedResourceAuditJavaObject.setCONSUMER_ID("ci"); + String resource_url = String.format("/sdc/v1/catalog/services/%s/artifacts/%s", resourceUUID, artifactUUID); + expectedResourceAuditJavaObject.setRESOURCE_URL(resource_url); + + AuditValidationUtils.validateAuditDownloadExternalAPI(expectedResourceAuditJavaObject, auditAction, null, false); + } + + + + + + + // External API - Download ComponentInstance artifact of service - negative test + @Test + public void downloadArtifactOfComponentInstanceFromServiceViaExternalAPI() throws Exception { + + Either resourceDetailsVF_01e = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + Component resourceDetailsVF_01 = resourceDetailsVF_01e.left().value(); + ArtifactDefinition heatArtifact = AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true, true).left().value(); + + resourceDetailsVF_01 = AtomicOperationUtils.changeComponentState(resourceDetailsVF_01, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + Service resourceDetailsService; + Either createdResource = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + resourceDetailsService = createdResource.left().value(); + + + ComponentInstance resourceDetailsVF1ins_01 = AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVF_01, resourceDetailsService, UserRoleEnum.DESIGNER, true).left().value(); + + + System.out.println("-----"); + + + String resourceUUID = resourceDetailsService.getUUID(); + String componentNormalizedName = resourceDetailsVF1ins_01.getNormalizedName(); + String artifactUUID = heatArtifact.getArtifactUUID(); + + System.out.println("Resource UUID: " + resourceUUID); + System.out.println("Component NormalizedName: " + componentNormalizedName); + System.out.println("Artifact UUID: " + artifactUUID); + + RestResponse restResponse = ArtifactRestUtils.getComponentInstanceDeploymentArtifactExternalAPI(resourceUUID, componentNormalizedName, artifactUUID, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), "Service"); +// + Integer responseCode = restResponse.getErrorCode(); + Integer expectedCode = 200; + Assert.assertEquals(responseCode,expectedCode, "Response code is not correct."); + + String response = restResponse.getResponse(); + + String payloadData = "aGVhdF90ZW1wbGF0ZV92ZXJzaW9uOiAyMDEzLTA1LTIzDQoNCmRlc2NyaXB0aW9uOiBTaW1wbGUgdGVtcGxhdGUgdG8gZGVwbG95IGEgc3RhY2sgd2l0aCB0d28gdmlydHVhbCBtYWNoaW5lIGluc3RhbmNlcw0KDQpwYXJhbWV0ZXJzOg0KICBpbWFnZV9uYW1lXzE6DQogICAgdHlwZTogc3RyaW5nDQogICAgbGFiZWw6IEltYWdlIE5hbWUNCiAgICBkZXNjcmlwdGlvbjogU0NPSU1BR0UgU3BlY2lmeSBhbiBpbWFnZSBuYW1lIGZvciBpbnN0YW5jZTENCiAgICBkZWZhdWx0OiBjaXJyb3MtMC4zLjEteDg2XzY0DQogIGltYWdlX25hbWVfMjoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogSW1hZ2UgTmFtZQ0KICAgIGRlc2NyaXB0aW9uOiBTQ09JTUFHRSBTcGVjaWZ5IGFuIGltYWdlIG5hbWUgZm9yIGluc3RhbmNlMg0KICAgIGRlZmF1bHQ6IGNpcnJvcy0wLjMuMS14ODZfNjQNCiAgbmV0d29ya19pZDoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogTmV0d29yayBJRA0KICAgIGRlc2NyaXB0aW9uOiBTQ09ORVRXT1JLIE5ldHdvcmsgdG8gYmUgdXNlZCBmb3IgdGhlIGNvbXB1dGUgaW5zdGFuY2UNCiAgICBoaWRkZW46IHRydWUNCiAgICBjb25zdHJhaW50czoNCiAgICAgIC0gbGVuZ3RoOiB7IG1pbjogNiwgbWF4OiA4IH0NCiAgICAgICAgZGVzY3JpcHRpb246IFBhc3N3b3JkIGxlbmd0aCBtdXN0IGJlIGJldHdlZW4gNiBhbmQgOCBjaGFyYWN0ZXJzLg0KICAgICAgLSByYW5nZTogeyBtaW46IDYsIG1heDogOCB9DQogICAgICAgIGRlc2NyaXB0aW9uOiBSYW5nZSBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3ZhbHVlczoNCiAgICAgICAgLSBtMS5zbWFsbA0KICAgICAgICAtIG0xLm1lZGl1bQ0KICAgICAgICAtIG0xLmxhcmdlDQogICAgICAgIGRlc2NyaXB0aW9uOiBBbGxvd2VkIHZhbHVlcyBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbYS16QS1aMC05XSsiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IGNvbnNpc3Qgb2YgY2hhcmFjdGVycyBhbmQgbnVtYmVycyBvbmx5Lg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbQS1aXStbYS16QS1aMC05XSoiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IHN0YXJ0IHdpdGggYW4gdXBwZXJjYXNlIGNoYXJhY3Rlci4NCiAgICAgIC0gY3VzdG9tX2NvbnN0cmFpbnQ6IG5vdmEua2V5cGFpcg0KICAgICAgICBkZXNjcmlwdGlvbjogQ3VzdG9tIGRlc2NyaXB0aW9uDQoNCnJlc291cmNlczoNCiAgbXlfaW5zdGFuY2UxOg0KICAgIHR5cGU6IE9TOjpOb3ZhOjpTZXJ2ZXINCiAgICBwcm9wZXJ0aWVzOg0KICAgICAgaW1hZ2U6IHsgZ2V0X3BhcmFtOiBpbWFnZV9uYW1lXzEgfQ0KICAgICAgZmxhdm9yOiBtMS5zbWFsbA0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9DQogIG15X2luc3RhbmNlMjoNCiAgICB0eXBlOiBPUzo6Tm92YTo6U2VydmVyDQogICAgcHJvcGVydGllczoNCiAgICAgIGltYWdlOiB7IGdldF9wYXJhbTogaW1hZ2VfbmFtZV8yIH0NCiAgICAgIGZsYXZvcjogbTEudGlueQ0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9"; + String decodedPaypload = Decoder.decode(payloadData); + + Assert.assertEquals(response, decodedPaypload, "Response deployment artifact not correct."); + + String auditAction = "DownloadArtifact"; + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setResourceName(resourceDetailsVF1ins_01.getName()); + expectedResourceAuditJavaObject.setResourceType("Service"); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + + expectedResourceAuditJavaObject.setCONSUMER_ID("ci"); + String resource_url = String.format("/sdc/v1/catalog/services/%s/resourceInstances/%s/artifacts/%s", resourceUUID, componentNormalizedName, artifactUUID); + expectedResourceAuditJavaObject.setRESOURCE_URL(resource_url); + + AuditValidationUtils.validateAuditDownloadExternalAPI(expectedResourceAuditJavaObject, auditAction, null, false); + } + + + + + + + + + + @Test + public void downloadArtifactFromResourceTest() throws Exception { + + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + String jsonBody = createUploadArtifactBodyJson(); + + String resourceId = resourceDetails.getUniqueId(); + String url = String.format(Urls.ADD_ARTIFACT_TO_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId); + HttpPost httppost = createPostAddArtifactRequeast(jsonBody, url, true); + HttpResponse response = httpclient.execute(httppost); + int status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("failed to add artifact", 200, status); + + ArtifactDefinition origArtifact = getArtifactDataFromJson(jsonBody); + addArtifactDataFromResponse(response, origArtifact); + String artifactId = origArtifact.getUniqueId(); + + url = String.format(Urls.UI_DOWNLOAD_RESOURCE_ARTIFACT, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId, artifactId); + HttpGet httpGet = createGetRequest(url); + response = httpclient.execute(httpGet); + status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("failed to download artifact", 200, status); + + InputStream inputStream = response.getEntity().getContent(); + ArtifactUiDownloadData artifactUiDownloadData = getArtifactUiDownloadData(IOUtils.toString(inputStream)); + AssertJUnit.assertEquals("Downloaded payload is different from uploaded one", UPLOAD_ARTIFACT_PAYLOAD, artifactUiDownloadData.getBase64Contents()); + AssertJUnit.assertEquals("Downloaded artifact name is different from uploaded one", UPLOAD_ARTIFACT_NAME, artifactUiDownloadData.getArtifactName()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor.constructFieldsForAuditValidation(resourceDetails, resourceDetails.getVersion(), sdncUserDetails); + String auditAction = "ArtifactDownload"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setArtifactData(AuditValidationUtils.buildArtifactDataAudit(origArtifact)); + expectedResourceAuditJavaObject.setCurrArtifactUuid(origArtifact.getUniqueId()); + expectedResourceAuditJavaObject.setPrevArtifactUuid(""); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } finally { + httpclient.close(); + } + + } + + @Test + public void downloadArtifactFromServiceTest() throws Exception { + + CloseableHttpClient httpclient = HttpClients.createDefault(); + + try { + + String jsonStr = createUploadArtifactBodyJson(); + + String url = String.format(Urls.ADD_ARTIFACT_TO_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), serviceDetails.getUniqueId()); + HttpPost httpPost = createPostAddArtifactRequeast(jsonStr, url, true); + CloseableHttpResponse result = httpclient.execute(httpPost); + int status = result.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("failed to add artifact", 200, status); + + ArtifactDefinition origArtifact = getArtifactDataFromJson(jsonStr); + addArtifactDataFromResponse(result, origArtifact); + String artifactId = origArtifact.getUniqueId(); + + url = String.format(Urls.UI_DOWNLOAD_SERVICE_ARTIFACT, config.getCatalogBeHost(), config.getCatalogBePort(), serviceDetails.getUniqueId(), artifactId); + HttpGet httpGet = createGetRequest(url); + CloseableHttpResponse response2 = httpclient.execute(httpGet); + status = response2.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("failed to download artifact", 200, status); + InputStream inputStream = response2.getEntity().getContent(); + ArtifactUiDownloadData artifactUiDownloadData = getArtifactUiDownloadData(IOUtils.toString(inputStream)); + AssertJUnit.assertEquals("Downloaded payload is different from uploaded one", UPLOAD_ARTIFACT_PAYLOAD, artifactUiDownloadData.getBase64Contents()); + AssertJUnit.assertEquals("Downloaded artifact name is different from uploaded one", UPLOAD_ARTIFACT_NAME, artifactUiDownloadData.getArtifactName()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = AuditValidationUtils.constructFieldsForAuditValidation(serviceDetails, serviceDetails.getVersion(), sdncUserDetails); + String auditAction = "ArtifactDownload"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setArtifactData(AuditValidationUtils.buildArtifactDataAudit(origArtifact)); + expectedResourceAuditJavaObject.setCurrArtifactUuid(origArtifact.getUniqueId()); + expectedResourceAuditJavaObject.setPrevArtifactUuid(""); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } finally { +// RestResponse response = ServiceRestUtils.deleteService(serviceDetails, serviceVersion, sdncUserDetails ); +// checkDeleteResponse(response); + httpclient.close(); + } + } + + @Test + public void downloadArtifactFromResourceNotFound() throws Exception { + + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + + String resourceId = resourceDetails.getUniqueId(); + String artifactIdNotFound = "11111"; + + ArtifactDefinition origArtifact = new ArtifactDefinition(); + origArtifact.setUniqueId(artifactIdNotFound); + + String url = String.format(Urls.UI_DOWNLOAD_RESOURCE_ARTIFACT, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId, artifactIdNotFound); + HttpGet httpGet = createGetRequest(url); + CloseableHttpResponse response = httpclient.execute(httpGet); + int status = response.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("expected 404 not found", 404, status); + + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_NOT_FOUND.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor.constructFieldsForAuditValidation(resourceDetails, resourceDetails.getVersion(), sdncUserDetails); + String auditAction = "ArtifactDownload"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setDesc(errorInfo.getAuditDesc("")); + expectedResourceAuditJavaObject.setArtifactData(""); + expectedResourceAuditJavaObject.setCurrArtifactUuid(origArtifact.getUniqueId()); + expectedResourceAuditJavaObject.setPrevArtifactUuid(""); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + expectedResourceAuditJavaObject.setPrevArtifactUuid(null); + } finally { + httpclient.close(); + } + + } + + @Test + public void downloadArtifactFromServiceNotFound() throws Exception { + + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + + String artifactIdNotFound = "11111"; + ArtifactDefinition origArtifact = new ArtifactDefinition(); + origArtifact.setUniqueId(artifactIdNotFound); + + String url = String.format(Urls.UI_DOWNLOAD_SERVICE_ARTIFACT, config.getCatalogBeHost(), config.getCatalogBePort(), serviceDetails.getUniqueId(), artifactIdNotFound); + HttpGet httpGet = createGetRequest(url); + CloseableHttpResponse response2 = httpclient.execute(httpGet); + int status = response2.getStatusLine().getStatusCode(); + AssertJUnit.assertEquals("expected 404 not found", 404, status); + + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_NOT_FOUND.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils.constructFieldsForAuditValidation(serviceDetails, serviceDetails.getVersion(), sdncUserDetails); + String auditAction = "ArtifactDownload"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setDesc(errorInfo.getAuditDesc("")); + expectedResourceAuditJavaObject.setArtifactData(""); + expectedResourceAuditJavaObject.setCurrArtifactUuid(origArtifact.getUniqueId()); + expectedResourceAuditJavaObject.setPrevArtifactUuid(""); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } finally { + httpclient.close(); + } + + } + + @Test + public void addArtifactToResourceTest() throws Exception { + + ArtifactReqDetails defaultArtifact = ElementFactory.getDefaultArtifact(); + + RestResponse response = ArtifactRestUtils.addInformationalArtifactToResource(defaultArtifact, sdncUserDetails, resourceDetails.getUniqueId()); + int status = response.getErrorCode(); + AssertJUnit.assertEquals("add informational artifact request returned status: " + response.getErrorCode(), 200, status); + + RestResponse resourceResp = ResourceRestUtils.getResource(resourceDetails.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(resourceResp.getResponse()); + AssertJUnit.assertNotNull(resource); + + Map artifacts = resource.getArtifacts(); + boolean isExist = false; + for (Map.Entry entry : artifacts.entrySet()) { + if (entry.getKey().equals(defaultArtifact.getArtifactLabel())) { + isExist = true; + + } + } + AssertJUnit.assertTrue(isExist); + } + + + protected String createUploadArtifactBodyJson() { + Map jsonBody = new HashMap(); + jsonBody.put("artifactName", UPLOAD_ARTIFACT_NAME); + jsonBody.put("artifactDisplayName", "configure"); + jsonBody.put("artifactType", "SHELL"); + jsonBody.put("mandatory", "false"); + jsonBody.put("description", "ff"); + jsonBody.put("payloadData", UPLOAD_ARTIFACT_PAYLOAD); + jsonBody.put("artifactLabel", "configure"); + return gson.toJson(jsonBody); + } + + protected ArtifactDefinition getArtifactDataFromJson(String json) { + Gson gson = new Gson(); + JsonObject jsonElement = new JsonObject(); + jsonElement = gson.fromJson(json, jsonElement.getClass()); + ArtifactDefinition artifact = new ArtifactDefinition(); + String payload = null; + JsonElement artifactPayload = jsonElement.get(Constants.ARTIFACT_PAYLOAD_DATA); + if (artifactPayload != null && !artifactPayload.isJsonNull()) { + payload = artifactPayload.getAsString(); + } + jsonElement.remove(Constants.ARTIFACT_PAYLOAD_DATA); + artifact = gson.fromJson(jsonElement, ArtifactDefinition.class); + artifact.setPayloadData(payload); + + /*atifact.setArtifactName(UPLOAD_ARTIFACT_NAME); +artifact.setArtifactDisplayName("configure"); +artifact.setArtifactType("SHELL"); +artifact.setMandatory(false); +artifact.setDescription("ff"); +artifact.setPayloadData(UPLOAD_ARTIFACT_PAYLOAD); +artifact.setArtifactLabel("configure");*/ + return artifact; + } + + protected HttpGet createGetRequest(String url) { + HttpGet httpGet = new HttpGet(url); + httpGet.addHeader(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + httpGet.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + httpGet.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + return httpGet; + } + + protected String getArtifactUid(HttpResponse response) throws HttpResponseException, IOException, ParseException { + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + String artifactId = (String) responseMap.get("uniqueId"); + return artifactId; + } + + protected String getArtifactEsId(HttpResponse response) throws HttpResponseException, IOException, ParseException { + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + String esId = (String) responseMap.get("EsId"); + return esId; + } + + protected ArtifactDefinition addArtifactDataFromResponse(HttpResponse response, ArtifactDefinition artifact) throws HttpResponseException, IOException, ParseException { + //String responseString = new BasicResponseHandler().handleResponse(response); + HttpEntity entity = response.getEntity(); + String responseString = EntityUtils.toString(entity); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + artifact.setEsId((String)responseMap.get("esId")); + artifact.setUniqueId((String) responseMap.get("uniqueId")); + artifact.setArtifactGroupType(ArtifactGroupTypeEnum.findType((String) responseMap.get("artifactGroupType"))); + artifact.setTimeout(((Long) responseMap.get("timeout")).intValue()); + return artifact; + } + + protected String getLifecycleArtifactUid(CloseableHttpResponse response) throws HttpResponseException, IOException, ParseException { + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + responseMap = (JSONObject) responseMap.get("implementation"); + String artifactId = (String) responseMap.get("uniqueId"); + return artifactId; + } + + protected HttpDelete createDeleteArtifactRequest(String url) { + HttpDelete httpDelete = new HttpDelete(url); + httpDelete.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + httpDelete.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + return httpDelete; + } + + protected HttpPost createPostAddArtifactRequeast(String jsonBody, String url, boolean addMd5Header) throws UnsupportedEncodingException { + HttpPost httppost = new HttpPost(url); + httppost.addHeader(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + httppost.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + httppost.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + if (addMd5Header) { + httppost.addHeader(HttpHeaderEnum.Content_MD5.getValue(), GeneralUtility.calculateMD5ByString(jsonBody)); + } + StringEntity input = new StringEntity(jsonBody); + input.setContentType("application/json"); + httppost.setEntity(input); + log.debug("Executing request {}" , httppost.getRequestLine()); + return httppost; + } + + protected String createLoadArtifactBody() { + Map json = new HashMap(); + json.put("artifactName", "install_apache2.sh"); + json.put("artifactType", "SHELL"); + json.put("description", "ddd"); + json.put("payloadData", "UEsDBAoAAAAIAAeLb0bDQz"); + json.put("artifactLabel", "name123"); + + String jsonStr = gson.toJson(json); + return jsonStr; + } + + protected void checkDeleteResponse(RestResponse response) { + BaseRestUtils.checkStatusCode(response, "delete request failed", false, 204, 404); + } + + protected ArtifactUiDownloadData getArtifactUiDownloadData(String artifactUiDownloadDataStr) throws Exception { + + ObjectMapper mapper = new ObjectMapper(); + try { + ArtifactUiDownloadData artifactUiDownloadData = mapper.readValue(artifactUiDownloadDataStr, ArtifactUiDownloadData.class); + return artifactUiDownloadData; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/HeatEnvArtifact.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/HeatEnvArtifact.java new file mode 100644 index 0000000000..e50d5b4ef9 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/HeatEnvArtifact.java @@ -0,0 +1,192 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.artifacts; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.elements.HeatParameterDataDefinition; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ArtifactUiDownloadData; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.HeatParameterDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.annotations.Test; +import org.yaml.snakeyaml.Yaml; + +public class HeatEnvArtifact extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public HeatEnvArtifact() { + super(name, HeatEnvArtifact.class.getName()); + } + + @Test(enabled = true) + public void heatEnvOnResourceFormatTest() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + Resource createdResource = createVfFromCSAR(sdncModifierDetails, "csarHeatEnv.csar"); + assertNotNull(createdResource); + + RestResponse certifyState = LifecycleRestUtils.changeComponentState(createdResource, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + BaseRestUtils.checkSuccess(certifyState); + + Resource certifiedResource = ResponseParser.parseToObjectUsingMapper(certifyState.getResponse(), Resource.class); + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService("ciNewtestservice1", ServiceCategoriesEnum.MOBILITY, sdncModifierDetails.getUserId()); + + // 2 create service + RestResponse createServiceResponse = ServiceRestUtils.createService(serviceDetails, sdncModifierDetails); + ResourceRestUtils.checkCreateResponse(createServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(createServiceResponse.getResponse(), Service.class); + + // 3 create vf instance in service + ComponentInstanceReqDetails componentInstanceDetails = ElementFactory.getComponentInstance(certifiedResource); + RestResponse createComponentInstance = ComponentInstanceRestUtils.createComponentInstance(componentInstanceDetails, sdncModifierDetails, service); + ResourceRestUtils.checkCreateResponse(createComponentInstance); + + RestResponse getService = ServiceRestUtils.getService(service.getUniqueId()); + BaseRestUtils.checkSuccess(getService); + service = ResponseParser.parseToObjectUsingMapper(getService.getResponse(), Service.class); + + List componentInstances = service.getComponentInstances(); + assertNotNull(componentInstances); + assertEquals(1, componentInstances.size()); + + ComponentInstance vfi = componentInstances.get(0); + Map deploymentArtifacts = vfi.getDeploymentArtifacts(); + assertNotNull(deploymentArtifacts); + assertEquals(4, deploymentArtifacts.size()); + ArtifactDefinition heatEnv = deploymentArtifacts.get("heat0env"); + assertNotNull(heatEnv); + + Map yaml = downloadComponentInstanceYamlFile(service.getUniqueId(), vfi.getUniqueId(), sdncModifierDetails, heatEnv.getUniqueId()); + assertNotNull(yaml); + Map paramters = (Map)yaml.get("parameters"); + assertNotNull(paramters); + assertEquals(8, paramters.size()); + assertEquals(null, paramters.get("param8")); + List heatParameters = heatEnv.getHeatParameters(); + heatParameters.forEach(p -> { + assertEquals(p.getCurrentValue(), paramters.get(p.getName())); + }); + } + @Test(enabled = true) + public void noHeatEnvOnResourceFormatTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + Resource createdResource = createVfFromCSAR(sdncModifierDetails, "csarHeatNoEnv.csar"); + assertNotNull(createdResource); + + RestResponse certifyState = LifecycleRestUtils.changeComponentState(createdResource, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + BaseRestUtils.checkSuccess(certifyState); + + Resource certifiedResource = ResponseParser.parseToObjectUsingMapper(certifyState.getResponse(), Resource.class); + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService("ciNewtestservice1", ServiceCategoriesEnum.MOBILITY, sdncModifierDetails.getUserId()); + + // 2 create service + RestResponse createServiceResponse = ServiceRestUtils.createService(serviceDetails, sdncModifierDetails); + ResourceRestUtils.checkCreateResponse(createServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(createServiceResponse.getResponse(), Service.class); + + // 3 create vf instance in service + ComponentInstanceReqDetails componentInstanceDetails = ElementFactory.getComponentInstance(certifiedResource); + RestResponse createComponentInstance = ComponentInstanceRestUtils.createComponentInstance(componentInstanceDetails, sdncModifierDetails, service); + ResourceRestUtils.checkCreateResponse(createComponentInstance); + + RestResponse getService = ServiceRestUtils.getService(service.getUniqueId()); + BaseRestUtils.checkSuccess(getService); + service = ResponseParser.parseToObjectUsingMapper(getService.getResponse(), Service.class); + + List componentInstances = service.getComponentInstances(); + assertNotNull(componentInstances); + assertEquals(1, componentInstances.size()); + + ComponentInstance vfi = componentInstances.get(0); + Map deploymentArtifacts = vfi.getDeploymentArtifacts(); + assertNotNull(deploymentArtifacts); + assertEquals(4, deploymentArtifacts.size()); + ArtifactDefinition heatEnv = deploymentArtifacts.get("heat0env"); + assertNotNull(heatEnv); + + Map yaml = downloadComponentInstanceYamlFile(service.getUniqueId(), vfi.getUniqueId(), sdncModifierDetails, heatEnv.getUniqueId()); + assertNotNull(yaml); + Map paramters = (Map)yaml.get("parameters"); + assertNotNull(paramters); + assertEquals(8, paramters.size()); + assertEquals(null, paramters.get("param1")); + assertEquals(null, paramters.get("param2")); + assertEquals(null, paramters.get("param4")); + assertEquals(null, paramters.get("param5")); + assertEquals(null, paramters.get("param7")); + assertEquals(null, paramters.get("param8")); + List heatParameters = heatEnv.getHeatParameters(); + heatParameters.forEach(p -> { + assertEquals(p.getCurrentValue(), paramters.get(p.getName())); + }); + + } + //**************************************** + private Map downloadComponentInstanceYamlFile(String serviceUniqueId, String resourceInstanceId, User user, String artifactUniqeId) throws Exception { + RestResponse heatEnvDownloadResponse = ArtifactRestUtils.downloadResourceInstanceArtifact(serviceUniqueId, resourceInstanceId, user, artifactUniqeId); + BaseRestUtils.checkSuccess(heatEnvDownloadResponse); + + ArtifactUiDownloadData artifactUiDownloadData = ResponseParser.parseToObject(heatEnvDownloadResponse.getResponse(), ArtifactUiDownloadData.class); + byte[] fromUiDownload = artifactUiDownloadData.getBase64Contents().getBytes(); + byte[] decodeBase64 = Base64.decodeBase64(fromUiDownload); + Yaml yaml = new Yaml(); + + InputStream inputStream = new ByteArrayInputStream(decodeBase64); + + Map load = (Map) yaml.load(inputStream); + + return load; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/PlaceHolderValidations.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/PlaceHolderValidations.java new file mode 100644 index 0000000000..0718fb6e5c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/PlaceHolderValidations.java @@ -0,0 +1,704 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.artifacts; + +//import static org.junit.Assert.assertTrue; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.javatuples.Pair; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.cassandra.CassandraUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.general.FileUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.datastax.driver.core.Row; + +import fj.data.Either; + +public class PlaceHolderValidations extends ComponentBaseTest { + private static Logger logger = LoggerFactory.getLogger(PlaceHolderValidations.class.getName()); + private static final String heatExtension = "yaml"; + // private static final String yangXmlExtension = "xml"; + // private static final String muranoPkgExtension = "zip"; + private final String folderName = "addHeatArtifactToServiceAndSertify"; + private Resource resource; + private final int timeOut = 60; + private ArtifactReqDetails updateArtifactReqDetails = null; + protected User sdncDesignerDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + protected User sdncDesignerDetails2 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2); + protected ResourceReqDetails resourceDetails1; + protected ResourceReqDetails resourceVF; + protected ResourceReqDetails resourceCP; + protected ResourceReqDetails resourceVL; + + protected ArtifactReqDetails heatArtifactDetails; + protected ArtifactReqDetails heatVolArtifactDetails; + protected ArtifactReqDetails heatNetArtifactDetails; + + public PlaceHolderValidations() { + super(name, PlaceHolderValidations.class.getName()); + } + + @Rule + public static TestName name = new TestName(); + + @BeforeMethod + public void init() throws IOException, Exception { + + heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatNetArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT_NET.getType()); + heatVolArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT_VOL.getType()); + Resource resourceObject = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resourceDetails1 = new ResourceReqDetails(resourceObject); + resourceObject = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true) + .left().value(); + resourceVF = new ResourceReqDetails(resourceObject); + resourceObject = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.CP, UserRoleEnum.DESIGNER, true) + .left().value(); + resourceCP = new ResourceReqDetails(resourceObject); + resourceObject = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VL, UserRoleEnum.DESIGNER, true) + .left().value(); + resourceVL = new ResourceReqDetails(resourceObject); + } + + @Test + public void validateDeploymentPlaceHoldersByConfig() throws IOException { + RestResponse resourceGetResponse = ResourceRestUtils.getResource(resourceDetails1, sdncDesignerDetails1); + Resource resourceObject = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceObject.getDeploymentArtifacts(); + assertNotNull("deploymentArtifacts list is null", deploymentArtifacts); + List listOfResDepArtTypesFromConfig = Utils.getListOfDepResArtLabels(true); + assertNotNull("deployment artifact types list is null", listOfResDepArtTypesFromConfig); + for (String resDepArtType : listOfResDepArtTypesFromConfig) { + assertNotNull("placeholder of " + resDepArtType + " type doesn't exist", + deploymentArtifacts.get(resDepArtType)); + } + } + + private void validateToscaArtifactsBeforeAndAfterSFT(ResourceReqDetails resourceDetails) + throws IOException, Exception { + RestResponse componentResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails1); + Component component = ResponseParser.convertResourceResponseToJavaObject(componentResponse.getResponse()); + Map toscaArtifacts = component.getToscaArtifacts(); + for (ArtifactDefinition artifact : toscaArtifacts.values()) { + assertNull(artifact.getEsId()); + } + + componentResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncDesignerDetails1, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + component = ResponseParser.convertResourceResponseToJavaObject(componentResponse.getResponse()); + toscaArtifacts = component.getToscaArtifacts(); + + for (ArtifactDefinition artifact : toscaArtifacts.values()) { + assertEquals(artifact.getEsId(), artifact.getUniqueId()); + List> fields = new ArrayList(); + fields.add(new Pair("id", artifact.getEsId())); + List fetchFromTable = CassandraUtils.fetchFromTableQuery("sdcartifact", "resources", fields); + assertTrue(1 == fetchFromTable.size()); + } + } + + @Test + public void validateToscaArtifactsBeforeAndAfterSFT() throws IOException, Exception { + // TODO ADD VF and Service + validateToscaArtifactsBeforeAndAfterSFT(resourceDetails1); + validateToscaArtifactsBeforeAndAfterSFT(resourceCP); + validateToscaArtifactsBeforeAndAfterSFT(resourceVL); + } + + @Test + public void validateToscaPlaceHoldersByConfig() throws IOException, Exception { + List components = new ArrayList<>(); + RestResponse componentGetResponse = ResourceRestUtils.getResource(resourceDetails1, sdncDesignerDetails1); + components.add(ResponseParser.convertResourceResponseToJavaObject(componentGetResponse.getResponse())); + + componentGetResponse = ResourceRestUtils.getResource(resourceCP, sdncDesignerDetails1); + components.add(ResponseParser.convertResourceResponseToJavaObject(componentGetResponse.getResponse())); + + componentGetResponse = ResourceRestUtils.getResource(resourceVF, sdncDesignerDetails1); + components.add(ResponseParser.convertResourceResponseToJavaObject(componentGetResponse.getResponse())); + + componentGetResponse = ResourceRestUtils.getResource(resourceVL, sdncDesignerDetails1); + components.add(ResponseParser.convertResourceResponseToJavaObject(componentGetResponse.getResponse())); + + Service service = AtomicOperationUtils + .createServiceByCategory(ServiceCategoriesEnum.MOBILITY, UserRoleEnum.DESIGNER, true).left().value(); + componentGetResponse = ServiceRestUtils.getService(service.getUniqueId(), + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + components.add(ResponseParser.parseToObjectUsingMapper(componentGetResponse.getResponse(), Service.class)); + + for (Component component : components) { + Map toscaArtifacts = component.getToscaArtifacts(); + assertNotNull("toscaArtifacts list is null", toscaArtifacts); + List listOfToscaArtTypesFromConfig = Utils.getListOfToscaArtLabels(true); + assertNotNull("tosca artifact types list is null", listOfToscaArtTypesFromConfig); + for (String toscaArtType : listOfToscaArtTypesFromConfig) { + assertNotNull("placeholder of " + toscaArtType + " type doesn't exist", + toscaArtifacts.get(toscaArtType)); + } + } + + } + + // test check configuration of "displayName" field for "heat" type + // deployment artifact + @Test + public void validateDeploymentPlaceHoldersDescriptionOfHeatByConfig() throws IOException { + + Map mapOfDepResArtTypesObjects = getMapOfDepResArtTypesObjects(); + assertNotNull("deployment artifact types list is null", mapOfDepResArtTypesObjects); + Object object = mapOfDepResArtTypesObjects.get("heat"); + if (object instanceof Map) { + Map map = (Map) object; + assertTrue(map.get("displayName").equals("Base HEAT Template")); + } else { + assertTrue("return object does not instance of map", false); + } + } + + @Test + public void addDepResArtEachType() throws Exception { + + String artType; + + addDeploymentArtifactByTypeToResource(resourceDetails1, heatArtifactDetails); + addDeploymentArtifactByTypeToResource(resourceDetails1, heatVolArtifactDetails); + addDeploymentArtifactByTypeToResource(resourceDetails1, heatNetArtifactDetails); + RestResponse response = ResourceRestUtils.getResource(resourceDetails1.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + List listOfResDepArtTypesFromConfig = Utils.getListOfDepResArtLabels(true); + assertNotNull("deployment artifact types list is null", listOfResDepArtTypesFromConfig); + for (String iter : listOfResDepArtTypesFromConfig) { + artType = iter; + verifyDepArtPlaceHoldersByType(artType); + } + } + + @Test + public void checkHeatParametersExistingForEachType() throws Exception { + + String artType; + + addDeploymentArtifactByTypeToResource(resourceDetails1, heatArtifactDetails); + addDeploymentArtifactByTypeToResource(resourceDetails1, heatVolArtifactDetails); + addDeploymentArtifactByTypeToResource(resourceDetails1, heatNetArtifactDetails); + RestResponse response = ResourceRestUtils.getResource(resourceDetails1.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + List listOfResDepArtTypesFromConfig = Utils.getListOfDepResArtLabels(true); + assertNotNull("deployment artifact types list is null", listOfResDepArtTypesFromConfig); + for (String iter : listOfResDepArtTypesFromConfig) { + artType = iter; + verifyDepArtPlaceHoldersByType(artType); + verifyHeatParametersExistance(artType, false); + } + } + + @Test + public void checkHeatParametersExistingForSpecificType() throws Exception { + + String artType; + + addDeploymentArtifactByTypeToResource(resourceDetails1, heatVolArtifactDetails); + addDeploymentArtifactByTypeToResource(resourceDetails1, heatNetArtifactDetails); + RestResponse response = ResourceRestUtils.getResource(resourceDetails1.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + List listOfResDepArtTypesFromConfig = Utils.getListOfDepResArtLabels(true); + assertNotNull("deployment artifact types list is null", listOfResDepArtTypesFromConfig); + for (String iter : listOfResDepArtTypesFromConfig) { + artType = iter; + if (heatArtifactDetails.getArtifactLabel().equals(iter)) { + verifyHeatParametersExistance(artType, true); + } else { + verifyHeatParametersExistance(artType, false); + } + } + } + + @Test + public void addAndDeleteDepResArtEachType() throws Exception { + + String artType; + + addDeploymentArtifactByTypeToResource(resourceDetails1, heatArtifactDetails); + addDeploymentArtifactByTypeToResource(resourceDetails1, heatVolArtifactDetails); + addDeploymentArtifactByTypeToResource(resourceDetails1, heatNetArtifactDetails); + RestResponse response = ResourceRestUtils.getResource(resourceDetails1.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + List listOfResDepArtTypesFromConfig = Utils.getListOfDepResArtLabels(true); + assertNotNull("deployment artifact types list is null", listOfResDepArtTypesFromConfig); + for (String iter : listOfResDepArtTypesFromConfig) { + artType = iter; + verifyDepArtPlaceHoldersByType(artType); + } + RestResponse restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails1, + sdncDesignerDetails1, LifeCycleStatesEnum.CHECKIN); + assertTrue("expected response code in CHECKIN 200", restResponseResource.getErrorCode() == 200); + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails1, sdncDesignerDetails1, + LifeCycleStatesEnum.CHECKOUT); + assertTrue("expected response code in CHECKOUT 200", restResponseResource.getErrorCode() == 200); + + // delete all deployment artifacts + deleteDeploymentArtifactByTypeToResource(resourceDetails1, heatArtifactDetails); + deleteDeploymentArtifactByTypeToResource(resourceDetails1, heatVolArtifactDetails); + deleteDeploymentArtifactByTypeToResource(resourceDetails1, heatNetArtifactDetails); + response = ResourceRestUtils.getResource(resourceDetails1.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + listOfResDepArtTypesFromConfig = Utils.getListOfDepResArtLabels(true); + assertNotNull("deployment artifact types list is null", listOfResDepArtTypesFromConfig); + for (String iter : listOfResDepArtTypesFromConfig) { + artType = iter; + verifyDepArtPlaceHoldersByType(artType); + } + } + + @Test + public void addRemoveAddAgainArtifact() throws Exception { + + // get MAP before upload artifact + RestResponse resourceGetResponse = ResourceRestUtils.getResource(resourceDetails1, sdncDesignerDetails1); + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + + ArtifactDefinition artifactDefinition = deploymentArtifacts.get("heat"); + + // validate place holder exist + assertNotNull(artifactDefinition); + + // add artifact + updateArtifactReqDetails = getUpdateArtifactDetails(ArtifactTypeEnum.HEAT.getType()); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource( + updateArtifactReqDetails, sdncDesignerDetails1, resourceDetails1.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: " + + addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not 200, returned :" + addInformationalArtifactToResource.getErrorCode(), + addInformationalArtifactToResource.getErrorCode() == 200); + + ArtifactDefinition artifactDefinitionResponseJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(addInformationalArtifactToResource.getResponse()); + ArtifactDefinition artDef1 = fillArtDefFromResponse(artifactDefinitionResponseJavaObject); + + // remove artifact + RestResponse deleteArtifactFromResource = ArtifactRestUtils.deleteInformationalArtifactFromResource( + resourceDetails1.getUniqueId(), updateArtifactReqDetails, sdncDesignerDetails1); + logger.debug( + "addInformationalArtifactToResource response: " + deleteArtifactFromResource.getResponseMessage()); + assertTrue("response code is not 200, returned :" + deleteArtifactFromResource.getErrorCode(), + deleteArtifactFromResource.getErrorCode() == 200); + + RestResponse getResourceResp = ResourceRestUtils.getResource(resourceDetails1, sdncDesignerDetails1); + + artifactDefinitionResponseJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(deleteArtifactFromResource.getResponse()); + assertTrue(artifactDefinitionResponseJavaObject.getArtifactName().isEmpty()); + assertTrue(artifactDefinitionResponseJavaObject.getDescription().isEmpty()); + assertTrue(artifactDefinitionResponseJavaObject.getArtifactChecksum().isEmpty()); + assertTrue(artifactDefinitionResponseJavaObject.getEsId().isEmpty()); + assertTrue(artifactDefinitionResponseJavaObject.getArtifactUUID().isEmpty()); + assertNull(artifactDefinitionResponseJavaObject.getHeatParameters()); + + // add artifact again with different user + addInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails1, resourceDetails1.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: " + + addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not 200, returned :" + addInformationalArtifactToResource.getErrorCode(), + addInformationalArtifactToResource.getErrorCode() == 200); + + artifactDefinitionResponseJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(addInformationalArtifactToResource.getResponse()); + ArtifactDefinition artDef2 = fillArtDefFromResponse(artifactDefinitionResponseJavaObject); + + assertFalse("check artifact checksum", artDef1.getArtifactChecksum().equals(artDef2.getArtifactChecksum())); + assertTrue("check artifact EsId", artDef1.getEsId().equals(artDef2.getEsId())); + assertFalse("check artifact UUID", artDef1.getArtifactUUID().equals(artDef2.getArtifactUUID())); + assertTrue("check UserIdCreator", artDef1.getUserIdCreator().equals(artDef2.getUserIdCreator())); + assertTrue("check UserIdLastUpdater", artDef1.getUserIdLastUpdater().equals(artDef2.getUserIdLastUpdater())); + } + + @Test + public void addUpdateArtifactByType() throws Exception { + + // get MAP before upload artifact + RestResponse resourceGetResponse = ResourceRestUtils.getResource(resourceDetails1, sdncDesignerDetails1); + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + + ArtifactDefinition artifactDefinition = deploymentArtifacts.get("heat"); + + // validate place holder exist + assertNotNull(artifactDefinition); + + // add artifact + updateArtifactReqDetails = getUpdateArtifactDetails(ArtifactTypeEnum.HEAT.getType()); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource( + updateArtifactReqDetails, sdncDesignerDetails1, resourceDetails1.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: " + + addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not 200, returned :" + addInformationalArtifactToResource.getErrorCode(), + addInformationalArtifactToResource.getErrorCode() == 200); + + ArtifactDefinition artifactDefinitionResponseJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(addInformationalArtifactToResource.getResponse()); + ArtifactDefinition artDef1 = fillArtDefFromResponse(artifactDefinitionResponseJavaObject); + + RestResponse restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails1, + sdncDesignerDetails1, LifeCycleStatesEnum.CHECKIN); + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails1, sdncDesignerDetails2, + LifeCycleStatesEnum.CHECKOUT); + + // update with different user artifact + heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setUniqueId(artifactDefinition.getUniqueId()); + heatArtifactDetails.setArtifactName("2.yaml"); + heatArtifactDetails.setArtifactLabel(artifactDefinition.getArtifactLabel()); + + addInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails2, resourceDetails1.getUniqueId(), "heat"); + logger.debug("addInformationalArtifactToResource response: " + + addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not 200, returned :" + addInformationalArtifactToResource.getErrorCode(), + addInformationalArtifactToResource.getErrorCode() == 200); + + artifactDefinitionResponseJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(addInformationalArtifactToResource.getResponse()); + ArtifactDefinition artDef2 = fillArtDefFromResponse(artifactDefinitionResponseJavaObject); + verifyArtDefFields(artDef1, artDef2); + + } + + @Test + public void addUpdateDeleteArtifact() throws Exception { + + // get MAP before upload artifact + RestResponse resourceGetResponse = ResourceRestUtils.getResource(resourceDetails1, sdncDesignerDetails1); + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + + ArtifactDefinition artifactDefinition = deploymentArtifacts.get("heat"); + + // validate place holder exist + assertNotNull(artifactDefinition); + + updateArtifactReqDetails = getUpdateArtifactDetails(ArtifactTypeEnum.HEAT.getType()); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource( + updateArtifactReqDetails, sdncDesignerDetails1, resourceDetails1.getUniqueId()); + logger.debug("addInformationalArtifactToResource response: " + + addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not 200, returned :" + addInformationalArtifactToResource.getErrorCode(), + addInformationalArtifactToResource.getErrorCode() == 200); + + ArtifactDefinition artifactDefinitionResponseJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(addInformationalArtifactToResource.getResponse()); + ArtifactDefinition artDef1 = fillArtDefFromResponse(artifactDefinitionResponseJavaObject); + + RestResponse restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails1, + sdncDesignerDetails1, LifeCycleStatesEnum.CHECKIN); + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails1, sdncDesignerDetails2, + LifeCycleStatesEnum.CHECKOUT); + + // update with different user artifact + heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setArtifactName("2.yaml"); + + addInformationalArtifactToResource = ArtifactRestUtils.updateInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails2, resourceDetails1.getUniqueId(), "heat"); + logger.debug("addInformationalArtifactToResource response: " + + addInformationalArtifactToResource.getResponseMessage()); + assertTrue("response code is not 200, returned :" + addInformationalArtifactToResource.getErrorCode(), + addInformationalArtifactToResource.getErrorCode() == 200); + + artifactDefinitionResponseJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(addInformationalArtifactToResource.getResponse()); + ArtifactDefinition artDef2 = fillArtDefFromResponse(artifactDefinitionResponseJavaObject); + + verifyArtDefFields(artDef1, artDef2); + + RestResponse delteArtifactFromResource = ArtifactRestUtils.deleteInformationalArtifactFromResource( + resourceDetails1.getUniqueId(), heatArtifactDetails, sdncDesignerDetails2); + logger.debug("addInformationalArtifactToResource response: {}", delteArtifactFromResource.getResponseMessage()); + assertTrue("response code is not 200, returned :" + delteArtifactFromResource.getErrorCode(), + delteArtifactFromResource.getErrorCode() == 200); + + } + + @Test + public void addHeatVolArtInvalidExtension() throws Exception { + + heatVolArtifactDetails.setArtifactName("heatVol.txt"); + RestResponse response = getResponseOnAddDeploymentArtifactByTypeToResource(resourceDetails1, + heatVolArtifactDetails); + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.WRONG_ARTIFACT_FILE_EXTENSION.name()); + assertEquals("Check response code after upload artifact", errorInfo.getCode(), response.getErrorCode()); + List variables = Arrays.asList(ArtifactTypeEnum.HEAT_VOL.getType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.WRONG_ARTIFACT_FILE_EXTENSION.name(), variables, + response.getResponse()); + } + + @Test + public void addHeatNetArtInvalidExtension() throws Exception { + + heatNetArtifactDetails.setArtifactName("yaml"); + RestResponse response = getResponseOnAddDeploymentArtifactByTypeToResource(resourceDetails1, + heatNetArtifactDetails); + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.WRONG_ARTIFACT_FILE_EXTENSION.name()); + assertEquals("Check response code after upload artifact", errorInfo.getCode(), response.getErrorCode()); + List variables = Arrays.asList(ArtifactTypeEnum.HEAT_NET.getType()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.WRONG_ARTIFACT_FILE_EXTENSION.name(), variables, + response.getResponse()); + } + + @Test + public void checkServiceSecurityTemplateInformationalArtifactsCreation() throws IOException, Exception { + + Either createServiceResponse = AtomicOperationUtils + .createServiceByCategory(ServiceCategoriesEnum.MOBILITY, UserRoleEnum.DESIGNER, true); + Map artifacts = null; + ArtifactDefinition securitytemplate = null; + if (createServiceResponse.isLeft()) { + Component component = createServiceResponse.left().value(); + artifacts = component.getArtifacts(); + securitytemplate = artifacts.get("servicesecuritytemplate"); + assertNotNull(securitytemplate); + assertEquals("Service Security Template", securitytemplate.getArtifactDisplayName()); + } else { + logger.debug("checkSecurityTemplateInformationalArtifactsCreation service creation response: " + + createServiceResponse.right().value().getResponseMessage()); + } + } + + @Test + public void checkResourceSecurityTemplateInformationalArtifactsCreation() throws IOException, Exception { + + Resource resource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.CONTAINER_APPLICATION, ResourceCategoryEnum.APPLICATION_L4_BORDER, + UserRoleEnum.DESIGNER, true).left().value(); + Map artifacts = resource.getArtifacts(); + ArtifactDefinition securitytemplate = artifacts.get("resourcesecuritytemplate"); + assertNotNull(securitytemplate); + assertEquals("Resource Security Template", securitytemplate.getArtifactDisplayName()); + } + + // Benny + @Test + public void serviceSecurityTemplateInformationalArtifact() throws IOException, Exception { + String artifactPlaceHolder = "servicesecuritytemplate"; + Service service = AtomicOperationUtils + .createServiceByCategory(ServiceCategoriesEnum.MOBILITY, UserRoleEnum.DESIGNER, true).left().value(); + Map artifacts = service.getArtifacts(); + ArtifactDefinition securitytemplate = artifacts.get(artifactPlaceHolder); + assertNotNull(securitytemplate); + assertEquals("Service Security Template", securitytemplate.getArtifactDisplayName()); + assertEquals("OTHER", securitytemplate.getArtifactType()); + assertEquals(artifactPlaceHolder, securitytemplate.getArtifactLabel()); + // Get service + RestResponse getService = ServiceRestUtils.getService(service.getUniqueId(), + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, getService.getErrorCode().intValue()); + service = ResponseParser.parseToObjectUsingMapper(getService.getResponse(), Service.class); + artifacts = service.getArtifacts(); + securitytemplate = artifacts.get(artifactPlaceHolder); + assertNotNull(securitytemplate); + assertEquals("Service Security Template", securitytemplate.getArtifactDisplayName()); + assertEquals("OTHER", securitytemplate.getArtifactType()); + assertEquals(artifactPlaceHolder, securitytemplate.getArtifactLabel()); + } + + @Test + public void resourceSecurityTemplateInformationalArtifacts() throws IOException, Exception { + String artifactPlaceHolder = "resourcesecuritytemplate"; + Resource resource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.CONTAINER_APPLICATION, ResourceCategoryEnum.APPLICATION_L4_BORDER, + UserRoleEnum.DESIGNER, true).left().value(); + Map artifacts = resource.getArtifacts(); + ArtifactDefinition securitytemplate = artifacts.get("resourcesecuritytemplate"); + assertNotNull(securitytemplate); + assertEquals("Resource Security Template", securitytemplate.getArtifactDisplayName()); + assertEquals("OTHER", securitytemplate.getArtifactType()); + assertEquals(artifactPlaceHolder, securitytemplate.getArtifactLabel()); + // Get resource + RestResponse getresource = ResourceRestUtils.getResource(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + resource.getUniqueId()); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, getresource.getErrorCode().intValue()); + resource = ResponseParser.parseToObjectUsingMapper(getresource.getResponse(), Resource.class); + artifacts = resource.getArtifacts(); + securitytemplate = artifacts.get(artifactPlaceHolder); + assertNotNull(securitytemplate); + assertEquals("Resource Security Template", securitytemplate.getArtifactDisplayName()); + assertEquals("OTHER", securitytemplate.getArtifactType()); + assertEquals(artifactPlaceHolder, securitytemplate.getArtifactLabel()); + } + + // ================================================ + + @SuppressWarnings("unchecked") + private Map getMapOfDepResArtTypesObjects() throws FileNotFoundException { + + return (Map) Utils.parseYamlConfig("deploymentResourceArtifacts"); + + } + + private void addDeploymentArtifactByTypeToResource(ResourceReqDetails resourceReqDetails, + ArtifactReqDetails artReqDetails) throws IOException, Exception { + + RestResponse response = ArtifactRestUtils.addInformationalArtifactToResource(artReqDetails, + sdncDesignerDetails1, resourceReqDetails.getUniqueId()); + assertTrue("add" + artReqDetails.getArtifactLabel() + " artifact to resource request returned status:" + + response.getErrorCode(), response.getErrorCode() == 200); + } + + private RestResponse getResponseOnAddDeploymentArtifactByTypeToResource(ResourceReqDetails resourceReqDetails, + ArtifactReqDetails artReqDetails) throws IOException, Exception { + + return ArtifactRestUtils.addInformationalArtifactToResource(artReqDetails, sdncDesignerDetails1, + resourceReqDetails.getUniqueId()); + } + + private void deleteDeploymentArtifactByTypeToResource(ResourceReqDetails resourceReqDetails, + ArtifactReqDetails artReqDetails) throws IOException, Exception { + + RestResponse response = ArtifactRestUtils.deleteInformationalArtifactFromResource( + resourceReqDetails.getUniqueId(), artReqDetails, sdncDesignerDetails1); + assertTrue("delete" + artReqDetails.getArtifactLabel() + " artifact to resource request returned status:" + + response.getErrorCode(), response.getErrorCode() == 200); + } + + private void verifyDepArtPlaceHoldersByType(String artType) { + + Map deploymentArtifacts = resource.getDeploymentArtifacts(); + assertNotNull("deployment artifact data is null", deploymentArtifacts.get(artType)); + assertNotNull("deployment artifact data is null", deploymentArtifacts.get(artType).getEsId()); + assertNotNull("deployment artifact data is null", deploymentArtifacts.get(artType).getDescription()); + assertTrue( + "deployment artifact timeout does not equal to default value " + timeOut + " expected " + timeOut + + ", actual - " + deploymentArtifacts.get(artType).getTimeout(), + deploymentArtifacts.get(artType).getTimeout() == timeOut); + assertTrue("deployment artifact label value ", + deploymentArtifacts.get(artType).getArtifactLabel().equals(artType)); + } + + private void verifyHeatParametersExistance(String artType, Boolean isNull) { + Map deploymentArtifacts = resource.getDeploymentArtifacts(); + if (isNull) { + assertNull("heatParameters list for type " + artType + " is not null", + deploymentArtifacts.get(artType).getHeatParameters()); + } else { + assertNotNull("heatParameters list for type " + artType + " is null", + deploymentArtifacts.get(artType).getHeatParameters()); + } + } + + private void verifyArtDefFields(ArtifactDefinition artDef1, ArtifactDefinition artDef2) { + + assertFalse("check artifact checksum", artDef1.getArtifactChecksum().equals(artDef2.getArtifactChecksum())); + assertFalse("check artifact EsId", artDef1.getEsId().equals(artDef2.getEsId())); + assertFalse("check artifact UUID", artDef1.getArtifactUUID().equals(artDef2.getArtifactUUID())); + assertTrue("check UserIdCreator", artDef1.getUserIdCreator().equals(artDef2.getUserIdCreator())); + assertFalse("check UserIdLastUpdater", artDef1.getUserIdLastUpdater().equals(artDef2.getUserIdLastUpdater())); + + } + + private ArtifactDefinition fillArtDefFromResponse(ArtifactDefinition artifactDefinitionResponseJavaObject) { + ArtifactDefinition artDef = new ArtifactDefinition(); + artDef.setArtifactChecksum(artifactDefinitionResponseJavaObject.getArtifactChecksum()); + artDef.setEsId(artifactDefinitionResponseJavaObject.getEsId()); + artDef.setArtifactUUID(artifactDefinitionResponseJavaObject.getArtifactUUID()); + artDef.setUserIdCreator(artifactDefinitionResponseJavaObject.getUserIdCreator()); + artDef.setUserIdLastUpdater(artifactDefinitionResponseJavaObject.getUserIdLastUpdater()); + return artDef; + } + + private ArtifactReqDetails getUpdateArtifactDetails(String artType) throws IOException, Exception { + String ext = heatExtension; + String sourceDir = config.getResourceConfigDir(); + String testResourcesPath = sourceDir + File.separator + folderName; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + logger.debug("listFileName: {}", listFileName.toString()); + + String payload = FileUtils.loadPayloadFile(listFileName, ext, true); + ArtifactReqDetails updateArtifactReqDetails = ElementFactory.getDefaultDeploymentArtifactForType(artType); + updateArtifactReqDetails.setPayload(payload); + updateArtifactReqDetails.setArtifactName("1.yaml"); + return updateArtifactReqDetails; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ValidateArtResponse.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ValidateArtResponse.java new file mode 100644 index 0000000000..6b902dbfb8 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ValidateArtResponse.java @@ -0,0 +1,632 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.artifacts; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.elements.HeatParameterDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.HeatParameterDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Decoder; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.ResourceValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.yaml.snakeyaml.Yaml; + +public class ValidateArtResponse extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + protected String serviceVersion; + + public ValidateArtResponse() { + super(name, ArtifactServletTest.class.getName()); + + } + + protected final String pathToFile = "heatArtifactParameters"; + protected final String heatWithValidParams = "heatWithValidParams.yaml"; + protected final String heatWithParamsMissingDefault = "heatWithParamsMissingDefault.yaml"; + protected final String heatWithParamsMissingDesc = "heatWithParamsMissingDesc.yaml"; + protected final String heatWithParamsMissingType = "heatWithParamsMissingType.yaml"; + protected final String importNoDerivedFromFile = "myComputeDerivedFromNotExists.yml"; + protected final String decodedPayload = "decodedPayload"; + protected final String encodedPayload = "encodedPayload"; + + protected Resource resourceDetailsObj; + protected ResourceReqDetails resourceDetails; + protected User sdncDesignerDetails; + + @BeforeMethod + public void init() throws Exception { + + resourceDetailsObj = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resourceDetails = new ResourceReqDetails(resourceDetailsObj); + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + } + + @Test + public void compareParamtersVsYaml() throws Exception { + + // select file to upload + + Map filePayload = selectFileToUpload(pathToFile, heatWithValidParams); + + // upload HEAT file and save JSON response + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(filePayload.get(encodedPayload)); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails, resourceDetails.getUniqueId()); + + // create MAP from received JSON + + String section2extract = "heatParameters"; + String createKeyMapBy = "name"; + Map> mapOfActualParameters = jsonToMap(addInformationalArtifactToResource, + section2extract, createKeyMapBy); + + // Prepare map to validate JS + + Map paramters = createMapFromYaml(filePayload.get(decodedPayload)); + + // compare MAPs + + ResourceValidationUtils.compareElements(mapOfActualParameters, paramters); + + } + + protected void assertnull(String string, boolean equals) { + // TODO Auto-generated method stub + + } + + public Map extractSingleParameter(Map curr) { + Map innerMap = new HashMap(); + if (curr.containsKey("description")) { + innerMap.put("description", curr.get("description")); + } + + if (curr.containsKey("defaultValue")) { + innerMap.put("default", curr.get("defaultValue")); + } else { + // System.out.println("kuku"); + } + innerMap.put("type", curr.get("type")); + return innerMap; + } + + public Map createMapFromYaml(String payload) { + ArrayList parametersList = new ArrayList(); + + Yaml yaml = new Yaml(); + + Map result = (Map) yaml.load(payload); + Map paramters = (Map) result.get("parameters"); + + for (Map.Entry entry : paramters.entrySet()) { + Map origInnerMap = (Map) entry.getValue(); + + if (origInnerMap.containsKey("label")) { + origInnerMap.remove("label"); + paramters.remove(entry); + paramters.put(entry.getKey(), origInnerMap); + } + } + return paramters; + } + + public Map> jsonToMap(RestResponse addInformationalArtifactToResource, + String section2extract, String createKeyMapBy) { + Map JsonToMap = new HashMap(); + JsonToMap = (Map) ResponseParser.parseToObject(addInformationalArtifactToResource.getResponse(), + JsonToMap.getClass()); + + List> listOfParamters = (List>) JsonToMap.get(section2extract); + Map> mapOfActualParameters = new HashMap>(); + + for (Map curr : listOfParamters) { + Map innerMap = extractSingleParameter(curr); + + mapOfActualParameters.put(curr.get(createKeyMapBy), innerMap); + } + return mapOfActualParameters; + } + + public Map selectFileToUpload(String pathToFile, String fileName) throws IOException { + String sourceDir = config.getResourceConfigDir(); + String testResourcesPath = sourceDir + File.separator + pathToFile; + String file = fileName; + Map filePayload = new HashMap(); + String payload = Decoder.readFileToString(testResourcesPath + File.separator + file); + filePayload.put(decodedPayload, payload); + filePayload.put(encodedPayload, Decoder.encode(payload.getBytes())); + + return filePayload; + } + + @Test + public void missingDescParam() throws Exception { + + // select file to upload + + Map filePayload = selectFileToUpload(pathToFile, heatWithParamsMissingDesc); + + // upload HEAT file and save JSON response + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(filePayload.get(encodedPayload)); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails, resourceDetails.getUniqueId()); + + // create MAP from received JSON + + String section2extract = "heatParameters"; + String createKeyMapBy = "name"; + Map> mapOfActualParameters = jsonToMap(addInformationalArtifactToResource, + section2extract, createKeyMapBy); + + // Prepare map to validate JS + + Map paramters = createMapFromYaml(filePayload.get(decodedPayload)); + + // compare MAPs + + ResourceValidationUtils.compareElements(mapOfActualParameters, paramters); + + } + + @Test + public void missingDefaultParam() throws Exception { + + // select file to upload + + Map filePayload = selectFileToUpload(pathToFile, heatWithParamsMissingDefault); + + // upload HEAT file and save JSON response + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(filePayload.get(encodedPayload)); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails, resourceDetails.getUniqueId()); + + // create MAP from received JSON + + String section2extract = "heatParameters"; + String createKeyMapBy = "name"; + Map> mapOfActualParameters = jsonToMap(addInformationalArtifactToResource, + section2extract, createKeyMapBy); + + // Prepare map to validate JS + + Map paramters = createMapFromYaml(filePayload.get(decodedPayload)); + + // compare MAPs + + ResourceValidationUtils.compareElements(mapOfActualParameters, paramters); + + } + + @Test + public void missingTypeParam() throws Exception { + + // select file to upload + + Map filePayload = selectFileToUpload(pathToFile, heatWithParamsMissingType); + + // upload HEAT file and save JSON response + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(filePayload.get(encodedPayload)); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails, resourceDetails.getUniqueId()); + + // System.out.println(addInformationalArtifactToResource); + AssertJUnit.assertTrue( + "response code is not 400, returned :" + addInformationalArtifactToResource.getErrorCode(), + addInformationalArtifactToResource.getErrorCode() == 400); + + } + + @Test + public void updateValueParam() throws Exception { + + String updateValueParam = "changed"; + + Map filePayload = selectFileToUpload(pathToFile, heatWithValidParams); + + // upload HEAT file and save JSON response + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(filePayload.get(encodedPayload)); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails, resourceDetails.getUniqueId()); + + RestResponse resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + // System.out.println(resourceGetResponse.getResponse().toString()); + String atifactUniqueId = ResponseParser + .getValueFromJsonResponse(addInformationalArtifactToResource.getResponse(), "uniqueId"); + + ArtifactReqDetails artifacJavaObject = ResponseParser + .convertArtifactReqDetailsToJavaObject(addInformationalArtifactToResource.getResponse()); + List heatParameters2 = artifacJavaObject.getHeatParameters(); + + for (HeatParameterDefinition heatParameterDefinition : heatParameters2) { + heatParameterDefinition.setCurrentValue(updateValueParam); + } + artifacJavaObject.setHeatParameters(heatParameters2); + artifacJavaObject.setPayloadData(null); + + RestResponse updateInformationalArtifactToResource = ArtifactRestUtils.updateDeploymentArtifactToResource( + artifacJavaObject, sdncDesignerDetails, resourceDetails.getUniqueId()); + + // verify change in update response + + ArtifactDefinition ArtifactDefinitionRespJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(updateInformationalArtifactToResource.getResponse()); + List heatParameters = ArtifactDefinitionRespJavaObject.getHeatParameters(); + for (HeatParameterDataDefinition heatParameterDefinition : heatParameters) { + String verify = updateValueParam; + AssertJUnit.assertTrue("verification failed", verify.equals(heatParameterDefinition.getCurrentValue())); + } + + // verify change in getResource + + resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + deploymentArtifacts.get(heatArtifactDetails.getArtifactName()); + for (HeatParameterDataDefinition heatParameterDefinition : heatParameters) { + String verify = updateValueParam; + AssertJUnit.assertTrue("verification failed", verify.equals(heatParameterDefinition.getCurrentValue())); + } + + // create MAP from received JSON + + String section2extract = "heatParameters"; + String createKeyMapBy = "name"; + Map> mapOfActualParameters = jsonToMap(addInformationalArtifactToResource, + section2extract, createKeyMapBy); + + // Prepare map to validate JS + + Map paramters = createMapFromYaml(filePayload.get(decodedPayload)); + + // compare MAPs + + ResourceValidationUtils.compareElements(mapOfActualParameters, paramters); + + } + + @Test + public void updateValueParamMissingDefault() throws Exception { + + String updateValueParam = "changed"; + + Map filePayload = selectFileToUpload(pathToFile, heatWithParamsMissingDefault); + + // upload HEAT file and save JSON response + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(filePayload.get(encodedPayload)); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails, resourceDetails.getUniqueId()); + + RestResponse resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + // System.out.println(resourceGetResponse.getResponse().toString()); + String atifactUniqueId = ResponseParser + .getValueFromJsonResponse(addInformationalArtifactToResource.getResponse(), "uniqueId"); + + ArtifactReqDetails artifacJavaObject = ResponseParser + .convertArtifactReqDetailsToJavaObject(addInformationalArtifactToResource.getResponse()); + List heatParameters2 = artifacJavaObject.getHeatParameters(); + + for (HeatParameterDefinition heatParameterDefinition : heatParameters2) { + heatParameterDefinition.setCurrentValue(updateValueParam); + } + artifacJavaObject.setHeatParameters(heatParameters2); + artifacJavaObject.setPayloadData(null); + + RestResponse updateInformationalArtifactToResource = ArtifactRestUtils.updateDeploymentArtifactToResource( + artifacJavaObject, sdncDesignerDetails, resourceDetails.getUniqueId()); + + // verify change in update response + + ArtifactDefinition ArtifactDefinitionRespJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(updateInformationalArtifactToResource.getResponse()); + List heatParameters = ArtifactDefinitionRespJavaObject.getHeatParameters(); + for (HeatParameterDataDefinition heatParameterDefinition : heatParameters) { + String verify = updateValueParam; + AssertJUnit.assertTrue("verification failed", verify.equals(heatParameterDefinition.getCurrentValue())); + } + + // verify change in getResource + + resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + deploymentArtifacts.get(heatArtifactDetails.getArtifactName()); + for (HeatParameterDataDefinition heatParameterDefinition : heatParameters) { + String verify = updateValueParam; + AssertJUnit.assertTrue("verification failed", verify.equals(heatParameterDefinition.getCurrentValue())); + } + + // create MAP from received JSON + + String section2extract = "heatParameters"; + String createKeyMapBy = "name"; + Map> mapOfActualParameters = jsonToMap(addInformationalArtifactToResource, + section2extract, createKeyMapBy); + + // Prepare map to validate JS + + Map paramters = createMapFromYaml(filePayload.get(decodedPayload)); + + // compare MAPs + + ResourceValidationUtils.compareElements(mapOfActualParameters, paramters); + + } + + @Test + public void updateValueParamNull() throws Exception { + + String updateValueParam = null; + + Map filePayload = selectFileToUpload(pathToFile, heatWithValidParams); + + // upload HEAT file and save JSON response + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(filePayload.get(encodedPayload)); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails, resourceDetails.getUniqueId()); + + RestResponse resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + // System.out.println(resourceGetResponse.getResponse().toString()); + String atifactUniqueId = ResponseParser + .getValueFromJsonResponse(addInformationalArtifactToResource.getResponse(), "uniqueId"); + + ArtifactReqDetails artifacJavaObject = ResponseParser + .convertArtifactReqDetailsToJavaObject(addInformationalArtifactToResource.getResponse()); + List heatParameters2 = artifacJavaObject.getHeatParameters(); + + for (HeatParameterDefinition heatParameterDefinition : heatParameters2) { + heatParameterDefinition.setCurrentValue(updateValueParam); + } + artifacJavaObject.setHeatParameters(heatParameters2); + artifacJavaObject.setPayloadData(null); + + RestResponse updateInformationalArtifactToResource = ArtifactRestUtils.updateDeploymentArtifactToResource( + artifacJavaObject, sdncDesignerDetails, resourceDetails.getUniqueId()); + + // verify change in update response + ArtifactDefinition ArtifactDefinitionRespJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(updateInformationalArtifactToResource.getResponse()); + List heatParameters = ArtifactDefinitionRespJavaObject.getHeatParameters(); + for (HeatParameterDataDefinition heatParameterDefinition : heatParameters) { + // String verify = updateValueParam; + if (heatParameterDefinition.getDefaultValue() != null) { + AssertJUnit.assertTrue( + heatParameterDefinition.getDefaultValue().equals(heatParameterDefinition.getCurrentValue())); + } else { + AssertJUnit.assertNull("verification failed", heatParameterDefinition.getCurrentValue()); + } + } + + // verify change in getResource + resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + deploymentArtifacts.get(heatArtifactDetails.getArtifactName()); + for (HeatParameterDataDefinition heatParameterDefinition : heatParameters) { + // String verify = updateValueParam; + if (heatParameterDefinition.getDefaultValue() != null) { + AssertJUnit.assertTrue( + heatParameterDefinition.getDefaultValue().equals(heatParameterDefinition.getCurrentValue())); + } else { + AssertJUnit.assertNull("verification failed", heatParameterDefinition.getCurrentValue()); + } + } + + // create MAP from received JSON + String section2extract = "heatParameters"; + String createKeyMapBy = "name"; + Map> mapOfActualParameters = jsonToMap(addInformationalArtifactToResource, + section2extract, createKeyMapBy); + + // Prepare map to validate JS + Map paramters = createMapFromYaml(filePayload.get(decodedPayload)); + + // compare MAPs + ResourceValidationUtils.compareElements(mapOfActualParameters, paramters); + + } + + @Test + public void updateValueParamEmpty() throws Exception { + + String updateValueParam = ""; + + Map filePayload = selectFileToUpload(pathToFile, heatWithValidParams); + + // upload HEAT file and save JSON response + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(filePayload.get(encodedPayload)); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails, resourceDetails.getUniqueId()); + + RestResponse resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + // System.out.println(resourceGetResponse.getResponse().toString()); + String atifactUniqueId = ResponseParser + .getValueFromJsonResponse(addInformationalArtifactToResource.getResponse(), "uniqueId"); + + ArtifactReqDetails artifacJavaObject = ResponseParser + .convertArtifactReqDetailsToJavaObject(addInformationalArtifactToResource.getResponse()); + List heatParameters2 = artifacJavaObject.getHeatParameters(); + + for (HeatParameterDefinition heatParameterDefinition : heatParameters2) { + heatParameterDefinition.setCurrentValue(updateValueParam); + } + artifacJavaObject.setHeatParameters(heatParameters2); + artifacJavaObject.setPayloadData(null); + + RestResponse updateInformationalArtifactToResource = ArtifactRestUtils.updateDeploymentArtifactToResource( + artifacJavaObject, sdncDesignerDetails, resourceDetails.getUniqueId()); + + // verify change in update response + + ArtifactDefinition ArtifactDefinitionRespJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(updateInformationalArtifactToResource.getResponse()); + List heatParameters = ArtifactDefinitionRespJavaObject.getHeatParameters(); + for (HeatParameterDataDefinition heatParameterDefinition : heatParameters) { + String verify = updateValueParam; + AssertJUnit.assertTrue("verification failed", verify.equals(heatParameterDefinition.getCurrentValue())); + } + + // verify change in getResource + + resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + deploymentArtifacts.get(heatArtifactDetails.getArtifactName()); + for (HeatParameterDataDefinition heatParameterDefinition : heatParameters) { + String verify = updateValueParam; + AssertJUnit.assertTrue("verification failed", verify.equals(heatParameterDefinition.getCurrentValue())); + } + + // create MAP from received JSON + String section2extract = "heatParameters"; + String createKeyMapBy = "name"; + Map> mapOfActualParameters = jsonToMap(addInformationalArtifactToResource, + section2extract, createKeyMapBy); + + // Prepare map to validate JS + Map paramters = createMapFromYaml(filePayload.get(decodedPayload)); + + // compare MAPs + ResourceValidationUtils.compareElements(mapOfActualParameters, paramters); + + } + + @Test + public void onlyValueParamPermited() throws Exception { + + Map filePayload = selectFileToUpload(pathToFile, heatWithValidParams); + + // upload HEAT file and save JSON response + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatArtifactDetails.setPayload(filePayload.get(encodedPayload)); + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails, resourceDetails.getUniqueId()); + + RestResponse resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + // System.out.println(resourceGetResponse.getResponse().toString()); + String atifactUniqueId = ResponseParser + .getValueFromJsonResponse(addInformationalArtifactToResource.getResponse(), "uniqueId"); + + ArtifactReqDetails artifacJavaObject = ResponseParser + .convertArtifactReqDetailsToJavaObject(addInformationalArtifactToResource.getResponse()); + List heatParameters2 = artifacJavaObject.getHeatParameters(); + + for (HeatParameterDefinition heatParameterDefinition : heatParameters2) { + heatParameterDefinition.setDefaultValue("changed"); + heatParameterDefinition.setName("changed"); + heatParameterDefinition.setDescription("changed"); + heatParameterDefinition.setType("changed"); + heatParameterDefinition.setCurrentValue("changed"); + } + artifacJavaObject.setHeatParameters(heatParameters2); + artifacJavaObject.setPayloadData(null); + + RestResponse updateInformationalArtifactToResource = ArtifactRestUtils.updateDeploymentArtifactToResource( + artifacJavaObject, sdncDesignerDetails, resourceDetails.getUniqueId()); + + resourceGetResponse = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails); + + // create MAP from received JSON + + String section2extract = "heatParameters"; + String createKeyMapBy = "name"; + Map> mapOfActualParameters = jsonToMap(addInformationalArtifactToResource, + section2extract, createKeyMapBy); + + // Prepare map to validate JS + + Map paramters = createMapFromYaml(filePayload.get(decodedPayload)); + + // compare MAPs + + ResourceValidationUtils.compareElements(mapOfActualParameters, paramters); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ValidateHeatArtFieldsTypes.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ValidateHeatArtFieldsTypes.java new file mode 100644 index 0000000000..dfbf035b41 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/artifacts/ValidateHeatArtFieldsTypes.java @@ -0,0 +1,177 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.artifacts; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.HeatParameterDataDefinition; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.HeatParameterDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.RespJsonKeysEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.ArtifactValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +public class ValidateHeatArtFieldsTypes extends ComponentBaseTest { + + protected User sdncDesignerDetails; + protected ResourceReqDetails resourceDetails; + protected ServiceReqDetails serviceDetails; + + private static final String heatExtension = "yaml"; + private static final String yangXmlExtension = "xml"; + private static final String muranoPkgExtension = "zip"; + private final String folderName = "yamlFieldsValidation"; + + private final String uuidString = RespJsonKeysEnum.UUID.getRespJsonKeyName().toString(); + + public ValidateHeatArtFieldsTypes() { + super(name, ValidateHeatArtFieldsTypes.class.getName()); + } + + @Rule + public static TestName name = new TestName(); + + @Test + public void validateHeatArtFiledTypes() throws Exception { + + // get relevant resource and service + + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + resourceDetails = ElementFactory.getDefaultResource(); + + RestResponse response = ResourceRestUtils.createResource(resourceDetails, sdncDesignerDetails); + AssertJUnit.assertTrue("create request returned status:" + response.getErrorCode(), + response.getErrorCode() == 201); + + // add artifact to resource1 + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + List listOfArtifactFromFolder = ArtifactValidationUtils.getListOfArtifactFromFolder(folderName); + for (int i = 0; i < listOfArtifactFromFolder.size(); i++) { + heatArtifactDetails = ArtifactValidationUtils.replaceDefaultArtWithArtFromList(heatArtifactDetails, + heatExtension, folderName, i); + response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails, + resourceDetails.getUniqueId()); + + if (heatArtifactDetails.getArtifactName().contains("bool")) { + if (heatArtifactDetails.getArtifactName().contains("negative")) { + // validate negative response + List variables = Arrays.asList("HEAT", "boolean", "city_name"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_HEAT_PARAMETER_VALUE.name(), + variables, response.getResponse()); + } + if (heatArtifactDetails.getArtifactName().contains("positive")) { + AssertJUnit.assertTrue( + "add HEAT artifact to resource request returned status:" + response.getErrorCode() + + " fileName: " + heatArtifactDetails.getArtifactName(), + response.getErrorCode() == 200); + ArtifactDefinition artifactDefinitionJavaObject = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(response.getResponse()); + List heatParameters = artifactDefinitionJavaObject.getHeatParameters(); + String currentValue = null; + for (HeatParameterDataDefinition heatParameterDefinition : heatParameters) { + if (heatParameterDefinition.getName().equals("city_name")) { + currentValue = heatParameterDefinition.getCurrentValue(); + } + } + if (heatArtifactDetails.getArtifactName().contains("true")) { + AssertJUnit.assertTrue(currentValue.equals("true")); + } + if (heatArtifactDetails.getArtifactName().contains("false")) { + AssertJUnit.assertTrue(currentValue.equals("false")); + } + RestResponse deleteInformationalArtifactFromResource = ArtifactRestUtils + .deleteInformationalArtifactFromResource(resourceDetails.getUniqueId(), heatArtifactDetails, + sdncDesignerDetails); + AssertJUnit.assertTrue( + "delete HEAT artifact from resource request returned status:" + + deleteInformationalArtifactFromResource.getErrorCode(), + deleteInformationalArtifactFromResource.getErrorCode() == 200); + } + + } else if (heatArtifactDetails.getArtifactName().contains("number")) { + if (heatArtifactDetails.getArtifactName().contains("negative")) { + // validate negative response + List variables = Arrays.asList("HEAT", "number", "city_name"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_HEAT_PARAMETER_VALUE.name(), + variables, response.getResponse()); + } + if (heatArtifactDetails.getArtifactName().contains("positive")) { + AssertJUnit.assertTrue( + "add HEAT artifact to resource request returned status:" + response.getErrorCode() + + " fileName: " + heatArtifactDetails.getArtifactName(), + response.getErrorCode() == 200); + } + + } else if (heatArtifactDetails.getArtifactName().contains("string")) { + if (heatArtifactDetails.getArtifactName().contains("negative")) { + // validate negative response + List variables = Arrays.asList("HEAT", "string", "city_name"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_HEAT_PARAMETER_VALUE.name(), + variables, response.getResponse()); + } + if (heatArtifactDetails.getArtifactName().contains("positive")) { + AssertJUnit.assertTrue( + "add HEAT artifact to resource request returned status:" + response.getErrorCode() + + " fileName: " + heatArtifactDetails.getArtifactName(), + response.getErrorCode() == 200); + } + + } + + else if (heatArtifactDetails.getArtifactName().contains("unsupported")) { + + // validate negative response + List variables = Arrays.asList("HEAT", "number123"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_HEAT_PARAMETER_TYPE.name(), + variables, response.getResponse()); + + } + + else { + AssertJUnit.assertTrue( + "add HEAT artifact to resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + } + } + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/attribute/ComponentInstanceAttributeTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/attribute/ComponentInstanceAttributeTest.java new file mode 100644 index 0000000000..b1d04ba88d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/attribute/ComponentInstanceAttributeTest.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.attribute; + +import static org.junit.Assert.assertEquals; +import static org.openecomp.sdc.common.datastructure.FunctionalInterfaces.swallowException; + +import java.io.File; +import java.util.function.Function; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.testng.annotations.Test; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class ComponentInstanceAttributeTest extends ComponentBaseTest { + + public static Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + @Rule + public static TestName name = new TestName(); + + public ComponentInstanceAttributeTest() { + super(name, ComponentInstanceAttributeTest.class.getName()); + } + + @Test + public void testUpdateAttributeOnResourceInstance() { + // Prepare VF with vfc instance with Attributes + String testResourcesPath = config.getResourceConfigDir() + File.separator + "importToscaResourceByCreateUrl"; + final Resource vfcWithAttributes = AtomicOperationUtils + .importResource(testResourcesPath, "CPWithAttributes.yml").left().value(); + swallowException(() -> AtomicOperationUtils.changeComponentState(vfcWithAttributes, UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CHECKIN, false)); + Resource vf = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, false) + .left().value(); + ComponentInstance vfcInstance = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfcWithAttributes, vf).left().value(); + + // util method to get the specific attribute from the vf + Function attributeGetter = resourceVf -> resourceVf + .getComponentInstancesAttributes().values().iterator().next().stream() + .filter(att -> att.getName().equals("private_address")).findAny().get(); + // update attribute on vfc instance + final Resource vfWithInsatncePreUpdate = swallowException( + () -> (Resource) AtomicOperationUtils.getCompoenntObject(vf, UserRoleEnum.DESIGNER)); + ComponentInstanceProperty attributeOfRI = attributeGetter.apply(vfWithInsatncePreUpdate); + final String newAttValue = "NewValue"; + attributeOfRI.setValue(newAttValue); + String body = gson.toJson(attributeOfRI); + String url = String.format(Urls.UPDATE_ATTRIBUTE_ON_RESOURCE_INSTANCE, config.getCatalogBeHost(), + config.getCatalogBePort(), ComponentTypeEnum.findParamByType(ComponentTypeEnum.RESOURCE), + vf.getUniqueId(), vfcInstance.getUniqueId()); + swallowException(() -> BaseRestUtils.sendPost(url, body, UserRoleEnum.DESIGNER.getUserId(), + BaseRestUtils.acceptHeaderData)); + // Retrieve updated vf and verify attribute was updated + final Resource vfWithInsatncePostUpdate = swallowException( + () -> (Resource) AtomicOperationUtils.getCompoenntObject(vf, UserRoleEnum.DESIGNER)); + ComponentInstanceProperty updatedAttribute = attributeGetter.apply(vfWithInsatncePostUpdate); + assertEquals(updatedAttribute.getValue(), newAttValue); + + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CatalogDataApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CatalogDataApiTest.java new file mode 100644 index 0000000000..9938266602 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CatalogDataApiTest.java @@ -0,0 +1,236 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.category; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.lf5.util.ResourceUtils; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.CatalogRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class CatalogDataApiTest extends ComponentBaseTest { + + protected Config config = Config.instance(); + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json"; + + @Rule + public static TestName name = new TestName(); + protected User user; + protected RestResponse res1; + protected RestResponse res2; + protected RestResponse svc1; + protected ResourceReqDetails resourceDetails1; + protected ResourceReqDetails resourceDetails2; + protected ServiceReqDetails svcDetails1; + + public CatalogDataApiTest() { + super(name, CatalogDataApiTest.class.getName()); + } + + @BeforeMethod + public void setUp() throws Exception { + user = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + resourceDetails1 = buildResourceDetails(user, "TestResource1"); + resourceDetails2 = buildResourceDetails(user, "TestResource2"); + svcDetails1 = buildServiceDetails("TestService1"); + + res1 = createResource(user, resourceDetails1); + AssertJUnit.assertEquals("create resorce failed", 201, res1.getErrorCode().intValue()); + resourceDetails1.setUniqueId(ResponseParser.getUniqueIdFromResponse(res1)); + resourceDetails2.setVersion(ResponseParser.getVersionFromResponse(res1)); + + res2 = createResource(user, resourceDetails2); + AssertJUnit.assertEquals("create resorce failed", 201, res2.getErrorCode().intValue()); + resourceDetails2.setUniqueId(ResponseParser.getUniqueIdFromResponse(res2)); + resourceDetails2.setVersion(ResponseParser.getVersionFromResponse(res2)); + + svc1 = createService(user, svcDetails1); + AssertJUnit.assertEquals("create resorce failed", 201, svc1.getErrorCode().intValue()); + svcDetails1.setUniqueId(ResponseParser.convertServiceResponseToJavaObject(svc1.getResponse()).getUniqueId()); + svcDetails1.setVersion(ResponseParser.convertServiceResponseToJavaObject(svc1.getResponse()).getVersion()); + } + + @AfterMethod + public void tearDown() throws Exception { + deleteResource(resourceDetails1.getUniqueId(), user.getUserId()); + deleteResource(resourceDetails2.getUniqueId(), user.getUserId()); + deleteService(svcDetails1.getUniqueId(), user); + } + + // Keep 1 + @Test + public void getCatalogData() throws Exception { + + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetails1, user, "0.1", + LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertEquals("check in operation failed", 200, checkInResponse.getErrorCode().intValue()); + + RestResponse res = CatalogRestUtils.getCatalog(user.getUserId()); + String json = res.getResponse(); + JSONObject jsonResp = (JSONObject) JSONValue.parse(json); + JSONArray resources = (JSONArray) jsonResp.get("resources"); + JSONArray services = (JSONArray) jsonResp.get("services"); + + // Verify all the expected resources received. + AssertJUnit.assertTrue("check resource1 is in response", + isComponentInArray(resourceDetails1.getUniqueId(), resources)); + AssertJUnit.assertTrue("check resource2 is in response", + isComponentInArray(resourceDetails2.getUniqueId(), resources)); + AssertJUnit.assertTrue("check service1 is in response", + isComponentInArray(svcDetails1.getUniqueId(), services)); + + } + + protected void deleteResource(String resourceUniqueId, String httpCspUserId) throws Exception { + RestResponse deleteResourceResponse = ResourceRestUtils.deleteResource(resourceUniqueId, httpCspUserId); + + } + + protected RestResponse createResource(User user, ResourceReqDetails resourceDetails) throws Exception { + deleteResource(resourceDetails.getName(), user.getUserId()); + return ResourceRestUtils.createResource(resourceDetails, user); + } + + protected ResourceReqDetails buildResourceDetails(User user, String resourceName) { + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add("tosca.nodes.Root"); + String vendorName = "Oracle"; + String vendorRelease = "1.0"; + String contactId = user.getUserId(); + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, null, + derivedFrom, vendorName, vendorRelease, contactId, icon); + resourceDetails.addCategoryChain(ResourceCategoryEnum.GENERIC_DATABASE.getCategory(), + ResourceCategoryEnum.GENERIC_DATABASE.getSubCategory()); + return resourceDetails; + } + + protected boolean isComponentInArray(String id, JSONArray component) { + for (int i = 0; i < component.size(); i++) { + JSONObject jobject = (JSONObject) component.get(i); + if (jobject.get("uniqueId").toString().equals(id.toLowerCase())) { + return true; + } + } + return false; + } + + protected RestResponse createService(User user, ServiceReqDetails svcDetails) throws Exception { + + Config config = Utils.getConfig(); + + Map headersMap = getHeadersMap(user); + + Gson gson = new Gson(); + String body = gson.toJson(svcDetails); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.CREATE_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort()); + RestResponse res = http.httpSendPost(url, body, headersMap); + // System.out.println("Create service was finished with response: + // "+res.getErrorCode()); + return res; + } + + protected Map getHeadersMap(User user) { + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put("USER_ID", user.getUserId()); + return headersMap; + } + + protected ServiceReqDetails buildServiceDetails(String serviceName) { + String description = "description"; + ArrayList serviceTags = new ArrayList(); + serviceTags.add("tag1"); + serviceTags.add(serviceName); + String category = ServiceCategoriesEnum.MOBILITY.getValue(); + String vendorName = "Oracle"; + String vendorRelease = "0.1"; + String contactId = "al1976"; + String icon = "myIcon"; + + ServiceReqDetails svcdetails = new ServiceReqDetails(serviceName, category, serviceTags, description, + contactId, icon); + return svcdetails; + } + + public RestResponse deleteService(String serviceId, User user) throws Exception { + HttpRequest httpRequest = new HttpRequest(); + String url = String.format(Urls.DELETE_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), + serviceId); + + Map headersMap = getHeadersMap(user); + RestResponse res = httpRequest.httpSendDelete(url, headersMap); + // System.out.println("Delete service was finished with response: + // "+res.getErrorCode()); + return res; + } + + public class NewObject { + private String _name; + + public String getName() { + return _name; + } + + public void setName(String name) { + this._name = name; + } + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CategoriesBaseTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CategoriesBaseTest.java new file mode 100644 index 0000000000..d68f3f5582 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CategoriesBaseTest.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.category; + +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; + +public abstract class CategoriesBaseTest extends ComponentBaseTest { + + public CategoriesBaseTest(TestName testName, String className) { + super(testName, className); + } + + protected static final String AUDIT_SERVICE_TYPE = "Service"; + protected static final String AUDIT_RESOURCE_TYPE = "Resource"; + protected static final String AUDIT_PRODUCT_TYPE = "Product"; + protected static final String GET_CATEGORY_HIERARCHY = "GetCategoryHierarchy"; + protected static User sdncAdminUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + protected static User sdncAdminUserDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + protected static User sdncDesignerUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + protected static User sdncTesterUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + protected static User sdncGovernorUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR); + protected static User sdncOpsUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.OPS); + protected static User sdncProductManagerUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1); + protected static User sdncProductStrategistUserDetails = ElementFactory + .getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1); + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CategoriesTests.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CategoriesTests.java new file mode 100644 index 0000000000..3b85c052a1 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/CategoriesTests.java @@ -0,0 +1,2303 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.category; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.PRODUCT_COMPONENT_TYPE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.RESOURCE_COMPONENT_TYPE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.SERVICE_COMPONENT_TYPE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_ALREADY_EXISTS; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_CREATED; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_INVALID_CONTENT; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_MISSING_INFORMATION; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.text.WordUtils; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.FileBody; +import org.json.JSONArray; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedCategoryAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.CategoryValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.SkipException; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class CategoriesTests extends CategoriesBaseTest { + + private static final String GET_CATEGORY_HIERARCHY = "GetCategoryHierarchy"; + protected static final String ADD_CATEGORY = "AddCategory"; + protected static final String DELETE_CATEGORY = "DeleteCategory"; + + public CategoriesTests() { + super(name, CategoriesTests.class.getName()); + } + + @Rule + public static TestName name = new TestName(); + private CategoryDefinition categoryDefinition; + private List categoryList; + private List subCategoryList; + private Map> subCategoriesToDeleteMap; + + @BeforeMethod + public void init() throws Exception { + subCategoriesToDeleteMap = new HashMap>(); + DbUtils.deleteFromEsDbByPattern("_all"); + + categoryDefinition = new CategoryDefinition(); + categoryDefinition.setName("Abcd"); + categoryList = defineCategories(); + subCategoryList = defineSubCategories(categoryList.size()); + } + + // pass + @Test + public void createServiceCategorySuccessFlow() throws Exception { + // Add New category + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + // get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); // also + // set + // catalog + // uniqeId + + } + + // pass + @Test + public void createResourceCategorySuccessFlow() throws Exception { + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get Category + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + // pass + @Test + public void createProductCategorySuccessFlow() throws Exception { + // Add Category by Product-strategist + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, + sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + + // Get Category + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncProductStrategistUserDetails, + STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void CategoryNameValidation_FirstWordStartWithAlphaNumeric_01() throws Exception { // category + // for + // service + categoryDefinition.setName("Category14AadE &&&---+++.'''###=:@@@____"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Category14AadE &-+.'#=:@_"); + categoryDefinition.setNormalizedName("category14aade &-+.'#=:@_"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_FirstWordStartWithAlphaNumeric_02() throws Exception { // category + // for + // resource + categoryDefinition.setName("Category14AadE &&&---+++.'''###=:@@@____"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Category14AadE &-+.'#=:@_"); + categoryDefinition.setNormalizedName("category14aade &-+.'#=:@_"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void categoryNameValidation_FirstWordStartWithAlphaNumeric_03() throws Exception { // category + // for + // resource + categoryDefinition.setName("Category14AadE &&&---+++.'''###=:@@@____"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, + sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Category14AadE &-+.'#=:@_"); + categoryDefinition.setNormalizedName("category14aade &-+.'#=:@_"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncProductStrategistUserDetails, + STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + // pass + @Test + public void createServiceCategoryByNonAdminUser() throws Exception { + // Add New category + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, + sdncProductStrategistUserDetails, SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_RESTRICTED_OPERATION, + createCategotyRest.getErrorCode().intValue()); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDefinition, sdncProductStrategistUserDetails, + ActionStatus.RESTRICTED_OPERATION, STATUS_CODE_RESTRICTED_OPERATION, AUDIT_SERVICE_TYPE); + } + + // pass + @Test + public void createResourceCategoryByNonAdminUser() throws Exception { + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, + sdncProductStrategistUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_RESTRICTED_OPERATION, + createCategotyRest.getErrorCode().intValue()); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDefinition, sdncProductStrategistUserDetails, + ActionStatus.RESTRICTED_OPERATION, STATUS_CODE_RESTRICTED_OPERATION, AUDIT_RESOURCE_TYPE); + } + + // pass + @Test + public void createProductCategoryByNonProductStrategistUser() throws Exception { + // Add New product category not by Product-Strategist + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_RESTRICTED_OPERATION, + createCategotyRest.getErrorCode().intValue()); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + ActionStatus.RESTRICTED_OPERATION, STATUS_CODE_RESTRICTED_OPERATION, AUDIT_PRODUCT_TYPE); + + } + + // pass + @Test + public void addCategoryByNonExistingUser() throws Exception { + User sdncAdminUserDetailsNonExisting = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncAdminUserDetailsNonExisting.setUserId("bt555h"); + // Add New category + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, + sdncAdminUserDetailsNonExisting, SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_RESTRICTED_OPERATION, + createCategotyRest.getErrorCode().intValue()); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(ADD_CATEGORY); + expectedCatrgoryAuditJavaObject.setModifier("(" + sdncAdminUserDetailsNonExisting.getUserId() + ")"); + expectedCatrgoryAuditJavaObject.setCategoryName(categoryDefinition.getName()); + expectedCatrgoryAuditJavaObject.setSubCategoryName(""); + expectedCatrgoryAuditJavaObject.setGroupingName(""); + expectedCatrgoryAuditJavaObject.setResourceType(AUDIT_SERVICE_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_RESTRICTED_OPERATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateCategoryAudit(expectedCatrgoryAuditJavaObject, ADD_CATEGORY); + } + + @Test + public void addServiceCategoryAllowedcharacters_01() throws Exception { + categoryDefinition.setName("1234AbcdE&"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde&"); // normalization + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_02() throws Exception { + categoryDefinition.setName("1234AbcdE-"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde-"); // normalization + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_03() throws Exception { + categoryDefinition.setName("1234AbcdE+"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde+"); // normalization + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_04() throws Exception { + categoryDefinition.setName("1234AbcdE."); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde."); // normalization + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_05() throws Exception { + categoryDefinition.setName("1234AbcdE'"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde'"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_06() throws Exception { + categoryDefinition.setName("1234AbcdE="); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde="); // normalization + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_07() throws Exception { + categoryDefinition.setName("1234AbcdE:"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde:"); // normalization + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_08() throws Exception { + categoryDefinition.setName("1234AbcdE@"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde@"); // normalization + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_09() throws Exception { + categoryDefinition.setName("1234AbcdE_"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde_"); // normalization + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_10() throws Exception { + categoryDefinition.setName("1234AbcdE#"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde#"); // normalization + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_11() throws Exception { + categoryDefinition.setName("1234AbcdE d"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde d"); // normalization + categoryDefinition.setName("1234AbcdE D"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void addServiceCategoryAllowedcharacters_12() throws Exception { + categoryDefinition.setName("1234AbcdE &_=+.-'#:@ d"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("1234abcde &_=+.-'#:@ d"); // normalization + categoryDefinition.setName("1234AbcdE &_=+.-'#:@ D"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveSpaceFromBeginning() throws Exception { + categoryDefinition.setName(" Category01"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("category01"); // normalization + categoryDefinition.setName("Category01"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveSpaceFromEnd() throws Exception { + categoryDefinition.setName("Category01 "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("category01"); // normalization + categoryDefinition.setName("Category01"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtraSpace() throws Exception { + categoryDefinition.setName("Category 02"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("category 02"); // normalization + categoryDefinition.setName("Category 02"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtraAmpersand() throws Exception { + categoryDefinition.setName("Category&& &02"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("category& &02"); // normalization + categoryDefinition.setName("Category& &02"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtraDash() throws Exception { + categoryDefinition.setName("CategorY-- --02"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("CategorY- -02"); + categoryDefinition.setNormalizedName("category- -02"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtraPlus() throws Exception { + categoryDefinition.setName("CateGory++++ +02"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("CateGory+ +02"); + categoryDefinition.setNormalizedName("category+ +02"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtraPeriod() throws Exception { + categoryDefinition.setName("Category.... .02"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Category. .02"); + categoryDefinition.setNormalizedName("category. .02"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtraApostrophe() throws Exception { + categoryDefinition.setName("CaTegory''' '02"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("CaTegory' '02"); + categoryDefinition.setNormalizedName("category' '02"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtraHashtag() throws Exception { + categoryDefinition.setName("Category### #02"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Category# #02"); + categoryDefinition.setNormalizedName("category# #02"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtrEequal() throws Exception { + categoryDefinition.setName("Category=== =02"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Category= =02"); + categoryDefinition.setNormalizedName("category= =02"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtrColon() throws Exception { + categoryDefinition.setName("Category::: :02"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Category: :02"); + categoryDefinition.setNormalizedName("category: :02"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtrAt() throws Exception { + categoryDefinition.setName("Category@@@ @a2"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Category@ @a2"); + categoryDefinition.setNormalizedName("category@ @a2"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_RemoveExtraUnderscore() throws Exception { + categoryDefinition.setName("Category___ _22"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Category_ _22"); + categoryDefinition.setNormalizedName("category_ _22"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_FirstWordStartWithNumber() throws Exception { + categoryDefinition.setName("1Category one"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("1Category One"); + categoryDefinition.setNormalizedName("1category one"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_FirstWordStartWithNonAlphaNumeric() throws Exception { // The + // first + // word + // must + // start + // with + // an + // alpha-numeric + // character + // [a-Z + // A..Z, + // 0..9] + char invalidChars[] = { '&', '-', '+', '.', '\'', '#', '=', ':', '@', '_' }; + for (int i = 0; i < invalidChars.length; i++) { + DbUtils.deleteFromEsDbByPattern("_all"); + categoryDefinition.setName(invalidChars[i] + "AbcD123"); + categoryDefinition.setNormalizedName((invalidChars[i] + "AbcD123").toLowerCase()); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, + sdncAdminUserDetails1, SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_INVALID_CONTENT, + createCategotyRest.getErrorCode().intValue()); + + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails1, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, STATUS_CODE_INVALID_CONTENT, AUDIT_SERVICE_TYPE, + "Service", "category"); + + } + } + + @Test + public void addServiceCategoryAlreadyExist_uniqueness() throws Exception { // Verify + // category + // name + // duplication + // ("uniqueness") + // as + // non-case-sensitive, + // so + // we + // don’t + // create + // duplicate + // names + // with + // upper/lower + // case + // inconsistency. + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); // also + // set + // catalog + // uniqeId + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + // Create same category name again + DbUtils.deleteFromEsDbByPattern("_all"); + CategoryDefinition categoryDataDefinition2 = new CategoryDefinition(); + categoryDataDefinition2.setName(categoryDefinition.getName()); + RestResponse addDuplicateCategoryRest = CategoryRestUtils.createCategory(categoryDataDefinition2, + sdncAdminUserDetails, SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_ALREADY_EXISTS, + addDuplicateCategoryRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDataDefinition2, sdncAdminUserDetails, + ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS, STATUS_CODE_ALREADY_EXISTS, AUDIT_SERVICE_TYPE, + "Service", categoryDefinition.getName()); + // Get Category and verify that category was created is not deleted + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + + } + + @Test + public void categoryNameValidation_ReplaceAndWithAmpersand_01() throws Exception { + categoryDefinition.setName("At and T"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("At & T"); + categoryDefinition.setNormalizedName("at & t"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_ReplaceAndWithAmpersand_02() throws Exception { + categoryDefinition.setName("At and t"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("At & T"); + categoryDefinition.setNormalizedName("at & t"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_ReplaceAndWithAmpersand_03() throws Exception { + categoryDefinition.setName("Atand T"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("atand t"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_ReplaceAndWithAmpersand_04() throws Exception { + categoryDefinition.setName("At andT"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("at andt"); + categoryDefinition.setName("At AndT"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_ReplaceAndWithAmpersand_05() throws Exception { + categoryDefinition.setName(" and AttT"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("and attt"); + categoryDefinition.setName("And AttT"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidation_ReplaceAndWithAmpersand_06() throws Exception { + categoryDefinition.setName("AttT and "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("attt and"); + categoryDefinition.setName("AttT And"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + // Bug + @Test + public void categoryNameValidation_ReplaceAndWithAmpersand_07() throws Exception { + categoryDefinition.setName(" and a"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("and a"); + categoryDefinition.setName("And a"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationMaxLength() throws Exception { + categoryDefinition.setName("AsdfghjQ234567890@#.&:+-_"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("asdfghjq234567890@#.&:+-_"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + + } + + @Test + public void categoryNameValidationMaxLengthAfterNormalization() throws Exception { + categoryDefinition.setName(" A jQ234 @@@___ +++ At and T and and "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("A JQ234 @_ + At & T & And"); + categoryDefinition.setNormalizedName("a jq234 @_ + at & t & and"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + + } + + @Test + public void categoryNameValidationExceedMaxLengthAfterNormalization() throws Exception { + categoryDefinition.setName(" AbdfghBCVa jQ234 @@___ +++ At and T "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_INVALID_CONTENT, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("abdfghbcva jq234 @_ + at&t"); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, STATUS_CODE_INVALID_CONTENT, AUDIT_SERVICE_TYPE, + "Service", "category"); + } + + @Test + public void categoryNameValidationMinLengthAfterNormalization() throws Exception { // MinLengthAfterNormalization + // = + // 4 + // characters + categoryDefinition.setName(" At and T "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("At & T"); + categoryDefinition.setNormalizedName("at & t"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationLessThanMinLengthAfterNormalization() throws Exception { + categoryDefinition.setName(" A&&&&&&&&&&&&&&&&&T "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_INVALID_CONTENT, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName("a&t"); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, STATUS_CODE_INVALID_CONTENT, AUDIT_SERVICE_TYPE, + "Service", "category"); + } + + @Test + public void categoryNameValidationIsNull() throws Exception { + categoryDefinition.setName(null); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_INVALID_CONTENT, + createCategotyRest.getErrorCode().intValue()); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, STATUS_CODE_INVALID_CONTENT, AUDIT_SERVICE_TYPE, + "Service", "category"); + } + + @Test + public void categoryNameValidationIsEmpty() throws Exception { + categoryDefinition.setName(""); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_INVALID_CONTENT, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName(""); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, STATUS_CODE_INVALID_CONTENT, AUDIT_SERVICE_TYPE, + "Service", "category"); + } + + @Test + public void categoryNameValidationInvalidCharacters() throws Exception { + char invalidChars[] = { '~', '!', '$', '%', '^', '*', '(', ')', '"', '{', '}', '[', ']', '?', '>', '<', '/', + '|', '\\', ',' }; + for (int i = 0; i < invalidChars.length; i++) { + DbUtils.deleteFromEsDbByPattern("_all"); + // DbUtils.cleanAllAudits(); + categoryDefinition.setName("AbcD123" + invalidChars[i]); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_INVALID_CONTENT, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setNormalizedName(""); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditFailure(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, STATUS_CODE_INVALID_CONTENT, AUDIT_SERVICE_TYPE, + "Service", "category"); + } + } + + @Test + public void categoryNameValidationSameNameDifferentResourceType() throws Exception { // same + // Catalog + // Name + // for + // service/resource/product + // is + // allowed + String name = ("Abcd"); + CategoryDefinition categoryDataDefinition1 = new CategoryDefinition(); + CategoryDefinition categoryDataDefinition2 = new CategoryDefinition(); + CategoryDefinition categoryDataDefinition3 = new CategoryDefinition(); + categoryDataDefinition1.setName(name); + categoryDataDefinition2.setName(name); + categoryDataDefinition3.setName(name); + // CREATE CATEGORY FOR SERVICE + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDataDefinition1, + sdncAdminUserDetails, SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDataDefinition1.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDataDefinition1); + // get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDataDefinition1); // also + // set + // catalog + // uniqeId + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDataDefinition1, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + // CREATE CATEGORY FOR RESOURCE_COMPONENT_TYPE + DbUtils.deleteFromEsDbByPattern("_all"); + createCategotyRest = CategoryRestUtils.createCategory(categoryDataDefinition2, sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDataDefinition2.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDataDefinition2); + // Get Category + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDataDefinition2); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDataDefinition2, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + // CREATE CATEGORY FOR PRODUCT + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse addCategotyRest = CategoryRestUtils.createCategory(categoryDataDefinition3, + sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + addCategotyRest.getErrorCode().intValue()); + categoryDataDefinition3.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateCategoryResponse(addCategotyRest, categoryDataDefinition3); + + // Get Category + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDataDefinition3); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncProductStrategistUserDetails, + STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void categoryNameValidationFirstLetterOfKeyWordsCapitalized() throws Exception { // First + // letter + // of + // key + // words + // are + // capitalized + categoryDefinition.setName("beNNy shaY michEl"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("BeNNy ShaY MichEl"); + categoryDefinition.setNormalizedName("benny shay michel"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_01() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" bank OF america "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Bank of America"); + categoryDefinition.setNormalizedName("bank of america"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_02() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName("THE america bank "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("THE America Bank"); + categoryDefinition.setNormalizedName("the america bank"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_03() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" A bank OF america "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("A Bank of America"); + categoryDefinition.setNormalizedName("a bank of america"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_04() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" bank america is A big ban "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Bank America Is a Big Ban"); + categoryDefinition.setNormalizedName("bank america is a big ban"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_05() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" aN apple comPany inC "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("AN Apple ComPany InC"); + categoryDefinition.setNormalizedName("an apple company inc"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_06() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" eat AN apple ANAN"); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Eat an Apple ANAN"); + categoryDefinition.setNormalizedName("eat an apple anan"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_07() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" united states OF americA "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("United States of AmericA"); + categoryDefinition.setNormalizedName("united states of america"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + // need to re-check + @Test + public void categoryNameValidationConjunctions_08() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" oF united states OF amer "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("OF United States of Amer"); + categoryDefinition.setNormalizedName("of united states of amer"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_09() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" to Apple TO at&T TOO "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("To Apple to At&T TOO"); + categoryDefinition.setNormalizedName("to apple to at&t too"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_10() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" eat apple AS you liiikeas "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Eat Apple as You Liiikeas"); + categoryDefinition.setNormalizedName("eat apple as you liiikeas"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_11() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" as you may want "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("As You May Want"); + categoryDefinition.setNormalizedName("as you may want"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void categoryNameValidationConjunctions_12() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" the bank OF america "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("The Bank of America"); + categoryDefinition.setNormalizedName("the bank of america"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + // need to recheck + @Test + public void categoryNameValidationConjunctions_13() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" To tel-toto "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("To Tel-toto"); + categoryDefinition.setNormalizedName("to tel-toto"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + // recheck + @Test + public void categoryNameValidationConjunctions_14() throws Exception { // Normalize + // the + // category + // name + // conjunctions + // ('of', + // 'to', + // 'for', + // 'as', + // 'a', + // 'an' + // , + // 'the') + // are + // lower + // case. + categoryDefinition.setName(" tel-aviv To la "); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_CREATED, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Tel-aviv to La"); + categoryDefinition.setNormalizedName("tel-aviv to la"); + CategoryValidationUtils.validateCreateCategoryResponse(createCategotyRest, categoryDefinition); + // Get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + AuditValidationUtils.categoryAuditSuccess(ADD_CATEGORY, categoryDefinition, sdncAdminUserDetails, + STATUS_CODE_CREATED, AUDIT_SERVICE_TYPE); + } + + @Test + public void createServiceCategoryHttpCspUserIdIsEmpty() throws Exception { + User sdncAdminUserDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncAdminUserDetails1.setUserId(""); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_INFORMATION, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Abcd"); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(ADD_CATEGORY); + expectedCatrgoryAuditJavaObject.setModifier(""); + expectedCatrgoryAuditJavaObject.setCategoryName(categoryDefinition.getName()); + expectedCatrgoryAuditJavaObject.setSubCategoryName(""); + expectedCatrgoryAuditJavaObject.setGroupingName(""); + expectedCatrgoryAuditJavaObject.setResourceType(AUDIT_SERVICE_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_MISSING_INFORMATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateCategoryAudit(expectedCatrgoryAuditJavaObject, ADD_CATEGORY); + } + + @Test + public void createServiceCategorHttpCspUserIdIsNull() throws Exception { + User sdncAdminUserDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncAdminUserDetails1.setUserId(null); + RestResponse createCategotyRest = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails1, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_INFORMATION, + createCategotyRest.getErrorCode().intValue()); + categoryDefinition.setName("Abcd"); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(ADD_CATEGORY); + expectedCatrgoryAuditJavaObject.setModifier(""); + expectedCatrgoryAuditJavaObject.setCategoryName(categoryDefinition.getName()); + expectedCatrgoryAuditJavaObject.setSubCategoryName(""); + expectedCatrgoryAuditJavaObject.setGroupingName(""); + expectedCatrgoryAuditJavaObject.setResourceType(AUDIT_SERVICE_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_MISSING_INFORMATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateCategoryAudit(expectedCatrgoryAuditJavaObject, ADD_CATEGORY); + } + + @Test + public void createSrvcCategoryHttpCspUserIdHeaderIsMissing() throws Exception { + RestResponse createConsumerRest = CategoryRestUtils + .createServiceCategoryHttpCspAtuUidIsMissing(categoryDefinition, sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_INFORMATION, + createConsumerRest.getErrorCode().intValue()); + categoryDefinition.setName("Abcd"); + // get service category and validate that category was not added + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyCategoryNotExistsInGetResponse(getAllCategoriesRest, categoryDefinition); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(ADD_CATEGORY); + expectedCatrgoryAuditJavaObject.setModifier(""); + expectedCatrgoryAuditJavaObject.setCategoryName(categoryDefinition.getName()); + expectedCatrgoryAuditJavaObject.setSubCategoryName(""); + expectedCatrgoryAuditJavaObject.setGroupingName(""); + expectedCatrgoryAuditJavaObject.setResourceType(AUDIT_SERVICE_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_MISSING_INFORMATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateCategoryAudit(expectedCatrgoryAuditJavaObject, ADD_CATEGORY); + } + + @Test + public void getServiceCategoryHierarchySuccessFlow() throws Exception { + + int numOfCategories = 3; + List categories = new ArrayList(); + RestResponse restResponse; + CategoryDefinition category; + String categoryName = categoryDefinition.getName(); + for (int i = 0; i < numOfCategories; i++) { + categoryDefinition.setName(categoryName + i); + restResponse = CategoryRestUtils.createCategory(categoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + category = ResponseParser.parseToObject(restResponse.getResponse(), CategoryDefinition.class); + categories.add(category); + } + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + + AuditValidationUtils.GetCategoryHierarchyAuditSuccess(GET_CATEGORY_HIERARCHY, AUDIT_SERVICE_TYPE, + sdncAdminUserDetails, STATUS_CODE_SUCCESS); + for (CategoryDefinition categoryCurr : categories) { + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryCurr); + } + } + + ///////////////////////////////// US570520 ///////////////////////////////// + private List defineCategories() throws Exception { + String firstCategory = "FirstCategory"; + String secondCategory = "secondCategory"; + String thirdCategory = "ThirdCategory"; + String forthCategory = "forthCategory"; + CategoryDefinition category1 = new CategoryDefinition(categoryDefinition); + category1.setName(firstCategory); + CategoryDefinition category2 = new CategoryDefinition(categoryDefinition); + category2.setName(secondCategory); + CategoryDefinition category3 = new CategoryDefinition(categoryDefinition); + category3.setName(thirdCategory); + CategoryDefinition category4 = new CategoryDefinition(categoryDefinition); + category4.setName(forthCategory); + ArrayList categoryList = new ArrayList(); + categoryList.add(category1); + categoryList.add(category2); + categoryList.add(category3); + categoryList.add(category4); + return categoryList; + } + + @Test + public void getAllResourceCategoriesHirarchy() throws Exception { + createAndValidateCategoriesExist(RESOURCE_COMPONENT_TYPE, categoryList); + + for (int i = 0; i < categoryList.size(); i++) { + List subCategorieUniqueIdList = new ArrayList(); + for (int j = 0; j < subCategoryList.size(); j++) { + RestResponse createSubCategory = CategoryRestUtils.createSubCategory(subCategoryList.get(j), + categoryList.get(i), sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + if (createSubCategory.getErrorCode().intValue() == STATUS_CODE_CREATED) { + String subCategoryUniqeId = ResponseParser.getUniqueIdFromResponse(createSubCategory); + subCategorieUniqueIdList.add(subCategoryUniqeId); + subCategoriesToDeleteMap.put(categoryList.get(i).getUniqueId(), subCategorieUniqueIdList); + } + } + } + + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + + for (int i = 0; i < categoryList.size(); i++) { + for (int j = 0; j < subCategoryList.size(); j++) { + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + categoryList.get(i).getUniqueId(), subCategoryList.get(j)); + } + } + + checkAuditSuccess(RESOURCE_COMPONENT_TYPE); + } + + private List defineSubCategories(int catListSize) { + List subCatList = new ArrayList(); + for (int j = 1; j <= catListSize; j++) { + SubCategoryDefinition subCategory = new SubCategoryDefinition(); + subCategory.setName("SubCategory" + String.valueOf(j)); + subCatList.add(subCategory); + } + return subCatList; + } + + private void createAndValidateCategoriesExist(String comp, List categoryList) throws Exception { + createCategories(comp, categoryList); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, comp); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + verifyCategoriesExist(categoryList, getAllCategoriesRest); + } + + private void verifyCategoriesExist(List categoryList, RestResponse getAllCategoriesRest) { + for (int i = 0; i < categoryList.size(); i++) { + categoryList.get(i).setName(WordUtils.capitalize(categoryList.get(i).getName())); + CategoryValidationUtils.verifyCategoryExistInGetResponse(getAllCategoriesRest, categoryList.get(i)); + } + } + + private void createCategories(String comp, List categoryList) throws Exception { + for (int i = 0; i < categoryList.size(); i++) { + CategoryRestUtils.createCategory(categoryList.get(i), sdncAdminUserDetails, comp); + } + } + + @Test + public void getAllServiceCategoriesHirarchy() throws Exception { + // deleteCategories(categoryList, SERVICE_COMPONENT_TYPE); + createAndValidateCategoriesExist(SERVICE_COMPONENT_TYPE, categoryList); + checkAuditSuccess(SERVICE_COMPONENT_TYPE); + // deleteCategories(categoryList, SERVICE_COMPONENT_TYPE); + } + + @Test + public void getAllResourceCategories_noAttUserHeader() throws Exception { + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(new User(), RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", 403, getAllCategoriesRest.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_INFORMATION.name(), new ArrayList(), + getAllCategoriesRest.getResponse()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(GET_CATEGORY_HIERARCHY); + expectedCatrgoryAuditJavaObject.setModifierName(""); + expectedCatrgoryAuditJavaObject.setModifierUid(""); + expectedCatrgoryAuditJavaObject.setDetails(RESOURCE_COMPONENT_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_MISSING_INFORMATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateGetCategoryHirarchy(expectedCatrgoryAuditJavaObject, GET_CATEGORY_HIERARCHY); + } + + @Test + public void getAllResourceCategories_userNotProvisioned() throws Exception { + User notProvisionedUser = new User(); + notProvisionedUser.setUserId("aa0001"); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(notProvisionedUser, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", 409, getAllCategoriesRest.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + getAllCategoriesRest.getResponse()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(GET_CATEGORY_HIERARCHY); + expectedCatrgoryAuditJavaObject.setModifierName(""); + expectedCatrgoryAuditJavaObject.setModifierUid(notProvisionedUser.getUserId()); + expectedCatrgoryAuditJavaObject.setDetails(RESOURCE_COMPONENT_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_RESTRICTED_OPERATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateGetCategoryHirarchy(expectedCatrgoryAuditJavaObject, GET_CATEGORY_HIERARCHY); + } + + @Test + public void getAllResourceCategories_unsupportedComponent() throws Exception { + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, "comp"); + assertEquals("Check response code after get all categories hirarchy", 400, + getAllCategoriesRest.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.UNSUPPORTED_ERROR.name(), + new ArrayList(Arrays.asList("component type")), getAllCategoriesRest.getResponse()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.UNSUPPORTED_ERROR.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(GET_CATEGORY_HIERARCHY); + expectedCatrgoryAuditJavaObject.setModifierUid(sdncAdminUserDetails.getUserId()); + expectedCatrgoryAuditJavaObject.setModifierName(sdncAdminUserDetails.getFullName()); + expectedCatrgoryAuditJavaObject.setDetails("comp"); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_INVALID_CONTENT)); + expectedCatrgoryAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, + new ArrayList(Arrays.asList("component type")))); + AuditValidationUtils.validateGetCategoryHirarchy(expectedCatrgoryAuditJavaObject, GET_CATEGORY_HIERARCHY); + } + + @Test(enabled = false) + public void getAllResourceCategories_emptyList() throws Exception { + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + JSONArray jArr = new JSONArray(getAllCategoriesRest.getResponse()); + assertTrue(jArr.length() == 0); + + checkAuditSuccess(RESOURCE_COMPONENT_TYPE); + } + + private void checkAuditSuccess(String componentType) throws Exception { + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(GET_CATEGORY_HIERARCHY); + expectedCatrgoryAuditJavaObject.setModifierName(sdncAdminUserDetails.getFullName()); + expectedCatrgoryAuditJavaObject.setModifierUid(sdncAdminUserDetails.getUserId()); + expectedCatrgoryAuditJavaObject.setDetails(componentType); + expectedCatrgoryAuditJavaObject.setStatus("200"); + expectedCatrgoryAuditJavaObject.setDesc("OK"); + AuditValidationUtils.validateGetCategoryHirarchy(expectedCatrgoryAuditJavaObject, GET_CATEGORY_HIERARCHY); + } + + @Test(enabled = false) + public void getAllServiceCategories_emptyList() throws Exception { + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + JSONArray jArr = new JSONArray(getAllCategoriesRest.getResponse()); + assertTrue(jArr.length() == 0); + + checkAuditSuccess(SERVICE_COMPONENT_TYPE); + } + + @Test(enabled = false) + public void getAllProductCategories_emptyList() throws Exception { + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get Category", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + JSONArray jArr = new JSONArray(getAllCategoriesRest.getResponse()); + assertTrue(jArr.length() == 0); + + checkAuditSuccess(PRODUCT_COMPONENT_TYPE); + } + + // @Test + // public void getAllResourceCategories_generalError() throws Exception + // { + // User user = new User(); + // RestResponse getAllCategoriesRest = + // CategoryRestUtils.getAllCategories(user, SERVICE_COMPONENT_TYPE); + // assertEquals("Check response code after get Category", 500, + // getAllCategoriesRest.getErrorCode().intValue()); + // Utils.checkBodyResponseOnError(ActionStatus.GENERAL_ERROR.name(), new + // ArrayList(), getAllCategoriesRest.getResponse()); + // } + + ////////////////////////////////////////////////////////////////////////////// + + @Test + public void importCategories() throws Exception { + + String importResourceDir = config.getImportTypesConfigDir() + File.separator + "categoryTypesTest.zip"; + + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + mpBuilder.addPart("categoriesZip", new FileBody(new File(importResourceDir))); + + RestResponse importResult = CategoryRestUtils.importCategories(mpBuilder, sdncAdminUserDetails.getUserId()); + assertEquals("Check response code after Import", BaseRestUtils.STATUS_CODE_CREATED, + importResult.getErrorCode().intValue()); + + Map map = ResponseParser.parseToObjectUsingMapper(importResult.getResponse(), Map.class); + assertEquals("Check entries count", 2, map.size()); + + List> resources = (List>) map.get("resources"); + assertEquals("Check resource category entries count", 1, resources.size()); + + List> services = (List>) map.get("services"); + assertEquals("Check resource category entries count", 2, services.size()); + + RestResponse allCategories = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, "resources"); + List resourceCategories = ResponseParser.parseCategories(allCategories); + for (Map resource : resources) { + boolean exist = false; + + for (CategoryDefinition categ : resourceCategories) { + if (categ.getName().equals(resource.get("name"))) { + exist = true; + break; + } + } + assertTrue("Check existance resource category " + resource.get("name"), exist); + } + + allCategories = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, "services"); + List servicesCategories = ResponseParser.parseCategories(allCategories); + for (Map service : services) { + boolean exist = false; + + for (CategoryDefinition categ : servicesCategories) { + if (categ.getName().equals(service.get("name"))) { + exist = true; + break; + } + } + assertTrue("Check existance service category " + service.get("name"), exist); + } + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/ElementsApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/ElementsApiTest.java new file mode 100644 index 0000000000..2f48f4fa1e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/ElementsApiTest.java @@ -0,0 +1,148 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.category; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.lf5.util.ResourceUtils; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.CatalogRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.testng.annotations.Test; + +public class ElementsApiTest extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public ElementsApiTest() { + super(name, ElementsApiTest.class.getName()); + } + + // public LCSbaseTest(TestName testName, String className) { + // super(testName, className); + // } + + // public ElementsApiTest(TestName name, String name2) { + //// super(name, name2); + // // TODO Auto-generated constructor stub + // } + + // Expected 200 Keep + @Test + public void getAllPropertyScopesSuccess() throws Exception { + RestResponse response = ResourceRestUtils.getAllPropertyScopesTowardsCatalogBe(); + String action = "Get All Property Scopes"; + int expectedCode = 200; + verifyErrorCode(response, action, expectedCode); + } + + // Expected 200 Keep + @Test + public void getAllArtifactTypes() throws Exception { + RestResponse response = ResourceRestUtils.getAllArtifactTypesTowardsCatalogBe(); + String action = "Get All Artifact Types"; + int expectedCode = 200; + verifyErrorCode(response, action, expectedCode); + } + + // Expected 200 Keep + @Test + public void getConfiguration() throws Exception { + RestResponse response = ResourceRestUtils.getConfigurationTowardsCatalogBe(); + String action = "Get All Artifact Types"; + int expectedCode = 200; + + String json = response.getResponse(); + JSONObject jsonResp = (JSONObject) JSONValue.parse(json); + + HashMap artifacts = (HashMap) jsonResp.get("artifacts"); + Long defaultHeatTimeout = (Long) jsonResp.get("defaultHeatTimeout"); + + if (defaultHeatTimeout == null) { + response.setErrorCode(500); + verifyErrorCode(response, action, expectedCode); + return; + } + + if (artifacts == null) { + response.setErrorCode(500); + verifyErrorCode(response, action, expectedCode); + return; + } + + JSONObject deploymentResources = (JSONObject) artifacts.get("deployment"); + JSONArray otherResources = (JSONArray) artifacts.get("other"); + if (deploymentResources == null || otherResources == null) { + response.setErrorCode(500); + verifyErrorCode(response, action, expectedCode); + return; + } + + JSONArray roles = (JSONArray) jsonResp.get("roles"); + if (roles == null) { + response.setErrorCode(500); + verifyErrorCode(response, action, expectedCode); + return; + } + + } + + public void verifyErrorCode(RestResponse response, String action, int expectedCode) { + assertNotNull("check response object is not null after " + action, response); + assertNotNull("check error code exists in response after " + action, response.getErrorCode()); + assertEquals("Check response code after + action" + action, expectedCode, response.getErrorCode().intValue()); + } + + @Test(enabled = false) + public void getAllCategoriesSuccess() throws Exception { + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + RestResponse response = CatalogRestUtils.getAllCategoriesTowardsCatalogBe(); + String action = "Get All Categories"; + int expectedCode = 200; + verifyErrorCode(response, action, expectedCode); + } + + @Test(enabled = false) + public void getAllTagSuccess() throws Exception { + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + RestResponse response = ResourceRestUtils.getAllTagsTowardsCatalogBe(); + String action = "Get All Categories"; + int expectedCode = 200; + verifyErrorCode(response, action, expectedCode); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/GroupingTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/GroupingTest.java new file mode 100644 index 0000000000..f6b6113b99 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/GroupingTest.java @@ -0,0 +1,2007 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.category; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.PRODUCT_COMPONENT_TYPE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.RESOURCE_COMPONENT_TYPE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.SERVICE_COMPONENT_TYPE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_ALREADY_EXISTS; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_CREATED; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_INVALID_CONTENT; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_MISSING_INFORMATION; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_NOT_FOUND; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; +import static org.testng.AssertJUnit.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedCategoryAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.CategoryValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.SkipException; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class GroupingTest extends CategoriesBaseTest { + + protected static final String ADD_GROUPING = "AddGrouping"; + protected static final String CATEGORY = "category"; + protected static final String SUB_CATEGORY = "sub-category"; + protected static final String GROUPING = "grouping"; + + public GroupingTest() { + super(name, GroupingTest.class.getName()); + } + + @Rule + public static TestName name = new TestName(); + + private CategoryDefinition productCategoryDefinition; + private CategoryDefinition productCategoryDefinition2; + + private SubCategoryDefinition productSubCategoryDefinition; + private SubCategoryDefinition productSubCategoryDefinition2; + private SubCategoryDefinition productSubCategoryDefinition3; + + private GroupingDefinition productGroupingDefinition; + private GroupingDefinition productGroupingDefinition2; + private GroupingDefinition productGroupingDefinition3; + + @BeforeMethod + public void init() throws Exception { + + // Category setup + productCategoryDefinition = new CategoryDefinition(); + productCategoryDefinition.setName("Category1"); + productCategoryDefinition2 = new CategoryDefinition(); + productCategoryDefinition2.setName("Category2"); + + // Subcategory setup + productSubCategoryDefinition = new SubCategoryDefinition(); + productSubCategoryDefinition.setName("SubCategory1"); + + productSubCategoryDefinition2 = new SubCategoryDefinition(); + productSubCategoryDefinition2.setName("SubCategory2"); + + productSubCategoryDefinition3 = new SubCategoryDefinition(); + productSubCategoryDefinition3.setName("SubCategory1"); + + // Group setup + productGroupingDefinition = new GroupingDefinition(); + productGroupingDefinition.setName("Grouping1"); + + productGroupingDefinition2 = new GroupingDefinition(); + productGroupingDefinition2.setName("Grouping2"); + + productGroupingDefinition3 = new GroupingDefinition(); + productGroupingDefinition3.setName("Grouping1"); + + // Init product category + RestResponse createCategory = CategoryRestUtils.createCategory(productCategoryDefinition, + sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createCategory.getErrorCode().intValue()); + CategoryDefinition category = ResponseParser.parseToObject(createCategory.getResponse(), + CategoryDefinition.class); + assertEquals("Check category name after creating category ", productCategoryDefinition.getName(), + category.getName()); + productCategoryDefinition = category; + + // Init product category1 + createCategory = CategoryRestUtils.createCategory(productCategoryDefinition2, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createCategory.getErrorCode().intValue()); + category = ResponseParser.parseToObject(createCategory.getResponse(), CategoryDefinition.class); + assertEquals("Check category name after creating category ", productCategoryDefinition2.getName(), + category.getName()); + productCategoryDefinition2 = category; + + // Init product productSubCategoryDefinition to + // productCategoryDefinition + RestResponse createSubCategory = CategoryRestUtils.createSubCategory(productSubCategoryDefinition, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createSubCategory.getErrorCode().intValue()); + SubCategoryDefinition subCategory = ResponseParser.parseToObject(createSubCategory.getResponse(), + SubCategoryDefinition.class); + assertEquals("Check category name after creating category ", productSubCategoryDefinition.getName(), + subCategory.getName()); + productSubCategoryDefinition = subCategory; + productCategoryDefinition.addSubCategory(productSubCategoryDefinition); + + // Init product productSubCategoryDefinition1 to + // productCategoryDefinition + createSubCategory = CategoryRestUtils.createSubCategory(productSubCategoryDefinition2, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createSubCategory.getErrorCode().intValue()); + subCategory = ResponseParser.parseToObject(createSubCategory.getResponse(), SubCategoryDefinition.class); + assertEquals("Check category name after creating category ", productSubCategoryDefinition2.getName(), + subCategory.getName()); + productSubCategoryDefinition2 = subCategory; + productCategoryDefinition.addSubCategory(productSubCategoryDefinition2); + + // Init product productSubCategoryDefinition3 to + // productCategoryDefinition2 + createSubCategory = CategoryRestUtils.createSubCategory(productSubCategoryDefinition3, + productCategoryDefinition2, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createSubCategory.getErrorCode().intValue()); + subCategory = ResponseParser.parseToObject(createSubCategory.getResponse(), SubCategoryDefinition.class); + assertEquals("Check category name after creating category ", productSubCategoryDefinition3.getName(), + subCategory.getName()); + productSubCategoryDefinition3 = subCategory; + productCategoryDefinition2.addSubCategory(productSubCategoryDefinition3); + } + + @Test + public void createProductGroupCategorySuccess() throws Exception { + createGroupingSuccess(productGroupingDefinition, productSubCategoryDefinition, productCategoryDefinition, + sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE, AUDIT_PRODUCT_TYPE); + } + + private void createGroupingSuccess(GroupingDefinition groupingDefinition, + SubCategoryDefinition subCategoryDefinition, CategoryDefinition categoryDefinition, + User sdncProductStrategistUserDetails, String productComponentType, String auditType) throws Exception { + + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(groupingDefinition, subCategoryDefinition, + categoryDefinition, sdncProductStrategistUserDetails, productComponentType); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("grouping1"); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + productComponentType); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, categoryDefinition.getUniqueId(), + subCategoryDefinition.getUniqueId(), groupingDefinition); + + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, categoryDefinition, subCategoryDefinition, + groupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, auditType); + } + + //// Benny + + @Test + public void createProductGroupByProductStrategist() throws Exception { + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("grouping1"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void createProductGroupAlreadyExistInSameCategorySubCategory() throws Exception { + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("grouping1"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + // Create Same Group already exist on same Category/SubCategory + DbUtils.deleteFromEsDbByPattern("_all"); + createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, productSubCategoryDefinition, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_ALREADY_EXISTS, + createGroupingRest.getErrorCode().intValue()); + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, + ActionStatus.COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY, STATUS_CODE_ALREADY_EXISTS, AUDIT_PRODUCT_TYPE, + AUDIT_PRODUCT_TYPE, productGroupingDefinition.getName(), productSubCategoryDefinition.getName()); + } + + @Test + public void createProductGroupUnderSameCategoryButDifferentSubCategory() throws Exception { + // Setting : Category-A, Sub-category-B , group : aBcd (display-Name : + // ABcd, normalized: abcd)  [A, B, ABcd] + // Action : Category-A, Sub-category-C, group : abcD (display-Name : + // ABcd, normalized: abcd)  [A, C, ABcd] + productGroupingDefinition.setName("ABCd"); + productGroupingDefinition2.setName("abcD"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + + DbUtils.deleteFromEsDbByPattern("_all"); + createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition2, productSubCategoryDefinition2, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition2.setName("ABCd"); + productGroupingDefinition2.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition2); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, + productSubCategoryDefinition2, productGroupingDefinition2, sdncProductStrategistUserDetails, + STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition2.getUniqueId(), + productGroupingDefinition2); + } + + @Test + public void createProductGroupUnderSameSubCategoryButDifferentCategory() throws Exception { + // Setting : Category-A, Sub-category-B , group : aBcd (display-Name : + // ABcd, normalized: abcd)  [A, B, ABcd] + // : Category-A, Sub-category-C, group : abcD (display-Name : ABcd, + // normalized: abcd)  [A, C, ABcd] + // : Category-K, Sub-category-B, group : abcD (display-Name : ABcd, + // normalized: abcd)  [K, B, ABcd] + productGroupingDefinition.setName("ABCd"); + productGroupingDefinition2.setName("abcD"); + productGroupingDefinition3.setName("aBCd"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + + DbUtils.deleteFromEsDbByPattern("_all"); + createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition2, productSubCategoryDefinition2, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition2.setName("ABCd"); + productGroupingDefinition2.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition2); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, + productSubCategoryDefinition2, productGroupingDefinition2, sdncProductStrategistUserDetails, + STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + DbUtils.deleteFromEsDbByPattern("_all"); + createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition3, productSubCategoryDefinition3, + productCategoryDefinition2, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition3.setName("ABCd"); + productGroupingDefinition3.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition3); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition2, + productSubCategoryDefinition3, productGroupingDefinition3, sdncProductStrategistUserDetails, + STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition2.getUniqueId(), + productGroupingDefinition2); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition2.getUniqueId(), productSubCategoryDefinition3.getUniqueId(), + productGroupingDefinition3); + + } + + @Test + public void createProductGroupsOnSameCategorySubCategory() throws Exception { + // Setting : Category-A, Sub-category-B , group : ABcd (display-Name : + // ABcd, normalized: abcd) [A ,B, ABcd] + // Action : Category-A, Sub-category-B, group : ZXcv (display-Name : + // ZXcv, normalized: zxcv) [A, B, ZXcv] + productGroupingDefinition.setName("ABcd"); + productGroupingDefinition2.setName("ZXcv"); + productGroupingDefinition2.setNormalizedName("zxcv"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + + DbUtils.deleteFromEsDbByPattern("_all"); + createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition2, productSubCategoryDefinition, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition2); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition2, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition2); + } + + @Test + public void createProductGroupUnderDifferentCategory() throws Exception { + // Setting : Category-A, Sub-category-B , group : aBcd (display-Name : + // ABcd, normalized: abcd) [A ,B, ABcd] + // Action : Category-K, Sub-category-B, group : abcD (display-Name : + // ABcd, normalized: abcd) [K, B, ABcd] + // productGroupingDefinition.setName("ABCd"); + productGroupingDefinition.setName("ABcD"); + productGroupingDefinition2.setName("abcD"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("abcd"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + + DbUtils.deleteFromEsDbByPattern("_all"); + createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition2, productSubCategoryDefinition3, + productCategoryDefinition2, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition2.setNormalizedName("abcd"); + productGroupingDefinition2.setName("ABcD"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition2); + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition2, + productSubCategoryDefinition3, productGroupingDefinition2, sdncProductStrategistUserDetails, + STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition2.getUniqueId(), productSubCategoryDefinition3.getUniqueId(), + productGroupingDefinition2); + } + + /////////// + @Test + public void createProductGroupByNonProductStrategist() throws Exception { + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncAdminUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_RESTRICTED_OPERATION, + createGroupingRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + productCategoryDefinition.setName(productCategoryDefinition.getUniqueId()); + productSubCategoryDefinition.setName(productSubCategoryDefinition.getUniqueId()); + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncAdminUserDetails, ActionStatus.RESTRICTED_OPERATION, + STATUS_CODE_RESTRICTED_OPERATION, AUDIT_PRODUCT_TYPE); + } + + // @Ignore("DE176245") + @Test + public void createProductGroupForNonExistingComponentType() throws Exception { + String nonSupportedComponentType = "NonExistingComponentType"; // instead + // resource/product + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + nonSupportedComponentType); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createGroupingRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + productCategoryDefinition.setName(productCategoryDefinition.getUniqueId()); + productSubCategoryDefinition.setName(productSubCategoryDefinition.getUniqueId()); + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, ActionStatus.INVALID_CONTENT, + STATUS_CODE_INVALID_CONTENT, nonSupportedComponentType); + } + + // @Ignore("DE176245") + @Test + public void createResourceGroup() throws Exception { + // Resource doesn't have group + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createGroupingRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + productCategoryDefinition.setName(productCategoryDefinition.getUniqueId()); + productSubCategoryDefinition.setName(productSubCategoryDefinition.getUniqueId()); + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, ActionStatus.INVALID_CONTENT, + STATUS_CODE_INVALID_CONTENT, AUDIT_RESOURCE_TYPE); + } + + // @Ignore("DE176245") + @Test + public void createServiceGroup() throws Exception { + // Service doesn't have group + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createGroupingRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + productCategoryDefinition.setName(productCategoryDefinition.getUniqueId()); + productSubCategoryDefinition.setName(productSubCategoryDefinition.getUniqueId()); + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, ActionStatus.INVALID_CONTENT, + STATUS_CODE_INVALID_CONTENT, AUDIT_SERVICE_TYPE); + } + + @Test + public void createProductGroupForNonExistingCategory() throws Exception { + + CategoryDefinition productCategoryDefinition100 = new CategoryDefinition(); + productCategoryDefinition100.setName("category.nonexistingCategory"); + productCategoryDefinition100.setUniqueId("category.nonexistingCategory"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition100, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_NOT_FOUND, + createGroupingRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + productSubCategoryDefinition.setName(productSubCategoryDefinition.getUniqueId()); + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition100, + productSubCategoryDefinition, productGroupingDefinition, sdncProductStrategistUserDetails, + ActionStatus.COMPONENT_CATEGORY_NOT_FOUND, STATUS_CODE_NOT_FOUND, AUDIT_PRODUCT_TYPE, + PRODUCT_COMPONENT_TYPE, CATEGORY, ""); + } + + @Test + public void createProductGroupForNonExistingSunCategory() throws Exception { + throw new SkipException( + "Skipping - failed in audit validation expected \"products\" actual result was \"product\" "); + // SubCategoryDefinition productSubCategoryDefinition100 = new + // SubCategoryDefinition(); + // productSubCategoryDefinition100.setUniqueId("category.nonexistingSubCategory"); + // RestResponse createGroupingRest = + // CategoryRestUtils.createGrouping(productGroupingDefinition, + // productSubCategoryDefinition100, productCategoryDefinition, + // sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + // assertEquals("Check response code after create Sub category", + // STATUS_CODE_NOT_FOUND, createGroupingRest.getErrorCode().intValue()); + // RestResponse getAllCategoriesRest = + // CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + // PRODUCT_COMPONENT_TYPE); + // assertEquals("Check response code after get all categories ", + // STATUS_CODE_SUCCESS, getAllCategoriesRest.getErrorCode().intValue()); + // CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + // productCategoryDefinition.getUniqueId(), + // productSubCategoryDefinition.getUniqueId(), + // productGroupingDefinition); + // //Audit validation + // productSubCategoryDefinition100.setName(productSubCategoryDefinition100.getUniqueId()); + // AuditValidationUtils.groupingAuditFailure(ADD_GROUPING , + // productCategoryDefinition, productSubCategoryDefinition100, + // productGroupingDefinition, sdncProductStrategistUserDetails, + // ActionStatus.COMPONENT_CATEGORY_NOT_FOUND, + // STATUS_CODE_NOT_FOUND,AUDIT_PRODUCT_TYPE, PRODUCT_COMPONENT_TYPE, + // SUB_CATEGORY, ""); + } + + @Test + public void ProductGroupAllowedcharacters_01() throws Exception { + productGroupingDefinition.setName("1234AbcdE-"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde-"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_02() throws Exception { + productGroupingDefinition.setName("1234AbcdE+"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde+"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_03() throws Exception { + productGroupingDefinition.setName("1234AbcdE&"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde&"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_04() throws Exception { + productGroupingDefinition.setName("1234AbcdE-"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde-"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_05() throws Exception { + productGroupingDefinition.setName("1234AbcdE+"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde+"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_06() throws Exception { + productGroupingDefinition.setName("1234AbcdE."); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde."); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_07() throws Exception { + productGroupingDefinition.setName("1234AbcdE'"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde'"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_08() throws Exception { + productGroupingDefinition.setName("1234AbcdE="); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde="); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_09() throws Exception { + productGroupingDefinition.setName("1234AbcdE:"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde:"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_10() throws Exception { + productGroupingDefinition.setName("1234AbcdE@"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde@"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_11() throws Exception { + productGroupingDefinition.setName("1234AbcdE_"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde_"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_12() throws Exception { + productGroupingDefinition.setName("1234AbcdE#"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("1234abcde#"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void ProductGroupAllowedcharacters_13() throws Exception { + productGroupingDefinition.setName("1234AbcdE d"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("1234AbcdE D"); + productGroupingDefinition.setNormalizedName("1234abcde d"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveSpaceFromBeginning() throws Exception { + productGroupingDefinition.setName(" Category01"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("category01"); + productGroupingDefinition.setName("Category01"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveSpaceFromEnd() throws Exception { + productGroupingDefinition.setName("Category01 "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("category01"); + productGroupingDefinition.setName("Category01"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtraSpace() throws Exception { + productGroupingDefinition.setName("Category 02"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("category 02"); + productGroupingDefinition.setName("Category 02"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtraAmpersand() throws Exception { + productGroupingDefinition.setName("Category&& &02"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("category& &02"); + productGroupingDefinition.setName("Category& &02"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtraDash() throws Exception { + productGroupingDefinition.setName("CategorY-- --02"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("category- -02"); + productGroupingDefinition.setName("CategorY- -02"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtraPlus() throws Exception { + productGroupingDefinition.setName("CateGory++++ +02"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("CateGory+ +02"); + productGroupingDefinition.setNormalizedName("category+ +02"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtraPeriod() throws Exception { + productGroupingDefinition.setName("Category.... .02"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Category. .02"); + productGroupingDefinition.setNormalizedName("category. .02"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtraApostrophe() throws Exception { + productGroupingDefinition.setName("CaTegory''' '02"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("CaTegory' '02"); + productGroupingDefinition.setNormalizedName("category' '02"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtraHashtag() throws Exception { + productGroupingDefinition.setName("Category### #02"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Category# #02"); + productGroupingDefinition.setNormalizedName("category# #02"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtrEequal() throws Exception { + productGroupingDefinition.setName("Category=== =02"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Category= =02"); + productGroupingDefinition.setNormalizedName("category= =02"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtrColon() throws Exception { + productGroupingDefinition.setName("Category::: :02"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Category: :02"); + productGroupingDefinition.setNormalizedName("category: :02"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtrAt() throws Exception { + productGroupingDefinition.setName("Category@@@ @a2"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Category@ @a2"); + productGroupingDefinition.setNormalizedName("category@ @a2"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_RemoveExtraUnderscore() throws Exception { + productGroupingDefinition.setName("Category___ _22"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Category_ _22"); + productGroupingDefinition.setNormalizedName("category_ _22"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_FirstWordStartWithNumber() throws Exception { + productGroupingDefinition.setName("1Category one"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("1Category One"); + productGroupingDefinition.setNormalizedName("1category one"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_FirstWordStartWithNonAlphaNumeric() throws Exception { // The + // first + // word + // must + // start + // with + // an + // alpha-numeric + // character + // [a-Z + // A..Z, + // 0..9] + char invalidChars[] = { '&', '-', '+', '.', '\'', '#', '=', ':', '@', '_' }; + RestResponse createGroupingRest; + RestResponse getAllCategoriesRest; + for (int i = 0; i < invalidChars.length; i++) { + DbUtils.deleteFromEsDbByPattern("_all"); + productGroupingDefinition.setName(invalidChars[i] + "AbcD123"); + productGroupingDefinition.setNormalizedName((invalidChars[i] + "AbcD123").toLowerCase()); + createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_INVALID_CONTENT, + createGroupingRest.getErrorCode().intValue()); + + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + } + } + + @Test + public void groupNameValidation_ReplaceAndWithAmpersand_01() throws Exception { + productGroupingDefinition.setName("At and T"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("At & T"); + productGroupingDefinition.setNormalizedName("at & t"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_ReplaceAndWithAmpersand_02() throws Exception { + productGroupingDefinition.setName("At and t"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("At & T"); + productGroupingDefinition.setNormalizedName("at & t"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_ReplaceAndWithAmpersand_03() throws Exception { + productGroupingDefinition.setName("Atand T"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("atand t"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_ReplaceAndWithAmpersand_04() throws Exception { + productGroupingDefinition.setName("At andT"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("at andt"); + productGroupingDefinition.setName("At AndT"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_ReplaceAndWithAmpersand_05() throws Exception { + productGroupingDefinition.setName(" and AttT"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("and attt"); + productGroupingDefinition.setName("And AttT"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_ReplaceAndWithAmpersand_06() throws Exception { + productGroupingDefinition.setName("AttT and "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("attt and"); + productGroupingDefinition.setName("AttT And"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidation_ReplaceAndWithAmpersand_07() throws Exception { + productGroupingDefinition.setName(" and a"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("and a"); + productGroupingDefinition.setName("And a"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationMaxLength() throws Exception { + productGroupingDefinition.setName("AsdfghjQ234567890@#.&:+-_"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("asdfghjq234567890@#.&:+-_"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationMaxLengthAfterNormalization() throws Exception { + productGroupingDefinition.setName(" A jQ234 @@@___ +++ At and T and and "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("a jq234 @_ + at & t & and"); + productGroupingDefinition.setName("A JQ234 @_ + At & T & And"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationExceedMaxLengthAfterNormalization() throws Exception { + productGroupingDefinition.setName(" AbdfghBCVa jQ234 @@___ +++ At and T "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_INVALID_CONTENT, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("abdfghbcva jq234 @_ + at&t"); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, STATUS_CODE_INVALID_CONTENT, AUDIT_PRODUCT_TYPE, + AUDIT_PRODUCT_TYPE, GROUPING); + } + + @Test + public void groupNameValidationMinLengthAfterNormalization() throws Exception { + productGroupingDefinition.setName(" At&&&&&&&&&&&&t "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("at&t"); + productGroupingDefinition.setName("At&t"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationLessThanMinLengthAfterNormalization() throws Exception { + productGroupingDefinition.setName(" A&&&&&&&&&&&&T "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_INVALID_CONTENT, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("a&t"); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, STATUS_CODE_INVALID_CONTENT, AUDIT_PRODUCT_TYPE, + AUDIT_PRODUCT_TYPE, GROUPING); + } + + @Test + public void groupNameValidationIsEmpty() throws Exception { + productGroupingDefinition.setName(""); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_INVALID_CONTENT, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName(""); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, STATUS_CODE_INVALID_CONTENT, AUDIT_PRODUCT_TYPE, + AUDIT_PRODUCT_TYPE, GROUPING); + } + + @Test + public void groupNameValidationInvalidCharacters() throws Exception { + RestResponse createGroupingRest; + RestResponse getAllCategoriesRest; + char invalidChars[] = { '~', '!', '$', '%', '^', '*', '(', ')', '"', '{', '}', '[', ']', '?', '>', '<', '/', + '|', '\\', ',' }; + for (int i = 0; i < invalidChars.length; i++) { + DbUtils.deleteFromEsDbByPattern("_all"); + productGroupingDefinition.setName("AbcD123" + invalidChars[i]); + createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_INVALID_CONTENT, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName(""); + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditFailure(ADD_GROUPING, productCategoryDefinition, + productSubCategoryDefinition, productGroupingDefinition, sdncProductStrategistUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, STATUS_CODE_INVALID_CONTENT, AUDIT_PRODUCT_TYPE, + AUDIT_PRODUCT_TYPE, GROUPING); + } + } + + @Test + public void groupNameValidationConjunctions_01() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" bank OF america "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setNormalizedName("bank of america"); + productGroupingDefinition.setName("Bank of America"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_02() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName("THE america bank "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("THE America Bank"); + productGroupingDefinition.setNormalizedName("the america bank"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_03() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" A bank OF america "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("A Bank of America"); + productGroupingDefinition.setNormalizedName("a bank of america"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_04() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" bank america is A big ban "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Bank America Is a Big Ban"); + productGroupingDefinition.setNormalizedName("bank america is a big ban"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_05() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" aN apple comPany inC "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("AN Apple ComPany InC"); + productGroupingDefinition.setNormalizedName("an apple company inc"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_06() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" eat AN apple ANAN"); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Eat an Apple ANAN"); + productGroupingDefinition.setNormalizedName("eat an apple anan"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_07() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" united states OF americA "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("United States of AmericA"); + productGroupingDefinition.setNormalizedName("united states of america"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_08() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" oF united states OF amer "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("OF United States of Amer"); + productGroupingDefinition.setNormalizedName("of united states of amer"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_09() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" to Apple TO at&T TOO "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("To Apple to At&T TOO"); + productGroupingDefinition.setNormalizedName("to apple to at&t too"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_10() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" eat apple AS you liiikeas "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Eat Apple as You Liiikeas"); + productGroupingDefinition.setNormalizedName("eat apple as you liiikeas"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_11() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" as you may want "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("As You May Want"); + productGroupingDefinition.setNormalizedName("as you may want"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_12() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" the bank OF america "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("The Bank of America"); + productGroupingDefinition.setNormalizedName("the bank of america"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_13() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" To tel-toto "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("To Tel-toto"); + productGroupingDefinition.setNormalizedName("to tel-toto"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void groupNameValidationConjunctions_14() throws Exception { + // Normalize the grouping name conjunctions ('of', 'to', 'for', 'as', + // 'a', 'an' , 'the') are lower case. + productGroupingDefinition.setName(" tel-aviv To la "); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create product group", STATUS_CODE_CREATED, + createGroupingRest.getErrorCode().intValue()); + productGroupingDefinition.setName("Tel-aviv to La"); + productGroupingDefinition.setNormalizedName("tel-aviv to la"); + CategoryValidationUtils.validateCreateGroupResponse(createGroupingRest, productGroupingDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + AuditValidationUtils.groupingAuditSuccess(ADD_GROUPING, productCategoryDefinition, productSubCategoryDefinition, + productGroupingDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, AUDIT_PRODUCT_TYPE); + } + + @Test + public void createProductGroupHttpCspUserIdIsEmpty() throws Exception { + User sdncPS = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1); + sdncPS.setUserId(""); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncPS, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_INFORMATION, + createGroupingRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(ADD_GROUPING); + expectedCatrgoryAuditJavaObject.setModifier(""); + expectedCatrgoryAuditJavaObject.setCategoryName(productCategoryDefinition.getUniqueId()); + expectedCatrgoryAuditJavaObject.setSubCategoryName(productSubCategoryDefinition.getUniqueId()); + expectedCatrgoryAuditJavaObject.setGroupingName(productGroupingDefinition.getName()); + expectedCatrgoryAuditJavaObject.setResourceType(AUDIT_PRODUCT_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_MISSING_INFORMATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateCategoryAudit(expectedCatrgoryAuditJavaObject, ADD_GROUPING); + } + + @Test + public void createProductGroupHttpCspUserIdIsNull() throws Exception { + User sdncPS = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1); + sdncPS.setUserId(null); + RestResponse createGroupingRest = CategoryRestUtils.createGrouping(productGroupingDefinition, + productSubCategoryDefinition, productCategoryDefinition, sdncPS, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_INFORMATION, + createGroupingRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifyGroupingNotExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition.getUniqueId(), + productGroupingDefinition); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(ADD_GROUPING); + expectedCatrgoryAuditJavaObject.setModifier(""); + expectedCatrgoryAuditJavaObject.setCategoryName(productCategoryDefinition.getUniqueId()); + expectedCatrgoryAuditJavaObject.setSubCategoryName(productSubCategoryDefinition.getUniqueId()); + expectedCatrgoryAuditJavaObject.setGroupingName(productGroupingDefinition.getName()); + expectedCatrgoryAuditJavaObject.setResourceType(AUDIT_PRODUCT_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_MISSING_INFORMATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateCategoryAudit(expectedCatrgoryAuditJavaObject, ADD_GROUPING); + } + + //////////////////////////////////////////////// + /////////////////////////////////////////////// + @Test + public void getProductCategoryHierarchySuccessFlow() throws Exception { + throw new SkipException( + "Skipping - failed in audit validation expected \"products\" actual result was \"product\" "); + // int numOfGrouping = 3; + // List groupingList = new ArrayList<>(); + // RestResponse restResponse; + // GroupingDefinition grouping; + // String groupingName = productGroupingDefinition.getName(); + // for (int i = 0; i < numOfGrouping; i++) { + // productGroupingDefinition.setName(groupingName+i); + // restResponse = + // CategoryRestUtils.createGrouping(productGroupingDefinition, + // productSubCategoryDefinition, productCategoryDefinition, + // sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + // grouping = ResponseParser.parseToObject(restResponse.getResponse(), + // GroupingDefinition.class); + // groupingList.add(grouping); + // } + // RestResponse getAllCategoriesRest = + // CategoryRestUtils.getAllCategories(sdncProductStrategistUserDetails, + // PRODUCT_COMPONENT_TYPE); + // assertEquals("Check response code after get all categories ", + // STATUS_CODE_SUCCESS, getAllCategoriesRest.getErrorCode().intValue()); + // AuditValidationUtils.GetCategoryHierarchyAuditSuccess(GET_CATEGORY_HIERARCHY, + // AUDIT_PRODUCT_TYPE, sdncProductStrategistUserDetails, + // STATUS_CODE_SUCCESS); + // + // for (GroupingDefinition group : groupingList) { + // CategoryValidationUtils.verifyGroupingExistInGetResponse(getAllCategoriesRest, + // productCategoryDefinition.getUniqueId(), + // productSubCategoryDefinition.getUniqueId(), group); + // } + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/SubCategoriesTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/SubCategoriesTest.java new file mode 100644 index 0000000000..dcc3172d59 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/category/SubCategoriesTest.java @@ -0,0 +1,1908 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.category; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.PRODUCT_COMPONENT_TYPE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.RESOURCE_COMPONENT_TYPE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.SERVICE_COMPONENT_TYPE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_ALREADY_EXISTS; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_CREATED; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_INVALID_CONTENT; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_MISSING_INFORMATION; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_NOT_FOUND; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; +import static org.testng.AssertJUnit.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedCategoryAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.CategoryValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class SubCategoriesTest extends ComponentBaseTest { + + protected static final String ADD_SUB_CATEGORY = "AddSubCategory"; + protected static final String CATEGORY = "category"; + protected static final String SUB_CATEGORY = "sub-category"; + + protected static final String AUDIT_SERVICE_TYPE = "Service"; + protected static final String AUDIT_RESOURCE_TYPE = "Resource"; + protected static final String AUDIT_PRODUCT_TYPE = "Product"; + protected static final String GET_CATEGORY_HIERARCHY = "GetCategoryHierarchy"; + protected static User sdncAdminUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + protected static User sdncAdminUserDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + protected static User sdncDesignerUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + protected static User sdncTesterUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + protected static User sdncGovernorUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR); + protected static User sdncOpsUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.OPS); + protected static User sdncProductManagerUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1); + protected static User sdncProductStrategistUserDetails = ElementFactory + .getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1); + + public SubCategoriesTest() { + super(name, SubCategoriesTest.class.getName()); + } + + @Rule + public static TestName name = new TestName(); + + private CategoryDefinition resourceCategoryDefinition; + private CategoryDefinition resourceCategoryDefinition1; + private CategoryDefinition serviceCategoryDefinition; + private CategoryDefinition productCategoryDefinition; + private CategoryDefinition productCategoryDefinition1; + private CategoryDefinition resourceCategoryDefinition100; + private CategoryDefinition productCategoryDefinition200; + + private SubCategoryDefinition resourceSubCategoryDefinition; + private SubCategoryDefinition resourceSubCategoryDefinition1; + private SubCategoryDefinition serviceSubCategoryDefinition; + private SubCategoryDefinition productSubCategoryDefinition; + private SubCategoryDefinition productSubCategoryDefinition1; + + @BeforeMethod + public void init() throws Exception { + + // Category setup + resourceCategoryDefinition = new CategoryDefinition(); + resourceCategoryDefinition1 = new CategoryDefinition(); + serviceCategoryDefinition = new CategoryDefinition(); + productCategoryDefinition = new CategoryDefinition(); + productCategoryDefinition1 = new CategoryDefinition(); + resourceCategoryDefinition100 = new CategoryDefinition(); // for + // negative + // tests + productCategoryDefinition200 = new CategoryDefinition(); // for negative + // tests + + resourceCategoryDefinition.setName("Category1"); + resourceCategoryDefinition1.setName("Category2"); + serviceCategoryDefinition.setName("Category1"); + productCategoryDefinition.setName("Category2"); + productCategoryDefinition1.setName("Category3"); + resourceCategoryDefinition100.setName("Category100"); + productCategoryDefinition200.setName("Category100"); + + // Subcategory setup + resourceSubCategoryDefinition = new SubCategoryDefinition(); + resourceSubCategoryDefinition1 = new SubCategoryDefinition(); + serviceSubCategoryDefinition = new SubCategoryDefinition(); + productSubCategoryDefinition = new SubCategoryDefinition(); + productSubCategoryDefinition1 = new SubCategoryDefinition(); + + resourceSubCategoryDefinition.setName("Resource-subcat"); + // Service sub - for negative testing since it's not allowed + serviceSubCategoryDefinition.setName("Service-subcat"); + productSubCategoryDefinition.setName("Product-subcat"); + + // Init resource category + RestResponse createCategory = CategoryRestUtils.createCategory(resourceCategoryDefinition, sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createCategory.getErrorCode().intValue()); + CategoryDefinition category = ResponseParser.parseToObject(createCategory.getResponse(), + CategoryDefinition.class); + assertEquals("Check category name after creating category ", resourceCategoryDefinition.getName(), + category.getName()); + resourceCategoryDefinition = category; + + // Init resource category1 + createCategory = CategoryRestUtils.createCategory(resourceCategoryDefinition1, sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createCategory.getErrorCode().intValue()); + category = ResponseParser.parseToObject(createCategory.getResponse(), CategoryDefinition.class); + assertEquals("Check category name after creating category ", resourceCategoryDefinition1.getName(), + category.getName()); + resourceCategoryDefinition1 = category; + + // Init service category + createCategory = CategoryRestUtils.createCategory(serviceCategoryDefinition, sdncAdminUserDetails, + SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createCategory.getErrorCode().intValue()); + category = ResponseParser.parseToObject(createCategory.getResponse(), CategoryDefinition.class); + assertEquals("Check category name after creating category ", serviceCategoryDefinition.getName(), + category.getName()); + serviceCategoryDefinition = category; + + // Init product category + createCategory = CategoryRestUtils.createCategory(productCategoryDefinition, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createCategory.getErrorCode().intValue()); + category = ResponseParser.parseToObject(createCategory.getResponse(), CategoryDefinition.class); + assertEquals("Check category name after creating category ", productCategoryDefinition.getName(), + category.getName()); + productCategoryDefinition = category; + + // Init product category1 + createCategory = CategoryRestUtils.createCategory(productCategoryDefinition1, sdncProductStrategistUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create category", STATUS_CODE_CREATED, + createCategory.getErrorCode().intValue()); + category = ResponseParser.parseToObject(createCategory.getResponse(), CategoryDefinition.class); + assertEquals("Check category name after creating category ", productCategoryDefinition1.getName(), + category.getName()); + productCategoryDefinition1 = category; + + } + + @Test + public void createResourceSubCategorySuccess() throws Exception { + createSubCategorySuccess(resourceCategoryDefinition, resourceSubCategoryDefinition, sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE, AUDIT_RESOURCE_TYPE); + } + + @Test + public void createProductSubCategorySuccess() throws Exception { + createSubCategorySuccess(productCategoryDefinition, productSubCategoryDefinition, + sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE, AUDIT_PRODUCT_TYPE); + } + + @Test + public void createProductSubCategoryTwoCategoriesCaseInsensitive() throws Exception { + String componentType = PRODUCT_COMPONENT_TYPE; + String auditType = AUDIT_PRODUCT_TYPE; + User user = sdncProductStrategistUserDetails; + // Create product sub Category2-->Product-subcat + createSubCategorySuccess(productCategoryDefinition, productSubCategoryDefinition, user, componentType, + auditType); + DbUtils.deleteFromEsDbByPattern("_all"); + + // Create product sub Category3-->PRoDUCT-SUBcat + // Should be created Category3-->Product-subcat + productSubCategoryDefinition1.setName("PRoDUCT-SUBcat"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition1, + productCategoryDefinition1, user, componentType); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(user, componentType); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + productSubCategoryDefinition1.setName(productSubCategoryDefinition.getName()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition1.getUniqueId(), productSubCategoryDefinition1); + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, productCategoryDefinition1, + productSubCategoryDefinition1, user, STATUS_CODE_CREATED, auditType); + } + + // Benny + @Test + public void createResourceSubCategoryAlreadyExistInDifferentResourceCategory() throws Exception { + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + DbUtils.deleteFromEsDbByPattern("_all"); + resourceSubCategoryDefinition1.setName("ResourcE-subCat"); + createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition1, + resourceCategoryDefinition1, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + resourceSubCategoryDefinition1.setName(resourceSubCategoryDefinition.getName()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition1.getUniqueId(), resourceSubCategoryDefinition1); // also + // set + // catalog + // uniqeId + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition1, + resourceSubCategoryDefinition1, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void createProductSubCategoryAlreadyExistInDifferentProductCategory() throws Exception { + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, productCategoryDefinition, + productSubCategoryDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, + AUDIT_PRODUCT_TYPE); + DbUtils.deleteFromEsDbByPattern("_all"); + productSubCategoryDefinition1.setName("PRoDUCT-SUBcat"); + createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition1, + productCategoryDefinition1, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + productSubCategoryDefinition1.setName(productSubCategoryDefinition.getName()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition1.getUniqueId(), productSubCategoryDefinition1); // also + // set + // catalog + // uniqeId + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, productCategoryDefinition1, + productSubCategoryDefinition1, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, + AUDIT_PRODUCT_TYPE); + } + + @Test + public void createResourceSubCategoryAlreadyExistInCategory() throws Exception { + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + DbUtils.deleteFromEsDbByPattern("_all"); + resourceSubCategoryDefinition1.setName("ResourcE-subCat"); + createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition1, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_ALREADY_EXISTS, + createSubCategoryRest.getErrorCode().intValue()); + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition1, sdncAdminUserDetails, + ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, STATUS_CODE_ALREADY_EXISTS, + AUDIT_RESOURCE_TYPE, AUDIT_RESOURCE_TYPE, resourceSubCategoryDefinition1.getName(), + resourceCategoryDefinition.getName()); + } + + @Test + public void createProductSubCategoryAlreadyExistInCategory() throws Exception { + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, productCategoryDefinition, + productSubCategoryDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, + AUDIT_PRODUCT_TYPE); + DbUtils.deleteFromEsDbByPattern("_all"); + productSubCategoryDefinition1.setName("ProducT-subCat"); + createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition1, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_ALREADY_EXISTS, + createSubCategoryRest.getErrorCode().intValue()); + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, productCategoryDefinition, + productSubCategoryDefinition1, sdncProductStrategistUserDetails, + ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY, STATUS_CODE_ALREADY_EXISTS, AUDIT_PRODUCT_TYPE, + AUDIT_PRODUCT_TYPE, productSubCategoryDefinition1.getName(), productCategoryDefinition.getName()); + } + + @Test + public void addSameNormalizedSubCategoryNameForRecourceAndProductCategory() throws Exception { + // add sub-categoty name "SubCaT" to resource category + // add sub-categoty name "SUbcAt" to product category + resourceSubCategoryDefinition.setName("SubCaT"); // normalized 'subcat' + productSubCategoryDefinition.setName("SUbcAt"); // normalized 'subcat' + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + + DbUtils.deleteFromEsDbByPattern("_all"); + createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition, + productCategoryDefinition, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, productCategoryDefinition, + productSubCategoryDefinition, sdncProductStrategistUserDetails, STATUS_CODE_CREATED, + AUDIT_PRODUCT_TYPE); + } + + @Test + public void createResourceSubCategoryByNonAdminUser() throws Exception { + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncTesterUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_RESTRICTED_OPERATION, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + resourceCategoryDefinition.setName(resourceCategoryDefinition.getUniqueId()); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncTesterUserDetails, ActionStatus.RESTRICTED_OPERATION, + STATUS_CODE_RESTRICTED_OPERATION, AUDIT_RESOURCE_TYPE); + } + + @Test + public void createResourceSubCategoryByProducStrategistUser() throws Exception { + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncProductStrategistUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_RESTRICTED_OPERATION, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + resourceCategoryDefinition.setName(resourceCategoryDefinition.getUniqueId()); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncProductStrategistUserDetails, ActionStatus.RESTRICTED_OPERATION, + STATUS_CODE_RESTRICTED_OPERATION, AUDIT_RESOURCE_TYPE); + } + + @Test + public void createProductSubCategoryByNonProducStrategistUser() throws Exception { + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition, + productCategoryDefinition, sdncDesignerUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_RESTRICTED_OPERATION, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition); + // Audit validation + productCategoryDefinition.setName(productCategoryDefinition.getUniqueId()); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, productCategoryDefinition, + productSubCategoryDefinition, sdncDesignerUserDetails, ActionStatus.RESTRICTED_OPERATION, + STATUS_CODE_RESTRICTED_OPERATION, AUDIT_PRODUCT_TYPE); + } + + @Test + public void createProductSubCategoryByAdminUser() throws Exception { + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition, + productCategoryDefinition, sdncAdminUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_RESTRICTED_OPERATION, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition); + // Audit validation + productCategoryDefinition.setName(productCategoryDefinition.getUniqueId()); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, productCategoryDefinition, + productSubCategoryDefinition, sdncAdminUserDetails, ActionStatus.RESTRICTED_OPERATION, + STATUS_CODE_RESTRICTED_OPERATION, AUDIT_PRODUCT_TYPE); + } + + // @Ignore("DE176245") + @Test + public void createResourceSubCategoryForNonExistingComponentType() throws Exception { + String nonSupportedComponentType = "NonExistingComponentType"; // instead + // resource/product + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, nonSupportedComponentType); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + resourceCategoryDefinition.setName(resourceCategoryDefinition.getUniqueId()); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, ActionStatus.INVALID_CONTENT, + STATUS_CODE_INVALID_CONTENT, nonSupportedComponentType); + } + + // @Ignore("DE176245") + @Test + public void createProductSubCategoryForNonExistingComponentType() throws Exception { + String nonSupportedComponentType = "NonExistingComponentType"; // instead + // resource/product + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition, + productCategoryDefinition, sdncProductStrategistUserDetails, nonSupportedComponentType); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition); + // Audit validation + productCategoryDefinition.setName(productCategoryDefinition.getUniqueId()); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, productCategoryDefinition, + productSubCategoryDefinition, sdncProductStrategistUserDetails, ActionStatus.INVALID_CONTENT, + STATUS_CODE_INVALID_CONTENT, nonSupportedComponentType); + } + + @Test + public void createServiceSubCategoryByAdmin() throws Exception { + // Service doesn't have sub-category + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + resourceCategoryDefinition.setName(resourceCategoryDefinition.getUniqueId()); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, ActionStatus.INVALID_CONTENT, + STATUS_CODE_INVALID_CONTENT, AUDIT_SERVICE_TYPE); + } + + @Test + public void createServiceSubCategoryByProductStrategist() throws Exception { + // Service doesn't have sub-category + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition, + productCategoryDefinition, sdncProductStrategistUserDetails, SERVICE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + productCategoryDefinition.getUniqueId(), productSubCategoryDefinition); + // Audit validation + productCategoryDefinition.setName(productCategoryDefinition.getUniqueId()); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, productCategoryDefinition, + productSubCategoryDefinition, sdncProductStrategistUserDetails, ActionStatus.INVALID_CONTENT, + STATUS_CODE_INVALID_CONTENT, AUDIT_SERVICE_TYPE); + } + + @Test + public void createResourceSubCategoryForNonExistingCategory() throws Exception { + resourceCategoryDefinition100.setUniqueId(resourceCategoryDefinition100.getName()); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition100, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_NOT_FOUND, + createSubCategoryRest.getErrorCode().intValue()); + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition100, + resourceSubCategoryDefinition, sdncAdminUserDetails, ActionStatus.COMPONENT_CATEGORY_NOT_FOUND, + STATUS_CODE_NOT_FOUND, AUDIT_RESOURCE_TYPE, RESOURCE_COMPONENT_TYPE, CATEGORY, ""); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition100.getUniqueId(), resourceSubCategoryDefinition); + } + + @Test + public void createProductSubCategoryForNonExistingCategory() throws Exception { + productCategoryDefinition200.setUniqueId(productCategoryDefinition200.getName()); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(productSubCategoryDefinition, + productCategoryDefinition200, sdncProductStrategistUserDetails, PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_NOT_FOUND, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + PRODUCT_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + productCategoryDefinition200.getUniqueId(), productSubCategoryDefinition); + // Audit validation // need to change ActionStatus + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, productCategoryDefinition200, + productSubCategoryDefinition, sdncProductStrategistUserDetails, + ActionStatus.COMPONENT_CATEGORY_NOT_FOUND, STATUS_CODE_NOT_FOUND, AUDIT_PRODUCT_TYPE, + PRODUCT_COMPONENT_TYPE, CATEGORY, ""); + } + + // pass + @Test + public void subCategoryAllowedcharacters_01() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE-"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); // also + // set + // catalog + // uniqeId + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + // pass + @Test + public void subCategoryAllowedcharacters_02() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE+"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_03() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE&"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_04() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE."); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_05() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE'"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_06() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE="); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_07() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE:"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_08() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE@"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_09() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE_"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_10() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE#"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_11() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE d"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("1234AbcdE D"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryAllowedcharacters_12() throws Exception { + resourceSubCategoryDefinition.setName("1234AbcdE &_=+.-'#:@ d"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("1234AbcdE &_=+.-'#:@ D"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveSpaceFromBeginning() throws Exception { + resourceSubCategoryDefinition.setName(" Category01"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category01"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveSpaceFromEnd() throws Exception { + resourceSubCategoryDefinition.setName("Category01 "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category01"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtraSpace() throws Exception { + resourceSubCategoryDefinition.setName("Category 02"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category 02"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtraAmpersand() throws Exception { + resourceSubCategoryDefinition.setName("Category&& &02"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category& &02"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtraDash() throws Exception { + resourceSubCategoryDefinition.setName("CategorY-- --02"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("CategorY- -02"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtraPlus() throws Exception { + resourceSubCategoryDefinition.setName("CateGory++++ +02"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("CateGory+ +02"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtraPeriod() throws Exception { + resourceSubCategoryDefinition.setName("Category.... .02"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category. .02"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtraApostrophe() throws Exception { + resourceSubCategoryDefinition.setName("CaTegory''' '02"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("CaTegory' '02"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtraHashtag() throws Exception { + resourceSubCategoryDefinition.setName("Category### #02"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category# #02"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtrEequal() throws Exception { + resourceSubCategoryDefinition.setName("Category=== =02"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category= =02"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtrColon() throws Exception { + resourceSubCategoryDefinition.setName("Category::: :02"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category: :02"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtrAt() throws Exception { + resourceSubCategoryDefinition.setName("Category@@@ @a2"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category@ @a2"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryRemoveExtraUnderscore() throws Exception { + resourceSubCategoryDefinition.setName("Category___ _22"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Category_ _22"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryFirstWordStartWithNumber() throws Exception { + resourceSubCategoryDefinition.setName("1Category one"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("1Category One"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + // Bug + // Desc= + // DESC=SVC4556: Error: InvalidResourcesub-categorynameformat., + // @Ignore + @Test + public void subCategoryFirstWordStartWithNonAlphaNumeric() throws Exception { + // The first word must start with an alpha-numeric character [a-Z A..Z, + // 0..9] + char invalidChars[] = { '&', '-', '+', '.', '\'', '#', '=', ':', '@', '_' }; + for (int i = 0; i < invalidChars.length; i++) { + DbUtils.deleteFromEsDbByPattern("_all"); + resourceSubCategoryDefinition.setName(invalidChars[i] + "AbcD123"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Category", STATUS_CODE_INVALID_CONTENT, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, STATUS_CODE_INVALID_CONTENT, + AUDIT_RESOURCE_TYPE, AUDIT_RESOURCE_TYPE, SUB_CATEGORY); + + } + } + + @Test + public void subCategoryReplaceAndWithAmpersand_01() throws Exception { + resourceSubCategoryDefinition.setName("At and T"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("At & T"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryReplaceAndWithAmpersand_02() throws Exception { + resourceSubCategoryDefinition.setName("At and t"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("At & T"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryReplaceAndWithAmpersand_03() throws Exception { + resourceSubCategoryDefinition.setName("Atand T"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryReplaceAndWithAmpersand_04() throws Exception { + resourceSubCategoryDefinition.setName("At andT"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("At AndT"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryReplaceAndWithAmpersand_05() throws Exception { + resourceSubCategoryDefinition.setName(" and AttT"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("And AttT"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryReplaceAndWithAmpersand_06() throws Exception { + resourceSubCategoryDefinition.setName("AttT and "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("AttT And"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryReplaceAndWithAmpersand_07() throws Exception { + resourceSubCategoryDefinition.setName(" and a"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("And a"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationMaxLength() throws Exception { + resourceSubCategoryDefinition.setName("AsdfghjQ234567890@#.&:+-_"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationMaxLengthAfterNormalization() throws Exception { + resourceSubCategoryDefinition.setName(" A jQ234 @@@___ +++ At and T and and "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("A JQ234 @_ + At & T & And"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + // bug : + // Desc= + @Test + public void subCategoryNameValidationExceedMaxLengthAfterNormalization() throws Exception { + resourceSubCategoryDefinition.setName(" AbdfghBCVa jQ234 @@___ +++ At and T "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, + STATUS_CODE_INVALID_CONTENT, AUDIT_RESOURCE_TYPE, AUDIT_RESOURCE_TYPE, SUB_CATEGORY); + } + + @Test + public void subCategoryNameValidationMinLengthAfterNormalization() throws Exception { + resourceSubCategoryDefinition.setName(" AT&&&&&&&&&T "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("AT&T"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + // bug + // Desc= + @Test + public void subCategoryNameValidationLessThanMinLengthAfterNormalization() throws Exception { + resourceSubCategoryDefinition.setName(" A&&&T "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH, + STATUS_CODE_INVALID_CONTENT, AUDIT_RESOURCE_TYPE, AUDIT_RESOURCE_TYPE, SUB_CATEGORY); + } + + @Test + public void subCategoryNameIsEmpty() throws Exception { + resourceSubCategoryDefinition.setName(""); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, + STATUS_CODE_INVALID_CONTENT, AUDIT_RESOURCE_TYPE, AUDIT_RESOURCE_TYPE, SUB_CATEGORY); + } + + // bug + // Desc= + @Test + public void subCategoryNameValidationInvalidCharacters() throws Exception { + char invalidChars[] = { '~', '!', '$', '%', '^', '*', '(', ')', '"', '{', '}', '[', ']', '?', '>', '<', '/', + '|', '\\', ',' }; + for (int i = 0; i < invalidChars.length; i++) { + DbUtils.deleteFromEsDbByPattern("_all"); + resourceSubCategoryDefinition.setName("AbcD123" + invalidChars[i]); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_INVALID_CONTENT, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditFailure(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, + ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT, STATUS_CODE_INVALID_CONTENT, + AUDIT_RESOURCE_TYPE, AUDIT_RESOURCE_TYPE, SUB_CATEGORY); + } + } + + @Test + public void subCategoryNameValidationFirstLetterOfKeyWordsCapitalized() throws Exception { + resourceSubCategoryDefinition.setName("beNNy shaY michEl"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("BeNNy ShaY MichEl"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_01() throws Exception { + resourceSubCategoryDefinition.setName(" bank OF america "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Bank of America"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_02() throws Exception { + resourceSubCategoryDefinition.setName("THE america bank "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("THE America Bank"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_03() throws Exception { + resourceSubCategoryDefinition.setName(" A bank OF america "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("A Bank of America"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_04() throws Exception { + resourceSubCategoryDefinition.setName(" bank america is A big ban "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Bank America Is a Big Ban"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_05() throws Exception { + resourceSubCategoryDefinition.setName(" aN apple comPany inC "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("AN Apple ComPany InC"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_06() throws Exception { + resourceSubCategoryDefinition.setName(" eat AN apple ANAN"); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Eat an Apple ANAN"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_07() throws Exception { + resourceSubCategoryDefinition.setName(" united states OF americA "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("United States of AmericA"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_08() throws Exception { + resourceSubCategoryDefinition.setName(" oF united states OF amer "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("OF United States of Amer"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_09() throws Exception { + resourceSubCategoryDefinition.setName(" to Apple TO at&T TOO "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("To Apple to At&T TOO"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_10() throws Exception { + resourceSubCategoryDefinition.setName(" eat apple AS you liiikeas "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Eat Apple as You Liiikeas"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_11() throws Exception { + resourceSubCategoryDefinition.setName(" as you may want "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("As You May Want"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_12() throws Exception { + resourceSubCategoryDefinition.setName(" the bank OF america "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("The Bank of America"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_13() throws Exception { + resourceSubCategoryDefinition.setName(" To tel-toto "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("To Tel-toto"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void subCategoryNameValidationConjunctions_14() throws Exception { + resourceSubCategoryDefinition.setName(" tel-aviv To la "); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + resourceSubCategoryDefinition.setName("Tel-aviv to La"); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, resourceSubCategoryDefinition); + + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, resourceCategoryDefinition, + resourceSubCategoryDefinition, sdncAdminUserDetails, STATUS_CODE_CREATED, AUDIT_RESOURCE_TYPE); + } + + @Test + public void createSubCategoryHttpCspUserIdHeaderIsMissing() throws Exception { + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategoryHttpCspAtuUidIsMissing( + resourceSubCategoryDefinition, resourceCategoryDefinition, sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_MISSING_INFORMATION, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(ADD_SUB_CATEGORY); + expectedCatrgoryAuditJavaObject.setModifier(""); + expectedCatrgoryAuditJavaObject.setCategoryName(resourceCategoryDefinition.getUniqueId()); + // String subCategoryName = (resourceSubCategoryDefinition != null ? + // resourceSubCategoryDefinition.getName() : Constants.EMPTY_STRING); + expectedCatrgoryAuditJavaObject.setSubCategoryName(resourceSubCategoryDefinition.getName()); + // String groupingName = (groupingDefinition != null ? + // groupingDefinition.getName() : Constants.EMPTY_STRING); + expectedCatrgoryAuditJavaObject.setGroupingName(""); + expectedCatrgoryAuditJavaObject.setResourceType(AUDIT_RESOURCE_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_MISSING_INFORMATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateCategoryAudit(expectedCatrgoryAuditJavaObject, ADD_SUB_CATEGORY); + } + + @Test + public void createSubCategoryHttpCspUserIdIsEmpty() throws Exception { + User sdncAdminUserDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncAdminUserDetails1.setUserId(""); + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails1, RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after create Sub category", STATUS_CODE_MISSING_INFORMATION, + createSubCategoryRest.getErrorCode().intValue()); + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryNotExistsInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), resourceSubCategoryDefinition); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(ADD_SUB_CATEGORY); + expectedCatrgoryAuditJavaObject.setModifier(""); + expectedCatrgoryAuditJavaObject.setCategoryName(resourceCategoryDefinition.getUniqueId()); + // String subCategoryName = (resourceSubCategoryDefinition != null ? + // resourceSubCategoryDefinition.getName() : Constants.EMPTY_STRING); + expectedCatrgoryAuditJavaObject.setSubCategoryName(resourceSubCategoryDefinition.getName()); + // String groupingName = (groupingDefinition != null ? + // groupingDefinition.getName() : Constants.EMPTY_STRING); + expectedCatrgoryAuditJavaObject.setGroupingName(""); + expectedCatrgoryAuditJavaObject.setResourceType(AUDIT_RESOURCE_TYPE); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(STATUS_CODE_MISSING_INFORMATION)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + AuditValidationUtils.validateCategoryAudit(expectedCatrgoryAuditJavaObject, ADD_SUB_CATEGORY); + } + + //////////////////////////////////////////////////////////// + private void createSubCategorySuccess(CategoryDefinition categoryDefinition, + SubCategoryDefinition subCategoryDefinition, User sdncAdminUserDetails, String componentType, + String auditType) throws Exception { + + RestResponse createSubCategoryRest = CategoryRestUtils.createSubCategory(subCategoryDefinition, + categoryDefinition, sdncAdminUserDetails, componentType); + assertEquals("Check response code after create Sub category", STATUS_CODE_CREATED, + createSubCategoryRest.getErrorCode().intValue()); + CategoryValidationUtils.validateCreateSubCategoryResponse(createSubCategoryRest, subCategoryDefinition); + // Audit validation + AuditValidationUtils.subCategoryAuditSuccess(ADD_SUB_CATEGORY, categoryDefinition, subCategoryDefinition, + sdncAdminUserDetails, STATUS_CODE_CREATED, auditType); + // get service category and validate that category added as defined + // (also set catalog uniqeId) + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, componentType); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + categoryDefinition.getUniqueId(), subCategoryDefinition); // also + // set + // catalog + // uniqeId + } + + @Test + public void getResourceCategoryHierarchySuccessFlow() throws Exception { + int numOfSubCategories = 3; + List subCategories = new ArrayList(); + RestResponse restResponse; + SubCategoryDefinition subCategory; + String subName = resourceSubCategoryDefinition.getName(); + for (int i = 0; i < numOfSubCategories; i++) { + resourceSubCategoryDefinition.setName(subName + i); + restResponse = CategoryRestUtils.createSubCategory(resourceSubCategoryDefinition, + resourceCategoryDefinition, sdncAdminUserDetails, RESOURCE_COMPONENT_TYPE); + subCategory = ResponseParser.parseToObject(restResponse.getResponse(), SubCategoryDefinition.class); + subCategories.add(subCategory); + } + RestResponse getAllCategoriesRest = CategoryRestUtils.getAllCategories(sdncAdminUserDetails, + RESOURCE_COMPONENT_TYPE); + assertEquals("Check response code after get all categories ", STATUS_CODE_SUCCESS, + getAllCategoriesRest.getErrorCode().intValue()); + AuditValidationUtils.GetCategoryHierarchyAuditSuccess(GET_CATEGORY_HIERARCHY, AUDIT_RESOURCE_TYPE, + sdncAdminUserDetails, STATUS_CODE_SUCCESS); + for (SubCategoryDefinition sub : subCategories) { + CategoryValidationUtils.verifySubCategoryExistInGetResponse(getAllCategoriesRest, + resourceCategoryDefinition.getUniqueId(), sub); + } + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/AndreyTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/AndreyTest.java new file mode 100644 index 0000000000..8a5fe91065 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/AndreyTest.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.devCI; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.GroupHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.TypeHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaDefinition; +import org.openecomp.sdc.ci.tests.utils.CsarParserUtils; +import org.openecomp.sdc.ci.tests.utils.ToscaParserUtils; +import org.openecomp.sdc.tosca.parser.api.ISdcCsarHelper; +import org.openecomp.sdc.tosca.parser.exceptions.SdcToscaParserException; +import org.openecomp.sdc.tosca.parser.impl.SdcToscaParserFactory; +//import org.openecomp.sdc.toscaparser.api.Metadata; +import org.openecomp.sdc.toscaparser.api.Capability; +import org.openecomp.sdc.toscaparser.api.NodeTemplate; +import org.openecomp.sdc.toscaparser.api.common.JToscaException; +import org.testng.annotations.Test; + +public class AndreyTest { + + public static void main(String[] args) throws Exception { + ToscaDefinition toscaDefinition; + System.out.println("start " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date())); +// File path = new File("C:/Data/D2.0/TOSCA_Ex/Definitions/tosca_definition_version.yaml"); +// File path = new File("C:/Data/D2.0/TOSCA_Ex/resource-Vl11Vl10-template.yml"); + File path = new File("C:/Data/D2.0/TOSCA_Ex/service-Servicepxtc-template US822998.yml"); + File csarPath = new File("C:/Data/D2.0/TOSCA_Ex/Nested.csar"); + + toscaDefinition = ToscaParserUtils.parseToscaYamlToJavaObject(path); + System.out.println("listTypeHeatMetaDefinition start " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date())); + List listTypeHeatMetaDefinition = CsarParserUtils.getListTypeHeatMetaDefinition(csarPath); + System.out.println("get service start " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date())); + System.out.println(listTypeHeatMetaDefinition); + for(TypeHeatMetaDefinition typeHeatMetaDefinition : listTypeHeatMetaDefinition){ + for(GroupHeatMetaDefinition groupHeatMetaDefinition : typeHeatMetaDefinition.getGroupHeatMetaDefinition()){ + List artifactList = groupHeatMetaDefinition.getArtifactList(); + boolean isBase = groupHeatMetaDefinition.getPropertyHeatMetaDefinition().getValue(); + } + + } + System.out.println("Finished"); + System.out.println("get service start " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date())); + } + + + @Test + public void distributionTest() throws SdcToscaParserException, JToscaException, IOException { + //String serviceName = import and create().getName(); + //getServiceObject(); + //parseServiceObject(); + + + + SdcToscaParserFactory factory = SdcToscaParserFactory.getInstance(); + long startTime = System.currentTimeMillis(); + long estimatedTime = System.currentTimeMillis() - startTime; + System.out.println("Time to init factory " + estimatedTime); + String fileStr1 = "src//test//resources//CI//csars//service-ServiceFdnt-csar-0904-2.csar";//ToscaParserStubsTest.class.getClassLoader().getResource("csars/service-ServiceFdnt-csar-0904-2.csar").getFile(); + File file1 = new File(fileStr1); + String name = file1.getName(); + String absolutePath = file1.getAbsolutePath(); + ISdcCsarHelper fdntCsarHelper = factory.getSdcCsarHelper(file1.getAbsolutePath()); + + List serviceVfList = fdntCsarHelper.getServiceVfList(); + serviceVfList.size(); + for (NodeTemplate nodeTemplate : serviceVfList) { + ArrayList requirements = nodeTemplate.getRequirements(); + requirements.size(); + LinkedHashMap capabilities = nodeTemplate.getCapabilities(); + ArrayList requirements2 = nodeTemplate.getRequirements(); + + System.out.println(nodeTemplate.getName()); + } + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ArtifactFromCsar.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ArtifactFromCsar.java new file mode 100644 index 0000000000..c3346952b2 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ArtifactFromCsar.java @@ -0,0 +1,301 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.devCI; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.openecomp.sdc.ci.tests.datatypes.GroupHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.TypeHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.utils.CsarParserUtils; + +public class ArtifactFromCsar { + + + public static void main(String[] args) throws Exception { + // TODO Auto-generated method stub + String zipFile = "C:\\Users\\rp955r\\Documents\\InTesting\\resource-CivfonboardedFdnt2f792348-csar.csar"; + +// Map combinedMap = combineHeatArtifacstWithFolderArtifacsToMap(zipFile); + + Map vfcArtifacts = ArtifactFromCsar.getVFCArtifacts(zipFile); + + System.out.println("1234o"); + } + + public static Map combineHeatArtifacstWithFolderArtifacsToMap(String pathToCsar) throws Exception { + return combineHeatArtifacstWithFolderArtifacsToMap(pathToCsar, "output"); + } + + public static Map combineHeatArtifacstWithFolderArtifacsToMap(String pathToCsar, String outputCsar) throws Exception { + File csarFile = new File(pathToCsar); + + + File dir = new File(csarFile.getParent() + File.separator + outputCsar); + dir.mkdir(); + if(!dir.exists()) { + } + + String outputFolder = dir.getPath(); + unZip(pathToCsar, outputFolder); + File directory = new File(outputFolder + File.separator + "Artifacts" + File.separator ); + + Map artifactsMap = combineHeatArtifacstWithFolderArtifacsToMap(getMapArtifactFromFolderStructure(directory), getDeploymentArtifactListFromHeatMeta(csarFile, directory)); + FileUtils.cleanDirectory(new File(outputFolder)); + + return artifactsMap; + } + + public static Map getVFCArtifacts(String pathToCsar) throws Exception{ + String outputFolder = unzipCsarFile(pathToCsar); + File directory = new File(outputFolder + File.separator + "Artifacts" + File.separator ); + Map artifactsMap = getMapArtifactFromFolderStructure(directory); + cleanFolders(outputFolder); + + return artifactsMap; + } + + private static Map combineHeatArtifacstWithFolderArtifacsToMap(Map map, List rlist) { + if(map.get("Deployment") != null) { + rlist.addAll((Collection) map.get("Deployment")); + } + map.put("Deployment", rlist); + return map; + } + + private static List getDeploymentArtifactListFromHeatMeta(File pathToCsar, File directory) throws Exception { + List artifactList = new LinkedList(); + + List listTypeHeatMetaDefinition = CsarParserUtils.getListTypeHeatMetaDefinition(pathToCsar); + + for(TypeHeatMetaDefinition typeHeatMetaDefinition : listTypeHeatMetaDefinition){ + for(GroupHeatMetaDefinition groupHeatMetaDefinition : typeHeatMetaDefinition.getGroupHeatMetaDefinition()){ + artifactList.addAll(groupHeatMetaDefinition.getArtifactList()); + } + } + + List listArtifactWithTypesByList = getListArtifactWithTypesByList(directory, artifactList); + return listArtifactWithTypesByList; +// return artifactList; + + } + + private static Map getMapArtifactFromFolderStructure(File pathToArtifactFolder) throws IOException { + + Map map = new HashMap(); + + + final Path dir = Paths.get(pathToArtifactFolder.getPath()); + final DirectoryStream dirStream = Files.newDirectoryStream(dir); + + dirStream.forEach(currFile -> { + File file = currFile.toFile(); + if (file.isDirectory()) { + System.out.println(file.getName()); + if(file.getName().toLowerCase().equals("deployment") || file.getName().toLowerCase().equals("informational")) { + map.put(file.getName(), getListArtifactWithTypes(file)); + } else { + try { + map.put(file.getName(), getMapArtifactFromFolderStructure(file)); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + }); + + dirStream.close(); + + + +// +// File[] fileList = pathToArtifactFolder.listFiles(); +// for(File file: fileList) { +// if (file.isDirectory()) { +// +// System.out.println(file.getName()); +// if(file.getName().equals("Deployment") || file.getName().equals("Informational")) { +// map.put(file.getName(), getListArtifactWithTypes(file)); +// } else { +// map.put(file.getName(), getMapArtifactFromFolderStructure(file)); +// } +// } +// } + return map; + } + + + + private static List getListArtifactWithTypes(File folderPath) { + List artifactList = new LinkedList(); + + File[] fileList = folderPath.listFiles(); + + for(File file: fileList) { + File[] artifacts = file.listFiles(); + + for(File artifact: artifacts) { +// HeatMetaFirstLevelDefinition heatMetaFirstLevelDefinition = new HeatMetaFirstLevelDefinition(file.getName(), artifact.getName()); + HeatMetaFirstLevelDefinition heatMetaFirstLevelDefinition = new HeatMetaFirstLevelDefinition(artifact.getName(), file.getName(), crunchifyGetMd5ForFile(artifact)); + artifactList.add(heatMetaFirstLevelDefinition); + } + } + + return artifactList; + } + + private static List getListArtifactWithTypesByList(File folderPath, List artifactLogicList) { + + + File[] fileList = folderPath.listFiles(); + + + + for (HeatMetaFirstLevelDefinition heatMetaFirstLevelDefinition : artifactLogicList) { + + String fileName = heatMetaFirstLevelDefinition.getFileName(); + + for (File fileFromFolder : fileList) { + if ( fileFromFolder.getName().equals(fileName)){ + heatMetaFirstLevelDefinition.setCheckSum(crunchifyGetMd5ForFile(fileFromFolder)); + } + + } + } + + return artifactLogicList; + } + + public static String crunchifyGetMd5ForFile(File crunchifyFile) { + String crunchifyValue = null; + FileInputStream crunchifyInputStream = null; + try { + crunchifyInputStream = new FileInputStream(crunchifyFile); + + // md5Hex converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order. + // The returned array will be double the length of the passed array, as it takes two characters to represent any given byte. + crunchifyValue = DigestUtils.md5Hex(IOUtils.toByteArray(crunchifyInputStream)); + } catch (IOException e) { + e.printStackTrace(); + } finally { + IOUtils.closeQuietly(crunchifyInputStream); + } + return crunchifyValue; + } + + public static void unZip(String zipFile, String outputFolder) { + byte[] buffer = new byte[1024]; + + try{ + File folder = new File(outputFolder); + + if(!folder.exists()){ + folder.mkdir(); + } + + ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile)); + ZipEntry ze = zis.getNextEntry(); + + while(ze!=null){ + + String fileName = ze.getName(); + File newFile = new File(outputFolder + File.separator + fileName); + + if(ze.isDirectory()) { + newFile.mkdir(); + ze = zis.getNextEntry(); + continue; + } + + new File(newFile.getParent()).mkdirs(); + FileOutputStream fos = new FileOutputStream(newFile); + + int len; + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + + fos.close(); + ze = zis.getNextEntry(); + } + + zis.closeEntry(); + zis.close(); + + } catch (IOException ex) { + ex.printStackTrace(); + } + + } + + private static void cleanFolders(String outputFolder) throws IOException { + System.gc(); + FileUtils.cleanDirectory(new File(outputFolder)); + FileUtils.deleteDirectory(new File(outputFolder)); + } + + private static String unzipCsarFile(String pathToCsar) { + File csarFile = new File(pathToCsar); + + + File dir = new File(csarFile.getParent() + File.separator + "output-" + UUID.randomUUID()); + if(!dir.exists()) { + dir.mkdirs(); + } + + String outputFolder = dir.getPath(); + ArtifactFromCsar.unZip(pathToCsar, outputFolder); + return outputFolder; + } + + public static String[] getArtifactNamesFromCsar(String path, String csarFile) throws Exception { + Map combinedMap = combineHeatArtifacstWithFolderArtifacsToMap(path + csarFile); + LinkedList deploymentArtifacts = ((LinkedList) combinedMap.get("Deployment")); + List artifactNamesList = deploymentArtifacts.stream().map(e -> e.getFileName()).collect(Collectors.toList()); + Object[] artifactNamesObjectArr = artifactNamesList.toArray(); + String[] artifactNamesFromFile = Arrays.copyOf(artifactNamesObjectArr, artifactNamesObjectArr.length, String[].class); + return artifactNamesFromFile; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ImportCsarUpdate.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ImportCsarUpdate.java new file mode 100644 index 0000000000..f66fd670f6 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ImportCsarUpdate.java @@ -0,0 +1,362 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.devCI; + +import static org.testng.AssertJUnit.assertTrue; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.imports.ImportCsarResourceTest; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.CsarValidationUtils; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class ImportCsarUpdate extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public ImportCsarUpdate() { + super(name, ImportCsarUpdate.class.getName()); + } + + @DataProvider(name = "happyArts") + public Object[][] getHappyArtifacts() { + + return new Object[][] { { "happy_VF_RI2_G2_two_different_artifacts_under_heatBaseheatVolheatNet2" }, + { "happy_VF_RI2_G2_two_different_artifacts_under_heatBaseheatVolheatNet" }, + { "happy_VF_RI2_G2_two_identical_artifacts_under_heatBaseheatVolheatNet" }, + { "happy_VF_RI2_G2_two_different_artifacts_under_nested" }, + { "happy_VF_RI2_G2_two_indentical_nested_under_different_groups" }, + { "happy_VF_RI2_G2_two_different_nested_under_different_groups" }, + { "happy_VF_RI2_G2_two_different_nested_under_same_group" }, + + }; + } + + @DataProvider(name = "negativeArts") + public Object[][] getNegativeArtifacts() { + + return new Object[][] { + + { "negative_VF_RI2_G2_same_heatVol_different_groups" }, + { "negative_VF_RI2_G2_same_heatBase_different_envs" }, + { "negative_VF_RI2_G2_heatBaseHeatVolHeatNet_under_nested" }, + { "negative_VF_RI2_G2_two_indentical_artifacts_under_nested" }, + { "negative_VF_RI2_G2_nested_under_nested" }, { "negative_VF_RI2_G2_same_heatVol_different_groups" }, }; + } + + @BeforeTest + public void resumeOrigCsarBefore() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, "orig.csar", "importCsar_2Gartifacts.csar"); + + } + + @AfterTest + public void resumeOrigCsarAfter() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, "orig.csar", "importCsar_2Gartifacts.csar"); + + } + + @Test + public void updateVFsearchByCsarIdCheckInState() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("hardcodedName"); + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceFirstImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + Component resourceObject = AtomicOperationUtils + .changeComponentState(resourceFirstImport, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true) + .getLeft(); + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "updateImportCsar_2Gartifacts_topologyChanged.csar", "importCsar_2Gartifacts.csar"); + + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceSecondImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + + // Validation Part + + resourceFirstImport.getGroups().equals(resourceSecondImport.getGroups()); + + } + + @Test + public void updateVFsearchByCsarIdCheckInState_checkSum() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("hardcodedName"); + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceFirstImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + Component resourceObject = AtomicOperationUtils + .changeComponentState(resourceFirstImport, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true) + .getLeft(); + + // User sdncModifierDetails = + // ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // RestResponse copyRes = + // ImportCsarResourceTest.copyCsarRest(sdncModifierDetails,"updateImportCsar_2Gartifacts_topologyChanged.csar","importCsar_2Gartifacts.csar"); + + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceSecondImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + + // Validation Part + + resourceFirstImport.getGroups().equals(resourceSecondImport.getGroups()); + + } + + @Test + public void updateVFsearchByCsarIdCheckOutState() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("hardcodedName"); + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceFirstImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + // Component resourceObject = + // AtomicOperationUtils.changeComponentState(resourceFirstImport, + // UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "updateImportCsar_2Gartifacts_topologyChanged.csar", "importCsar_2Gartifacts.csar"); + + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceSecondImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + + // Validation Part + + resourceFirstImport.getGroups().equals(resourceSecondImport.getGroups()); + + } + + @Test + public void updateVFsearchByCsarIdCertifyStat() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("hardcodedName"); + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceFirstImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + Component resourceObject = AtomicOperationUtils + .changeComponentState(resourceFirstImport, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true) + .getLeft(); + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "updateImportCsar_2Gartifacts_topologyChanged.csar", "importCsar_2Gartifacts.csar"); + + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceSecondImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + + // Validation Part + + resourceFirstImport.getGroups().equals(resourceSecondImport.getGroups()); + + } + + @Test + public void updateVFsearchByCsarStartCertifaicationState() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("hardcodedName"); + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceFirstImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + Component resourceObject = AtomicOperationUtils.changeComponentState(resourceFirstImport, UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CERTIFICATIONREQUEST, true).getLeft(); + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "updateImportCsar_2Gartifacts_topologyChanged.csar", "importCsar_2Gartifacts.csar"); + + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceSecondImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + + // Validation Part + + resourceFirstImport.getGroups().equals(resourceSecondImport.getGroups()); + + } + + @Test + public void updateVFsearchBySystemNameCheckInState() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("hardcodedName"); + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceFirstImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + Component resourceObject = AtomicOperationUtils + .changeComponentState(resourceFirstImport, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true) + .getLeft(); + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "updateImportCsar_2Gartifacts_topologyChanged.csar", "importCsar_2Gartifacts.csar"); + + resourceDetails.setName("hardcodedNameChanged"); + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceSecondImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + + // Validation Part + + resourceFirstImport.getGroups().equals(resourceSecondImport.getGroups()); + + } + + @Test + public void updateVFsearchBySystemNameCertifyState() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("hardcodedName"); + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceFirstImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + Component resourceObject = AtomicOperationUtils + .changeComponentState(resourceFirstImport, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true) + .getLeft(); + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "updateImportCsar_2Gartifacts_topologyChanged.csar", "importCsar_2Gartifacts.csar"); + + resourceDetails.setName("hardcodedNameChanged"); + resourceDetails.setCsarUUID("importCsar_2Gartifacts"); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + } + + @Test + public void updateVFsearchBySystemNameCsarIdNotExist() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("hardcodedName"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceFirstImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + Component resourceObject = AtomicOperationUtils + .changeComponentState(resourceFirstImport, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true) + .getLeft(); + // User sdncModifierDetails = + // ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // RestResponse copyRes = + // ImportCsarResourceTest.copyCsarRest(sdncModifierDetails,"updateImportCsar_2Gartifacts_topologyChanged.csar","importCsar_2Gartifacts.csar"); + ResourceReqDetails resourceDetails2 = ElementFactory.getDefaultResource(); + resourceDetails2.setName("hardcodedName"); + resourceDetails2.setCsarUUID("importCsar_2Gartifacts"); + resourceDetails2.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails2, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resourceSecondImport = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + + // Validation Part + + resourceFirstImport.getGroups().equals(resourceSecondImport.getGroups()); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ImportCsarValidateArtifacts.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ImportCsarValidateArtifacts.java new file mode 100644 index 0000000000..5ed71e53b0 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ImportCsarValidateArtifacts.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.devCI; + +import static org.testng.AssertJUnit.assertTrue; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.CsarValidationUtils; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class ImportCsarValidateArtifacts extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public ImportCsarValidateArtifacts() { + super(name, ImportCsarValidateArtifacts.class.getName()); + } + + @DataProvider(name = "happyArts") + public Object[][] getHappyArtifacts() { + + return new Object[][] { { "happy_VF_RI2_G2_two_different_artifacts_under_heatBaseheatVolheatNet2" }, + { "happy_VF_RI2_G2_two_different_artifacts_under_heatBaseheatVolheatNet" }, + { "happy_VF_RI2_G2_two_identical_artifacts_under_heatBaseheatVolheatNet" }, + { "happy_VF_RI2_G2_two_different_artifacts_under_nested" }, + { "happy_VF_RI2_G2_two_indentical_nested_under_different_groups" }, + { "happy_VF_RI2_G2_two_different_nested_under_different_groups" }, + { "happy_VF_RI2_G2_two_different_nested_under_same_group" }, + + }; + } + + @DataProvider(name = "negativeArts") + public Object[][] getNegativeArtifacts() { + + return new Object[][] { + + { "negative_VF_RI2_G2_same_heatVol_different_groups" }, + { "negative_VF_RI2_G2_same_heatBase_different_envs" }, + { "negative_VF_RI2_G2_heatBaseHeatVolHeatNet_under_nested" }, + { "negative_VF_RI2_G2_two_indentical_artifacts_under_nested" }, + { "negative_VF_RI2_G2_nested_under_nested" }, { "negative_VF_RI2_G2_same_heatVol_different_groups" }, }; + } + + @Test(dataProvider = "happyArts") + public void createResourceFromCsarArtsHappy(String artifactName) throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(artifactName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + CsarValidationUtils.validateCsarVfArtifact(artifactName, resource); + + } + + @Test(dataProvider = "negativeArts") + public void createResourceFromCsarArtsNegative(String artifactName) throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(artifactName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + assertTrue(createResource.getErrorCode() != 201 && createResource.getErrorCode() != 500); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ToscaGroupInsideVF.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ToscaGroupInsideVF.java new file mode 100644 index 0000000000..64df976c09 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/ToscaGroupInsideVF.java @@ -0,0 +1,580 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.devCI; + +import static org.testng.AssertJUnit.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.tuple.Pair; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaDefinition; +import org.openecomp.sdc.ci.tests.utils.ToscaParserUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.CsarValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +public class ToscaGroupInsideVF extends ComponentBaseTest { + private static Logger logger = LoggerFactory.getLogger(ToscaGroupInsideVF.class.getName()); + + @Rule + public static TestName name = new TestName(); + + public ToscaGroupInsideVF() { + super(name, ToscaGroupInsideVF.class.getName()); + } + + /*@Test + public void createResourceFromCsarArts() throws Exception { + + // String csar = getCsar(); + // parseCsar(csar); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("VF_RI2_G6_withArtifacts"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + Component resourceObject = AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + Resource vfManual = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true) + .left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, vfManual, UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.changeComponentState(vfManual, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true) + .getLeft(); + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils + .addComponentInstanceToComponentContainer(resourceObject, service, UserRoleEnum.DESIGNER, true).left() + .value(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(vfManual, service, UserRoleEnum.DESIGNER, true) + .left().value(); + AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + AtomicOperationUtils + .changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true) + .getLeft(); + AtomicOperationUtils + .changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CANCELCERTIFICATION, true) + .getLeft(); + AtomicOperationUtils + .changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true) + .getLeft(); + + } + + @Test + public void soferTest() throws Exception { + + // String csar = getCsar(); + // parseCsar(csar); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("sofer"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + } + + @Test + public void createVFwith2VLs() throws Exception { + + // String csar = getCsar(); + // parseCsar(csar); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("VSPPackage"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + Component resourceObject = AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + Resource vfManual = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true) + .left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, vfManual, UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.changeComponentState(vfManual, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true) + .getLeft(); + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils + .addComponentInstanceToComponentContainer(resourceObject, service, UserRoleEnum.DESIGNER, true).left() + .value(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(vfManual, service, UserRoleEnum.DESIGNER, true) + .left().value(); + AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + AtomicOperationUtils + .changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true) + .getLeft(); + AtomicOperationUtils + .changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CANCELCERTIFICATION, true) + .getLeft(); + AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true) + .getLeft(); + + } + + @Test // (enabled = false) + public void createResourceFromCsarHappy() throws Exception { + // String csarUUID = "VF_RI2_G2_withArtifacts"; + String csarUUID = "VF_RI2_G1_Invalid"; + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + CsarValidationUtils.validateCsarVfArtifact(csarUUID, resource); + } + + @Test // (enabled = false) + public void createResourceFromCsarWithProperty() throws Exception { + String csarUUID = "VF_RI2_G4_withArtifacts"; + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + CsarValidationUtils.validateCsarVfArtifact(csarUUID, resource); + } + + @Test // (enabled = false) + public void UpdateCsarWithNonExistingResourceInstanceFail() throws Exception { + + // String csarUUID = "VF_RI2_G1-RI_NotExist"; + // String csarUUID = "nested3"; + + // String csarUUID = "VF_RI2_G1_Invalid_WithArtifacts"; + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + RestResponse copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", + "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + String csarUUID = "VF_RI2_G4_withArtifacts.csar"; + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifactsRI_FAIL.csar", + "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + + resourceDetails.setName(resource.getName()); + // resourceDetails.setVendorName("Govnuk"); + // resourceDetails.setDescription("Other"); + RestResponse createResource2 = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource2); + Resource resource2 = ResponseParser.parseToObjectUsingMapper(createResource2.getResponse(), Resource.class); + + CsarValidationUtils.validateCsarVfArtifact(csarUUID, resource); + ToscaDefinition toscaDefinition = ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID); + CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition, resource); + + // CsarValidationUtils.validateCsarVfArtifact(csarUUID2, resource2); + // ToscaDefinition toscaDefinition2 = + // ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID2); + // CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition2, + // resource2); + + // Csar csar = parserTocsarObject(csarUUID); + // validateCsarVsResourceObj(csar, resource); + // csar.node_types(); + + } + + @Test // (enabled = false) + public void UpdateCsarWithSameCsarDifferentMetadata() throws Exception { + + // User sdncModifierDetails = + // ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // RestResponse copyRes = + // copyCsarRest(sdncModifierDetails,"VF_RI2_G4_withArtifacts_a.csar","VF_RI2_G4_withArtifacts.csar"); + // BaseRestUtils.checkSuccess(copyRes); + String csarUUID = "VF_RI2_G4_withArtifacts.csar"; + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + resourceDetails.setName(resource.getName()); + resourceDetails.setVendorName("Govnuk"); + resourceDetails.setDescription("Other"); + RestResponse createResource2 = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource2); + Resource resource2 = ResponseParser.parseToObjectUsingMapper(createResource2.getResponse(), Resource.class); + + CsarValidationUtils.validateCsarVfArtifact(csarUUID, resource); + ToscaDefinition toscaDefinition = ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID); + CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition, resource); + + // CsarValidationUtils.validateCsarVfArtifact(csarUUID2, resource2); + // ToscaDefinition toscaDefinition2 = + // ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID2); + // CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition2, + // resource2); + + // Csar csar = parserTocsarObject(csarUUID); + // validateCsarVsResourceObj(csar, resource); + // csar.node_types(); + + } + + @Test // (enabled = false) + public void UpdateCsarWithSameCsar() throws Exception { + + // User sdncModifierDetails = + // ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // RestResponse copyRes = + // copyCsarRest(sdncModifierDetails,"VF_RI2_G4_withArtifacts_a.csar","VF_RI2_G4_withArtifacts.csar"); + // BaseRestUtils.checkSuccess(copyRes); + String csarUUID = "VF_RI2_G4_withArtifacts.csar"; + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + resourceDetails.setName(resource.getName()); + RestResponse createResource2 = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource2); + Resource resource2 = ResponseParser.parseToObjectUsingMapper(createResource2.getResponse(), Resource.class); + + CsarValidationUtils.validateCsarVfArtifact(csarUUID, resource); + ToscaDefinition toscaDefinition = ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID); + CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition, resource); + + // CsarValidationUtils.validateCsarVfArtifact(csarUUID2, resource2); + // ToscaDefinition toscaDefinition2 = + // ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID2); + // CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition2, + // resource2); + + // Csar csar = parserTocsarObject(csarUUID); + // validateCsarVsResourceObj(csar, resource); + // csar.node_types(); + + } + + @Test // (enabled = false) + public void UpdateCsarCertifiedVfWithSameCsar() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", + "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + String csarUUID = "VF_RI2_G4_withArtifacts.csar"; + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + Pair changeComponentState = AtomicOperationUtils.changeComponentState(resource, + UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + resource = (Resource) changeComponentState.getLeft(); + + resourceDetails.setName(resource.getName()); + RestResponse createResource2 = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource2); + Resource resource2 = ResponseParser.parseToObjectUsingMapper(createResource2.getResponse(), Resource.class); + + CsarValidationUtils.validateCsarVfArtifact(csarUUID, resource); + ToscaDefinition toscaDefinition = ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID); + CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition, resource); + + // CsarValidationUtils.validateCsarVfArtifact(csarUUID2, resource2); + // ToscaDefinition toscaDefinition2 = + // ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID2); + // CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition2, + // resource2); + + // Csar csar = parserTocsarObject(csarUUID); + // validateCsarVsResourceObj(csar, resource); + // csar.node_types(); + + } + + @Test // (enabled = false) + public void UpdateCsarDifferentTosca() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", + "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + String csarUUID = "VF_RI2_G4_withArtifacts.csar"; + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifactsUpdated.csar", + "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + + resourceDetails.setName(resource.getName()); + RestResponse createResource2 = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource2); + Resource resource2 = ResponseParser.parseToObjectUsingMapper(createResource2.getResponse(), Resource.class); + + CsarValidationUtils.validateCsarVfArtifact(csarUUID, resource); + ToscaDefinition toscaDefinition = ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID); + CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition, resource); + + // CsarValidationUtils.validateCsarVfArtifact(csarUUID2, resource2); + // ToscaDefinition toscaDefinition2 = + // ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID2); + // CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition2, + // resource2); + + // Csar csar = parserTocsarObject(csarUUID); + // validateCsarVsResourceObj(csar, resource); + // csar.node_types(); + + } + + @Test // (enabled = false) + public void UpdateCsarDifferentToscaAndArtifacts() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", + "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + String csarUUID = "VF_RI2_G4_withArtifacts.csar"; + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_UpdateToscaAndArtifacts.csar", + "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + + resourceDetails.setName(resource.getName()); + RestResponse createResource2 = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource2); + Resource resource2 = ResponseParser.parseToObjectUsingMapper(createResource2.getResponse(), Resource.class); + + CsarValidationUtils.validateCsarVfArtifact(csarUUID, resource); + ToscaDefinition toscaDefinition = ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID); + CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition, resource); + + // CsarValidationUtils.validateCsarVfArtifact(csarUUID2, resource2); + // ToscaDefinition toscaDefinition2 = + // ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID2); + // CsarValidationUtils.validateToscaDefinitonObjectVsResource(toscaDefinition2, + // resource2); + + // Csar csar = parserTocsarObject(csarUUID); + // validateCsarVsResourceObj(csar, resource); + // csar.node_types(); + + } + + @Test // (enabled = false) + public void migration() throws Exception { + String csarUUID = "VF_RI2_G4_withArtifacts"; + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setName("Resource1"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + + resourceDetails.setName("Resource2"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + + resourceDetails.setName("Resource3"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + resourceDetails.setName("Resource4"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + resourceDetails.setName("Resource5"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + + resourceDetails.setName("Resource6"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.STARTCERTIFICATION, true) + .getLeft(); + + resourceDetails.setName("Resource7"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils + .changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true) + .getLeft(); + + logger.debug("7 VF resources were created"); + + } + + public static RestResponse copyCsarRest(User sdncModifierDetails, String sourceCsarUuid, String targetCsarUuid) + throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.COPY_CSAR_USING_SIMULATOR, config.getCatalogBeHost(), config.getCatalogBePort(), + sourceCsarUuid, targetCsarUuid); + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + + RestResponse copyCsarResponse = http.httpSendPost(url, "dummy", headersMap); + if (copyCsarResponse.getErrorCode() != 200) { + return null; + } + return copyCsarResponse; + + } + + private static Map prepareHeadersMap(String userId) { + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + if (userId != null) { + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), userId); + } + return headersMap; + } + + public static void main(String[] args) throws Exception { + // String csarUUID = "VF_RI2_G4_withArtifacts"; + String csarUUID = "node_types"; + ToscaParserUtils.getToscaDefinitionObjectByCsarUuid(csarUUID); + }*/ +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/test1.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/test1.java new file mode 100644 index 0000000000..7acf1206e7 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/devCI/test1.java @@ -0,0 +1,96 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.devCI; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.DistributionNotificationStatusEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.DistributionValidationUtils; +import org.openecomp.sdc.externalApis.CRUDExternalAPI; +import org.testng.annotations.Test; + +import fj.data.Either; + +public class test1 extends ComponentBaseTest{ + + @Rule + public static TestName name = new TestName(); + + public test1() { + super(name, CRUDExternalAPI.class.getName()); + + } + + @Test() + public void uploadArtifactOnServiceViaExternalAPI() throws Exception { + Config config = Utils.getConfig(); + + Service service = AtomicOperationUtils.createServiceByCategory(ServiceCategoriesEnum.MOBILITY, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.MODEL_QUERY_SPEC, service, UserRoleEnum.DESIGNER, true, true); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + if(config.getIsDistributionClientRunning()){ + List distributionStatusList = Arrays.asList(DistributionNotificationStatusEnum.DOWNLOAD_OK.toString(), DistributionNotificationStatusEnum.DEPLOY_OK.toString(), DistributionNotificationStatusEnum.NOTIFIED.toString()); + DistributionValidationUtils.validateDistributedArtifactsByAudit(service, distributionStatusList); + } + } + + + public static Map addVNF_ModuleDeploymentArtifactToMap(Service service, Map distributionArtifactMap){ + + + return distributionArtifactMap; + } + + public Component getComponentInTargetLifeCycleState(String componentType, UserRoleEnum creatorUser, LifeCycleStatesEnum targetLifeCycleState) throws Exception { + Component component = null; + + if(componentType.toLowerCase().equals("vf")) { + Either createdResource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, creatorUser, true); + component = createdResource.left().value(); + component = AtomicOperationUtils.changeComponentState(component, creatorUser, targetLifeCycleState, true).getLeft(); + } else { + Either createdResource = AtomicOperationUtils.createDefaultService(creatorUser, true); + component = createdResource.left().value(); + component = AtomicOperationUtils.changeComponentState(component, creatorUser, targetLifeCycleState, true).getLeft(); + } + + return component; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/distribution/AuthanticationTests.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/distribution/AuthanticationTests.java new file mode 100644 index 0000000000..b4a9bb87ce --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/distribution/AuthanticationTests.java @@ -0,0 +1,186 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.distribution; + +import static org.testng.AssertJUnit.assertEquals; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedAuthenticationAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ConsumerRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class AuthanticationTests extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + protected ResourceReqDetails resourceDetails; + protected ServiceReqDetails serviceDetails; + protected User sdncUserDetails; + + protected static final String AUTH_SUCCESS = "AUTH_SUCCESS"; + + protected static final String AUTH_REQUIRED = "AUTH_REQUIRED"; + + // user ci password 123456 + // protected final String authorizationHeader = "Basic Y2k6MTIzNDU2"; + // user ci password 123456 + protected final String USER = "ci"; + protected final String PASSWORD = "123456"; + protected final String SALT = "2a1f887d607d4515d4066fe0f5452a50"; + protected final String HASHED_PASSWORD = "0a0dc557c3bf594b1a48030e3e99227580168b21f44e285c69740b8d5b13e33b"; + protected User sdncAdminUserDetails; + protected ConsumerDataDefinition consumerDataDefinition; + + public AuthanticationTests() { + super(name, AuthanticationTests.class.getName()); + } + + @DataProvider + private final Object[][] getServiceDepArtType() throws IOException, Exception { + return new Object[][] { { ArtifactTypeEnum.YANG_XML.getType() }, { ArtifactTypeEnum.OTHER.getType() } }; + } + + @BeforeMethod + public void setup() throws Exception { + resourceDetails = ElementFactory.getDefaultResource(); + serviceDetails = ElementFactory.getDefaultService(); + sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncAdminUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + createComponents(); + consumerDataDefinition = createConsumer(); + RestResponse deleteResponse = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + BaseRestUtils.checkStatusCode(deleteResponse, "delete operation filed", false, 404, 200); + ; + + RestResponse createResponse = ConsumerRestUtils.createConsumer(consumerDataDefinition, sdncAdminUserDetails); + BaseRestUtils.checkCreateResponse(createResponse); + + } + + @AfterMethod + public void tearDown() throws Exception { + RestResponse deleteResponse = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + BaseRestUtils.checkStatusCode(deleteResponse, "delete operation filed", false, 404, 200); + ; + + } + + protected ConsumerDataDefinition createConsumer() { + ConsumerDataDefinition consumer = new ConsumerDataDefinition(); + consumer.setConsumerName(USER); + consumer.setConsumerSalt(SALT); + consumer.setConsumerPassword(HASHED_PASSWORD); + return consumer; + + } + + protected void createComponents() throws Exception { + RestResponse response = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + ServiceRestUtils.checkCreateResponse(response); + } + + @Test(dataProvider = "getServiceDepArtType", description = "mumu") + public void downloadServiceArtifactSuccessWithAutantication(String serviceDepArtType) throws Exception { + String serviceUniqueId = serviceDetails.getUniqueId(); + + ArtifactReqDetails artifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(serviceDepArtType); + + RestResponse addArtifactResponse = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, + sdncUserDetails, serviceUniqueId, ArtifactRestUtils.calculateChecksum(artifactDetails)); + AssertJUnit.assertEquals("Check response code after adding interface artifact", 200, + addArtifactResponse.getErrorCode().intValue()); + + String artifactName = ValidationUtils.normalizeFileName(artifactDetails.getArtifactName()); + // Thread.sleep(5000); + Map authorizationHeaders = BaseRestUtils.addAuthorizeHeader(USER, PASSWORD); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, artifactDetails, + sdncUserDetails, authorizationHeaders); + AssertJUnit.assertEquals("Check response code after download resource", 200, + restResponse.getErrorCode().intValue()); + + List contDispHeaderList = restResponse.getHeaderFields().get(Constants.CONTENT_DISPOSITION_HEADER); + AssertJUnit.assertNotNull(contDispHeaderList); + AssertJUnit.assertEquals("Check content disposition header", + new StringBuilder().append("attachment; filename=\"").append(artifactName).append("\"").toString(), + contDispHeaderList.get(0)); + + String downloadUrl = ArtifactRestUtils + .getPartialUrlByArtifactName(serviceDetails, serviceDetails.getVersion(), artifactName).substring(6); + + ExpectedAuthenticationAudit expectedAuthenticationAudit = new ExpectedAuthenticationAudit(downloadUrl, USER, + AuditingActionEnum.AUTH_REQUEST.getName(), AUTH_SUCCESS); + AuditValidationUtils.validateAuthenticationAudit(expectedAuthenticationAudit); + } + + @Test(dataProvider = "getServiceDepArtType") + public void downloadServiceArtifactWithOutAutantication(String serviceDepArtType) throws Exception { + String serviceUniqueId = serviceDetails.getUniqueId(); + + ArtifactReqDetails artifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(serviceDepArtType); + + RestResponse addArtifactResponse = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, + sdncUserDetails, serviceUniqueId, ArtifactRestUtils.calculateChecksum(artifactDetails)); + assertEquals("Check response code after adding interface artifact", 200, + addArtifactResponse.getErrorCode().intValue()); + + Map authorizationHeaders = new HashMap(); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, artifactDetails, + sdncUserDetails, authorizationHeaders); + assertEquals("Check response code after download resource failure", 401, + restResponse.getErrorCode().intValue()); + + String downloadUrl = ArtifactRestUtils.getPartialUrlByArtifactName(serviceDetails, serviceDetails.getVersion(), + artifactDetails.getArtifactName()).substring(6); + ExpectedAuthenticationAudit expectedAuthenticationAudit = new ExpectedAuthenticationAudit(downloadUrl, "", + AuditingActionEnum.AUTH_REQUEST.getName(), AUTH_REQUIRED); + AuditValidationUtils.validateAuthenticationAudit(expectedAuthenticationAudit); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/distribution/DistributionDownloadArtifactTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/distribution/DistributionDownloadArtifactTest.java new file mode 100644 index 0000000000..7ba705fc7d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/distribution/DistributionDownloadArtifactTest.java @@ -0,0 +1,537 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.distribution; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipInputStream; + +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.lf5.util.ResourceUtils; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedDistDownloadAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ConsumerRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class DistributionDownloadArtifactTest extends ComponentBaseTest { + + protected static ResourceReqDetails resourceDetails; + protected static User designerUser; + protected static User adminUser; + protected static String resourceBaseVersion; + // user ci password 123456 + protected final String authorizationHeader = "Basic Y2k6MTIzNDU2"; + protected ConsumerDataDefinition consumerDataDefinition; + + @Rule + public static TestName name = new TestName(); + protected static String artifactInterfaceType; + protected static String artifactOperationName; + + protected static ServiceReqDetails serviceDetails; + protected static String serviceBaseVersion; + protected static String serviceUniqueId; + protected final String USER = "ci"; + protected final String PASSWORD = "123456"; + protected final String SALT = "2a1f887d607d4515d4066fe0f5452a50"; + protected final String HASHED_PASSWORD = "0a0dc557c3bf594b1a48030e3e99227580168b21f44e285c69740b8d5b13e33b"; + + public DistributionDownloadArtifactTest() { + super(name, DistributionDownloadArtifactTest.class.getName()); + } + + // @BeforeClass + // public static void InitBeforeTest() throws Exception + // { + // + // + // resourceBaseVersion = "0.1"; + // serviceBaseVersion = "0.1"; + // designerUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // adminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // resourceDetails = + // ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + // NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, + // adminUser); + // serviceDetails = ElementFactory.getDefaultService(); + // serviceUniqueId = "svc_" + serviceDetails.getName().toLowerCase() + "." + + // serviceBaseVersion; + // artifactInterfaceType = "standard"; + // artifactOperationName = "start"; + // } + + @BeforeMethod + public void setup() throws Exception { + + resourceBaseVersion = "0.1"; + serviceBaseVersion = "0.1"; + designerUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + adminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + resourceDetails = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, adminUser); + serviceDetails = ElementFactory.getDefaultService(); + serviceUniqueId = "svc_" + serviceDetails.getName().toLowerCase() + "." + serviceBaseVersion; + artifactInterfaceType = "standard"; + artifactOperationName = "start"; + consumerDataDefinition = createConsumer(); + RestResponse deleteResponse = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, adminUser); + BaseRestUtils.checkStatusCode(deleteResponse, "delete operation filed", false, 404, 200); + + RestResponse createResponse = ConsumerRestUtils.createConsumer(consumerDataDefinition, adminUser); + BaseRestUtils.checkCreateResponse(createResponse); + } + + @Test + public void downloadResourceArtifactSuccess() throws Exception { + // Create service + RestResponse serviceResponse = ServiceRestUtils.createService(serviceDetails, designerUser); + AssertJUnit.assertEquals("Check response code after creating resource", 201, + serviceResponse.getErrorCode().intValue()); + + // Create resource + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, designerUser); + AssertJUnit.assertEquals("Check response code after creating resource", 201, + createResource.getErrorCode().intValue()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(createResource.getResponse()); + + ArtifactReqDetails artifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + // Setting the name to be with space + artifactDetails.setArtifactName("test artifact file.yaml"); + // artifactDetails.set(ArtifactRestUtils.calculateChecksum(artifactDetails)); + + RestResponse addArtifactResponse = ArtifactRestUtils.addInformationalArtifactToResource(artifactDetails, + designerUser, resource.getUniqueId(), ArtifactRestUtils.calculateChecksum(artifactDetails)); + AssertJUnit.assertEquals("Check response code after adding interface artifact", 200, + addArtifactResponse.getErrorCode().intValue()); + + // Getting expected artifact checksum + ArtifactDefinition artifactResp = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(addArtifactResponse.getResponse()); + String expectedPayloadChecksum = artifactResp.getArtifactChecksum(); + + Config config = Utils.getConfig(); + String relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceDetails.getName()), serviceBaseVersion, + ValidationUtils.convertToSystemName(resource.getName()), resource.getVersion(), + artifactResp.getArtifactName())); + // String fullUrlFormatted = + // String.format(Urls.DOWNLOAD_RESOURCE_ARTIFACT_FULL_URL, + // config.getCatalogBeHost(),config.getCatalogBePort(), relativeUrl); + // String consumerId = "dummy.ecomp"; + + ResourceReqDetails resourceInfo = new ResourceReqDetails(); + resourceInfo.setName(resource.getName()); + resourceInfo.setVersion(resource.getVersion()); + + Map authorizationHeaders = new HashMap(); + authorizationHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + RestResponse restResponse = ArtifactRestUtils.downloadResourceArtifact(serviceDetails, resourceInfo, + artifactDetails, designerUser, authorizationHeaders); + // RestResponse restResponse = + // artifactUtils.downloadResourceArtifact(designerUser,fullUrlFormatted, + // consumerId,true); + AssertJUnit.assertEquals("Check response code after download resource", 200, + restResponse.getErrorCode().intValue()); + + // Validating headers + // content disposition + List contDispHeaderList = restResponse.getHeaderFields().get(Constants.CONTENT_DISPOSITION_HEADER); + AssertJUnit.assertNotNull(contDispHeaderList); + AssertJUnit + .assertEquals( + "Check content disposition header", new StringBuilder().append("attachment; filename=\"") + .append(artifactResp.getArtifactName()).append("\"").toString(), + contDispHeaderList.get(0)); + + // content type + List contTypeHeaderList = restResponse.getHeaderFields().get(Constants.CONTENT_TYPE_HEADER); + AssertJUnit.assertNotNull(contTypeHeaderList); + AssertJUnit.assertEquals("Check content type", "application/octet-stream", contTypeHeaderList.get(0)); + + String actualContents = restResponse.getResponse(); + + // Contents - comparing decoded content + AssertJUnit.assertEquals(artifactDetails.getPayload(), Base64.encodeBase64String(actualContents.getBytes())); + + // validating checksum + String actualPayloadChecksum = GeneralUtility.calculateMD5ByByteArray(actualContents.getBytes()); + AssertJUnit.assertEquals(expectedPayloadChecksum, actualPayloadChecksum); + + // validate audit + String auditAction = "DArtifactDownload"; + + ExpectedDistDownloadAudit expectedDistDownloadAudit = new ExpectedDistDownloadAudit(auditAction, + BaseRestUtils.ecomp, relativeUrl, "200", "OK"); + AuditValidationUtils.validateAudit(expectedDistDownloadAudit, auditAction); + } + + protected void download_serviceNameNotFound_inner(String serviceName, String serviceVersion, String resourceName, + String resourceVersion) throws Exception { + Config config = Utils.getConfig(); + String artifactName = "kuku"; + ArtifactReqDetails artifact = new ArtifactReqDetails(); + artifact.setArtifactName(artifactName); + String relativeUrl; + Map authorizationHeaders = new HashMap(); + authorizationHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + ServiceReqDetails serviceInfo = new ServiceReqDetails(); + serviceInfo.setName(serviceName); + serviceInfo.setVersion(serviceVersion); + RestResponse restResponse = null; + if (resourceName != null) { + ResourceReqDetails resourceDetailes = new ResourceReqDetails(); + resourceDetailes.setName(resourceName); + resourceDetailes.setVersion(resourceVersion); + relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceName), serviceVersion, + ValidationUtils.convertToSystemName(resourceName), resourceVersion, artifactName)); + restResponse = ArtifactRestUtils.downloadResourceArtifact(serviceInfo, resourceDetailes, artifact, + designerUser, authorizationHeaders); + } else { + relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_SERVICE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceName), serviceVersion, artifactName)); + restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceInfo, artifact, designerUser, + authorizationHeaders); + } + + // RestResponse restResponse = + // artifactUtils.downloadResourceArtifact(designerUser,fullUrlFormatted, + // consumerId,true); + AssertJUnit.assertEquals("Check response code after download resource", 404, + restResponse.getErrorCode().intValue()); + + // validate audit + String auditAction = "DArtifactDownload"; + + ExpectedDistDownloadAudit expectedDistDownloadAudit = new ExpectedDistDownloadAudit(auditAction, + BaseRestUtils.ecomp, relativeUrl, "404", "SVC4503: Error: Requested '" + + ValidationUtils.convertToSystemName(serviceName) + "' service was not found."); + AuditValidationUtils.validateAudit(expectedDistDownloadAudit, auditAction); + } + + protected void download_serviceVersionNotFound_inner(String serviceName, String serviceVersion, String resourceName, + String resourceVersion) throws Exception { + Config config = Utils.getConfig(); + String artifactName = "kuku"; + String relativeUrl; + ArtifactReqDetails artifact = new ArtifactReqDetails(); + artifact.setArtifactName(artifactName); + Map authorizationHeaders = new HashMap(); + authorizationHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + ServiceReqDetails serviceInfo = new ServiceReqDetails(); + serviceInfo.setName(serviceName); + serviceInfo.setVersion(serviceVersion); + RestResponse restResponse = null; + if (resourceName != null) { + ResourceReqDetails resourceDetailes = new ResourceReqDetails(); + resourceDetailes.setName(resourceName); + resourceDetailes.setVersion(resourceVersion); + relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceName), serviceVersion, + ValidationUtils.convertToSystemName(resourceName), resourceVersion, artifactName)); + restResponse = ArtifactRestUtils.downloadResourceArtifact(serviceInfo, resourceDetailes, artifact, + designerUser, authorizationHeaders); + } else { + relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_SERVICE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceName), serviceVersion, artifactName)); + restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceInfo, artifact, designerUser, + authorizationHeaders); + } + // String fullUrlFormatted = + // String.format(Urls.DOWNLOAD_RESOURCE_ARTIFACT_FULL_URL, + // config.getCatalogBeHost(),config.getCatalogBePort(), relativeUrl); + // String consumerId = "dummy.ecomp"; + + // RestResponse restResponse = + // artifactUtils.downloadResourceArtifact(designerUser,fullUrlFormatted, + // consumerId,true); + AssertJUnit.assertEquals("Check response code after download resource", 404, + restResponse.getErrorCode().intValue()); + + // validate audit + String auditAction = "DArtifactDownload"; + + ExpectedDistDownloadAudit expectedDistDownloadAudit = new ExpectedDistDownloadAudit(auditAction, + BaseRestUtils.ecomp, relativeUrl, "404", + "SVC4504: Error: Service version " + serviceVersion + " was not found."); + AuditValidationUtils.validateAudit(expectedDistDownloadAudit, auditAction); + } + + protected String encodeUrlForDownload(String url) { + return url.replaceAll(" ", "%20"); + } + + protected ConsumerDataDefinition createConsumer() { + ConsumerDataDefinition consumer = new ConsumerDataDefinition(); + consumer.setConsumerName(USER); + consumer.setConsumerSalt(SALT); + consumer.setConsumerPassword(HASHED_PASSWORD); + return consumer; + + } + + @Test(enabled = false) + public void downloadServiceArtifactSuccess() throws Exception { + // Create service + RestResponse serviceResponse = ServiceRestUtils.createService(serviceDetails, designerUser); + assertEquals("Check response code after creating resource", 201, serviceResponse.getErrorCode().intValue()); + serviceUniqueId = ResponseParser.convertServiceResponseToJavaObject(serviceResponse.getResponse()) + .getUniqueId(); + + ArtifactReqDetails artifactDetails = ElementFactory.getDefaultDeploymentArtifactForType("MURANO_PKG"); + + RestResponse addArtifactResponse = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, + designerUser, serviceUniqueId, ArtifactRestUtils.calculateMD5Header(artifactDetails)); + assertEquals("Check response code after adding interface artifact", 200, + addArtifactResponse.getErrorCode().intValue()); + + // Getting expected artifact checksum + + // ArtifactResJavaObject artifactResp = + // artifactUtils.parseInformationalArtifactResp(addArtifactResponse); + String expectedPayloadChecksum = ResponseParser + .convertArtifactDefinitionResponseToJavaObject(addArtifactResponse.getResponse()).getArtifactChecksum(); + + String artifactName = ValidationUtils.normalizeFileName(artifactDetails.getArtifactName()); + + String relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_SERVICE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceDetails.getName()), serviceBaseVersion, artifactName)); + + Map authorizationHeaders = new HashMap(); + authorizationHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, artifactDetails, + designerUser, authorizationHeaders); + assertEquals("Check response code after download resource", 200, restResponse.getErrorCode().intValue()); + + // Validating headers + // content disposition + List contDispHeaderList = restResponse.getHeaderFields().get(Constants.CONTENT_DISPOSITION_HEADER); + assertNotNull(contDispHeaderList); + assertEquals("Check content disposition header", + new StringBuilder().append("attachment; filename=\"").append(artifactName).append("\"").toString(), + contDispHeaderList.get(0)); + + // content type + List contTypeHeaderList = restResponse.getHeaderFields().get(Constants.CONTENT_TYPE_HEADER); + assertNotNull(contTypeHeaderList); + assertEquals("Check content type", "application/octet-stream", contTypeHeaderList.get(0)); + + String actualContents = restResponse.getResponse(); + + assertEquals(artifactDetails.getPayload(), Base64.encodeBase64String(actualContents.getBytes())); + + // validating checksum + byte[] bytes = actualContents.getBytes(); + String actualPayloadChecksum = GeneralUtility.calculateMD5ByByteArray(bytes); + assertEquals(expectedPayloadChecksum, actualPayloadChecksum); + + // validating valid zip + InputStream is = new ByteArrayInputStream(bytes); + InputStream zis = new ZipInputStream(is); + zis.close(); + + // validate audit + String auditAction = "DArtifactDownload"; + + ExpectedDistDownloadAudit expectedDistDownloadAudit = new ExpectedDistDownloadAudit(auditAction, + ResourceRestUtils.ecomp, encodeUrlForDownload(relativeUrl), "200", "OK"); + AuditValidationUtils.validateAudit(expectedDistDownloadAudit, auditAction); + } + + @Test + public void downloadResourceArtifact_NoConsumerId() throws Exception { + + String artifactName = "kuku"; + ArtifactReqDetails artifact = new ArtifactReqDetails(); + artifact.setArtifactName(artifactName); + ResourceReqDetails resource = new ResourceReqDetails(); + resource.setName("notExisting"); + resource.setVersion("0.1"); + String relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceDetails.getName()), serviceBaseVersion, + ValidationUtils.convertToSystemName(resource.getName()), resource.getVersion(), artifactName)); + serviceDetails.setVersion("0.1"); + Map authorizationHeaders = new HashMap(); + authorizationHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + RestResponse restResponse = ArtifactRestUtils.downloadResourceArtifact(serviceDetails, resource, artifact, + designerUser, authorizationHeaders, false); + assertEquals("Check response code after download resource", 400, restResponse.getErrorCode().intValue()); + + // validate audit + String auditAction = "DArtifactDownload"; + + ExpectedDistDownloadAudit expectedDistDownloadAudit = new ExpectedDistDownloadAudit(auditAction, "", + relativeUrl, "400", "POL5001: Error: Missing 'X-ECOMP-InstanceID' HTTP header."); + AuditValidationUtils.validateAudit(expectedDistDownloadAudit, auditAction); + } + + @Test + public void downloadResourceArtifact_ResourceNameNotFound() throws Exception { + + String artifactName = "kuku"; + ArtifactReqDetails artifact = new ArtifactReqDetails(); + artifact.setArtifactName(artifactName); + ResourceReqDetails resource = new ResourceReqDetails(); + resource.setName("notExisting"); + resource.setVersion("0.1"); + serviceDetails.setVersion("0.1"); + String relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceDetails.getName()), serviceDetails.getVersion(), + ValidationUtils.convertToSystemName(resource.getName()), resource.getVersion(), artifactName)); + + Map authorizationHeaders = new HashMap(); + authorizationHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + RestResponse restResponse = ArtifactRestUtils.downloadResourceArtifact(serviceDetails, resource, artifact, + designerUser, authorizationHeaders); + + assertEquals("Check response code after download resource", 404, restResponse.getErrorCode().intValue()); + + // validate audit + String auditAction = "DArtifactDownload"; + + ExpectedDistDownloadAudit expectedDistDownloadAudit = new ExpectedDistDownloadAudit(auditAction, + BaseRestUtils.ecomp, relativeUrl, "404", + "SVC4063: Error: Requested 'Notexisting' resource was not found."); + AuditValidationUtils.validateAudit(expectedDistDownloadAudit, auditAction); + } + + @Test + public void downloadResourceArtifact_ResourceVersionNotFound() throws Exception { + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, designerUser); + assertEquals("Check response code after creating resource", 201, createResource.getErrorCode().intValue()); + + Resource resource = ResponseParser.convertResourceResponseToJavaObject(createResource.getResponse()); + ResourceReqDetails resourceDetailes = new ResourceReqDetails(); + resourceDetailes.setName(resource.getName()); + resourceDetailes.setVersion("0.2"); + + serviceDetails.setVersion("0.1"); + + String artifactName = "kuku"; + ArtifactReqDetails artifact = new ArtifactReqDetails(); + artifact.setArtifactName(artifactName); + + String relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceDetails.getName()), serviceBaseVersion, + ValidationUtils.convertToSystemName(resourceDetailes.getName()), resourceDetailes.getVersion(), + artifactName)); + + Map authorizationHeaders = new HashMap(); + authorizationHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + RestResponse restResponse = ArtifactRestUtils.downloadResourceArtifact(serviceDetails, resourceDetailes, + artifact, designerUser, authorizationHeaders); + assertEquals("Check response code after download resource", 404, restResponse.getErrorCode().intValue()); + + // validate audit + String auditAction = "DArtifactDownload"; + + ExpectedDistDownloadAudit expectedDistDownloadAudit = new ExpectedDistDownloadAudit(auditAction, + BaseRestUtils.ecomp, relativeUrl, "404", "SVC4504: Error: Resource version 0.2 was not found."); + AuditValidationUtils.validateAudit(expectedDistDownloadAudit, auditAction); + } + + @Test + public void downloadResourceArtifact_ServiceNameNotFound() throws Exception { + // Create resource + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, designerUser); + assertEquals("Check response code after creating resource", 201, createResource.getErrorCode().intValue()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(createResource.getResponse()); + download_serviceNameNotFound_inner("notExistingServiceName", serviceBaseVersion, resource.getName(), + resource.getVersion()); + + } + + @Test + public void downloadResourceArtifact_ServiceVersionNotFound() throws Exception { + // Create resource + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, designerUser); + assertEquals("Check response code after creating resource", 201, createResource.getErrorCode().intValue()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(createResource.getResponse()); + + // Create service + RestResponse serviceResponse = ServiceRestUtils.createService(serviceDetails, designerUser); + assertEquals("Check response code after creating resource", 201, serviceResponse.getErrorCode().intValue()); + serviceUniqueId = ResponseParser.convertServiceResponseToJavaObject(serviceResponse.getResponse()) + .getUniqueId(); + + download_serviceVersionNotFound_inner(serviceDetails.getName(), "0.3", resource.getName(), + resource.getVersion()); + } + + @Test + public void downloadServiceArtifact_ServiceNameNotFound() throws Exception { + download_serviceNameNotFound_inner("notExistingServiceName", serviceBaseVersion, null, null); + + } + + @Test + public void downloadServiceArtifact_ServiceVersionNotFound() throws Exception { + + // Create service + RestResponse serviceResponse = ServiceRestUtils.createService(serviceDetails, designerUser); + assertEquals("Check response code after creating resource", 201, serviceResponse.getErrorCode().intValue()); + serviceUniqueId = ResponseParser.convertServiceResponseToJavaObject(serviceResponse.getResponse()) + .getUniqueId(); + + download_serviceVersionNotFound_inner(serviceDetails.getName(), "0.2", null, null); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/externalapi/DownloadArtifactsTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/externalapi/DownloadArtifactsTest.java new file mode 100644 index 0000000000..80b70d675e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/externalapi/DownloadArtifactsTest.java @@ -0,0 +1,385 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.externalapi; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class DownloadArtifactsTest extends ComponentBaseTest { + @Rule + public static TestName name = new TestName(); + + Gson gson = new Gson(); + + public DownloadArtifactsTest() { + super(name, DownloadArtifactsTest.class.getName()); + } + + private User sdncDesignerDetails; + private User sdncAdminDetails; + private ImportReqDetails resourceDetailsVF_01; + private ResourceReqDetails resourceDetailsVF_02; + private ResourceReqDetails resourceDetailsVF_03; + private ResourceReqDetails resourceDetailsCP_01; + private ServiceReqDetails serviceDetails_01; + private ServiceReqDetails serviceDetails_02; + public static String rootPath = System.getProperty("user.dir"); + + @BeforeMethod(alwaysRun = true) + public void before() throws Exception { + init(); + createComponents(); + } + + private void createComponents() throws Exception { + createAtomicResource(resourceDetailsCP_01); + importVfWithArtifacts(resourceDetailsVF_01); + createVF(resourceDetailsVF_03); + createVF(resourceDetailsVF_02); + createService(serviceDetails_01); + } + + public void init() { + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncAdminDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + resourceDetailsVF_01 = ElementFactory.getDefaultImportResourceByType("VF100", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.VF.toString()); + resourceDetailsVF_02 = ElementFactory.getDefaultResourceByType("VF200", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.VF.toString()); + resourceDetailsVF_03 = ElementFactory.getDefaultResourceByType("VF300", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.VF.toString()); + resourceDetailsCP_01 = ElementFactory.getDefaultResourceByType("CP100", NormativeTypesEnum.PORT, + ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.CP.toString()); + serviceDetails_01 = ElementFactory.getDefaultService("newtestservice1", ServiceCategoriesEnum.MOBILITY, + sdncDesignerDetails.getUserId()); + serviceDetails_02 = ElementFactory.getDefaultService("newtestservice2", ServiceCategoriesEnum.MOBILITY, + sdncDesignerDetails.getUserId()); + } + + @Test + public void downloadResourceInstanceArtifactsFromServiceTest() throws Exception { + Service service = createServiceWithRIsWithArtifacts(); + Map deploymentArtifacts; + List resourceInstances = service.getComponentInstances(); + for (ComponentInstance ri : resourceInstances) { + deploymentArtifacts = ri.getDeploymentArtifacts(); + for (ArtifactDefinition artifact : deploymentArtifacts.values()) { + assertNotNull(downloadResourceInstanceArtifact(service, ri, artifact)); + } + } + } + + @Test + public void downloadServiceArtifactsTest() throws Exception { + Service service = createServiceWithArtifacts(); + Map deploymentArtifacts = service.getDeploymentArtifacts(); + for (ArtifactDefinition artifact : deploymentArtifacts.values()) { + assertNotNull(downloadServiceArtifact(service, artifact)); + } + + } + + private Service createServiceWithArtifacts() throws Exception { + + ArtifactReqDetails otherArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.OTHER.getType()); + + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService( + otherArtifactDetails, sdncDesignerDetails, serviceDetails_01.getUniqueId()); + assertTrue( + "response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + + addInformationalArtifactToService.getErrorCode(), + addInformationalArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + ArtifactReqDetails yangXmlArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.YANG_XML.getType()); + + addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(yangXmlArtifactDetails, + sdncDesignerDetails, serviceDetails_01.getUniqueId()); + assertTrue( + "response code is not BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + + addInformationalArtifactToService.getErrorCode(), + addInformationalArtifactToService.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + RestResponse createServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + return ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()); + } + + private RestResponse downloadResourceInstanceArtifact(Service service, ComponentInstance ri, + ArtifactDefinition artifact) throws Exception { + String url = String.format(Urls.GET_DOWNLOAD_SERVICE_RI_ARTIFACT, "localhost", "8080", service.getUUID(), + ri.getUniqueId(), artifact.getArtifactUUID()); + String userId = sdncDesignerDetails.getUserId(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.CACHE_CONTROL.getValue(), "no-cache"); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), "Basic dGVzdDoxMjM0NTY="); + headersMap.put("X-ECOMP-InstanceID", "test"); + if (userId != null) { + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), userId); + } + sendAuthorizationRequest(); + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendGet(url, headersMap); + if (response.getErrorCode() != 200 && response.getResponse().getBytes() == null + && response.getResponse().getBytes().length == 0) { + return null; + } + return response; + } + + private RestResponse downloadServiceArtifact(Service service, ArtifactDefinition artifact) throws Exception { + String url = String.format(Urls.GET_DOWNLOAD_SERVICE_ARTIFACT, "localhost", "8080", service.getUUID(), + artifact.getArtifactUUID()); + String userId = sdncDesignerDetails.getUserId(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.CACHE_CONTROL.getValue(), "no-cache"); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), "Basic dGVzdDoxMjM0NTY="); + headersMap.put("X-ECOMP-InstanceID", "test"); + if (userId != null) { + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), userId); + } + sendAuthorizationRequest(); + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendGet(url, headersMap); + if (response.getErrorCode() != 200 && response.getResponse().getBytes() == null + && response.getResponse().getBytes().length == 0) { + return null; + } + return response; + + } + + private RestResponse sendAuthorizationRequest() throws IOException { + String url = String.format(Urls.POST_AUTHORIZATION, "localhost", "8080"); + String userId = sdncAdminDetails.getUserId(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.CACHE_CONTROL.getValue(), "no-cache"); + if (userId != null) { + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), userId); + } + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, + "{\"consumerName\":\"test\",\"consumerPassword\":\"0a0dc557c3bf594b1a48030e3e99227580168b21f44e285c69740b8d5b13e33b\",\"consumerSalt\":\"2a1f887d607d4515d4066fe0f5452a50\"}", + headersMap); + if (response.getErrorCode() != 201) { + return null; + } + return response; + } + + private Service createServiceWithRIsWithArtifacts() throws Exception { + serviceDetails_02.setUniqueId(serviceDetails_01.getUniqueId()); + createTreeCheckedinVFInstances(); + LifecycleRestUtils.changeResourceState(resourceDetailsCP_01, sdncDesignerDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + createVFInstanceAndAtomicResourceInstanceWithoutCheckin(resourceDetailsVF_01, resourceDetailsCP_01, + sdncDesignerDetails); + RestResponse updateServiceResp = ServiceRestUtils.updateService(serviceDetails_02, sdncDesignerDetails); + ServiceRestUtils.checkSuccess(updateServiceResp); + getComponentAndValidateRIs(serviceDetails_01, 5, 0); + + return ResponseParser.convertServiceResponseToJavaObject(updateServiceResp.getResponse()); + } + + private void createTreeCheckedinVFInstances() throws Exception { + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createSecondVFInstResp); + RestResponse createThirdVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_03, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createThirdVFInstResp); + } + + private Component getComponentAndValidateRIs(ComponentReqDetails componentDetails, int numberOfRIs, + int numberOfRelations) throws IOException, Exception { + + RestResponse getResponse = null; + Component component = null; + if (componentDetails instanceof ResourceReqDetails) { + getResponse = ResourceRestUtils.getResource(sdncAdminDetails, componentDetails.getUniqueId()); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Resource.class); + } else if (componentDetails instanceof ServiceReqDetails) { + getResponse = ServiceRestUtils.getService((ServiceReqDetails) componentDetails, sdncAdminDetails); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Service.class); + } else if (componentDetails instanceof ProductReqDetails) { + getResponse = ProductRestUtils.getProduct(componentDetails.getUniqueId(), sdncAdminDetails.getUserId()); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Product.class); + } else { + Assert.fail("Unsupported type of componentDetails - " + componentDetails.getClass().getSimpleName()); + } + ResourceRestUtils.checkSuccess(getResponse); + int numberOfActualRIs = component.getComponentInstances() != null ? component.getComponentInstances().size() + : 0; + int numberOfActualRelations = component.getComponentInstancesRelations() != null + ? component.getComponentInstancesRelations().size() : 0; + assertEquals("Check number of RIs meet the expected number", numberOfRIs, numberOfActualRIs); + assertEquals("Check number of RI relations meet the expected number", numberOfRelations, + numberOfActualRelations); + + return component; + } + + private void createVFInstanceAndAtomicResourceInstanceWithoutCheckin(ResourceReqDetails vf, + ResourceReqDetails atomicResource, User user) throws Exception { + RestResponse createVFInstance = createVFInstance(serviceDetails_01, vf, user); + ResourceRestUtils.checkCreateResponse(createVFInstance); + RestResponse atomicInstanceForService = createAtomicInstanceForService(serviceDetails_01, atomicResource, user); + ResourceRestUtils.checkCreateResponse(atomicInstanceForService); + } + + private RestResponse createCheckedinVFInstance(ServiceReqDetails containerDetails, + ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + changeResourceLifecycleState(compInstOriginDetails, modifier.getUserId(), LifeCycleStatesEnum.CHECKIN); + return createVFInstance(containerDetails, compInstOriginDetails, modifier); + } + + private RestResponse createVFInstance(ServiceReqDetails containerDetails, ResourceReqDetails compInstOriginDetails, + User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, + true); + } + + private RestResponse createAtomicInstanceForService(ServiceReqDetails containerDetails, + ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, + true); + } + + private RestResponse createComponentInstance(ComponentReqDetails containerDetails, + ComponentReqDetails compInstOriginDetails, User modifier, ComponentTypeEnum containerComponentTypeEnum, + boolean isHighestLevel) throws IOException, Exception { + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(compInstOriginDetails); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, modifier, containerDetails.getUniqueId(), containerComponentTypeEnum); + return createResourceInstanceResponse; + } + + private void changeResourceLifecycleState(ResourceReqDetails resourceDetails, String userUserId, + LifeCycleStatesEnum lifeCycleStates) throws Exception { + RestResponse response = LifecycleRestUtils.changeResourceState(resourceDetails, userUserId, lifeCycleStates); + LifecycleRestUtils.checkLCS_Response(response); + } + + private void createAtomicResource(ResourceReqDetails resourceDetails) throws Exception { + RestResponse createResourceResponse = ResourceRestUtils.createResource(resourceDetails, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createResourceResponse); + + } + + private void createVF(ResourceReqDetails resourceDetails) throws Exception { + createVF(resourceDetails, sdncDesignerDetails); + + } + + private void createVF(ResourceReqDetails resourceDetails, User sdncModifier) throws Exception { + RestResponse createVfResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifier); + ResourceRestUtils.checkCreateResponse(createVfResponse); + } + + private void createService(ServiceReqDetails serviceDetails) throws Exception { + createService(serviceDetails, sdncDesignerDetails); + } + + private void createService(ServiceReqDetails serviceDetails, User sdncModifier) throws Exception { + RestResponse createServiceResponse = ServiceRestUtils.createService(serviceDetails, sdncModifier); + ResourceRestUtils.checkCreateResponse(createServiceResponse); + } + + private void importVfWithArtifacts(ImportReqDetails resourceDetailsVF_01) throws Exception { + String payloadName = "VF_RI2_G4_withArtifacts.csar"; + Path path = Paths.get(rootPath + "/src/main/resources/ci/VF_RI2_G4_withArtifacts.csar"); + byte[] data = Files.readAllBytes(path); + String payloadData = Base64.encodeBase64String(data); + resourceDetailsVF_01.setPayloadData(payloadData); + + resourceDetailsVF_01.setPayloadName(payloadName); + resourceDetailsVF_01.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetailsVF_01, sdncDesignerDetails); + BaseRestUtils.checkCreateResponse(createResource); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/BasicHttpAuthenticationTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/BasicHttpAuthenticationTest.java new file mode 100644 index 0000000000..c52ee470cf --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/BasicHttpAuthenticationTest.java @@ -0,0 +1,442 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +//US505653 +package org.openecomp.sdc.ci.tests.execute.general; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedAuthenticationAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ConsumerRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class BasicHttpAuthenticationTest extends ComponentBaseTest { + + protected static final String AUTH_FAILED_INVALID_AUTHENTICATION_HEADER = "AUTH_FAILED_INVALID_AUTHENTICATION_HEADER"; + + protected static final String AUTH_SUCCESS = "AUTH_SUCCESS"; + + protected static final String AUTH_FAILED_INVALID_PASSWORD = "AUTH_FAILED_INVALID_PASSWORD"; + + protected static final String AUTH_FAILED_USER_NOT_FOUND = "AUTH_FAILED_USER_NOT_FOUND"; + + protected static final String AUTH_REQUIRED = "AUTH_REQUIRED"; + + protected static final String WWW_AUTHENTICATE = "WWW-Authenticate"; + + // user ci password 123456 + // protected final String authorizationHeader = "Basic Y2k6MTIzNDU2"; + // user ci password 123456 + protected final String USER = "ci"; + + protected final String PASSWORD = "123456"; + + protected final String SALT = "2a1f887d607d4515d4066fe0f5452a50"; + + protected final String HASHED_PASSWORD = "0a0dc557c3bf594b1a48030e3e99227580168b21f44e285c69740b8d5b13e33b"; + + protected User sdncAdminUserDetails; + + protected ConsumerDataDefinition consumerDataDefinition; + protected ResourceReqDetails resourceDetails; + protected ServiceReqDetails serviceDetails; + protected User sdncUserDetails; + + protected ArtifactReqDetails deploymentArtifact; + + protected ExpectedAuthenticationAudit expectedAuthenticationAudit; + + protected final String auditAction = "HttpAuthentication"; + + protected String expectedDownloadServiceUrl; + protected String expectedDownloadResourceUrl; + protected ComponentInstanceReqDetails componentInstanceReqDetails; + + @Rule + public static TestName name = new TestName(); + + public BasicHttpAuthenticationTest() { + super(name, BasicHttpAuthenticationTest.class.getName()); + } + + @BeforeMethod + public void init() throws Exception { + + sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + Resource resourceObject = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resourceDetails = new ResourceReqDetails(resourceObject); + Service serviceObject = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + serviceDetails = new ServiceReqDetails(serviceObject); + + deploymentArtifact = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + RestResponse response = ArtifactRestUtils.addInformationalArtifactToResource(deploymentArtifact, + sdncUserDetails, resourceDetails.getUniqueId()); + AssertJUnit.assertTrue("add HEAT artifact to resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + componentInstanceReqDetails = ElementFactory.getDefaultComponentInstance(); + // certified resource + response = LifecycleRestUtils.certifyResource(resourceDetails); + AssertJUnit.assertTrue("certify resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + // add resource instance with HEAT deployment artifact to the service + componentInstanceReqDetails.setComponentUid(resourceDetails.getUniqueId()); + response = ComponentInstanceRestUtils.createComponentInstance(componentInstanceReqDetails, sdncUserDetails, + serviceDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + AssertJUnit.assertTrue("response code is not 201, returned: " + response.getErrorCode(), + response.getErrorCode() == 201); + expectedAuthenticationAudit = new ExpectedAuthenticationAudit(); + + // RestResponse addDeploymentArtifactResponse = + // ArtifactRestUtils.addInformationalArtifactToService(deploymentArtifact, + // sdncUserDetails, serviceDetails.getUniqueId()); + // assertEquals("didn't succeed to upload deployment artifact", 200, + // addDeploymentArtifactResponse.getErrorCode().intValue()); + // + // downloadUrl = + // String.format(Urls.DISTRIB_DOWNLOAD_SERVICE_ARTIFACT_RELATIVE_URL, + // ValidationUtils.convertToSystemName(serviceDetails.getServiceName()), + // serviceDetails.getVersion(), + // ValidationUtils.normalizeFileName(deploymentArtifact.getArtifactName())); + + expectedDownloadResourceUrl = String.format(Urls.DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceDetails.getName()), serviceDetails.getVersion(), + ValidationUtils.convertToSystemName(resourceDetails.getName()), resourceDetails.getVersion(), + ValidationUtils.normalizeFileName(deploymentArtifact.getArtifactName())); + expectedDownloadResourceUrl = expectedDownloadResourceUrl.substring("/sdc/".length(), + expectedDownloadResourceUrl.length()); + + expectedDownloadServiceUrl = String.format(Urls.DISTRIB_DOWNLOAD_SERVICE_ARTIFACT_RELATIVE_URL, + ValidationUtils.convertToSystemName(serviceDetails.getName()), serviceDetails.getVersion(), + ValidationUtils.normalizeFileName(deploymentArtifact.getArtifactName())); + expectedDownloadServiceUrl = expectedDownloadServiceUrl.substring("/sdc/".length(), + expectedDownloadServiceUrl.length()); + + sdncAdminUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + consumerDataDefinition = createConsumer(); + RestResponse deleteResponse = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + BaseRestUtils.checkStatusCode(deleteResponse, "delete operation filed", false, 404, 200); + ; + + RestResponse createResponse = ConsumerRestUtils.createConsumer(consumerDataDefinition, sdncAdminUserDetails); + BaseRestUtils.checkCreateResponse(createResponse); + + } + + @AfterMethod + public void tearDown() throws Exception { + RestResponse deleteResponse = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + BaseRestUtils.checkStatusCode(deleteResponse, "delete operation filed", false, 404, 200); + ; + } + + @Test + public void sendAuthenticatedRequestTest_success() throws Exception, Exception { + DbUtils.cleanAllAudits(); + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader(USER, PASSWORD); + // RestResponse restResponse = + // ArtifactRestUtils.downloadServiceArtifact(serviceDetails, + // deploymentArtifact, sdncUserDetails, authorizationHeader); + RestResponse restResponse = ArtifactRestUtils.downloadResourceArtifact(serviceDetails, resourceDetails, + deploymentArtifact, sdncUserDetails, authorizationHeader); + AssertJUnit.assertEquals("Check response code after download artifact", 200, + restResponse.getErrorCode().intValue()); + AssertJUnit.assertFalse(restResponse.getHeaderFields().containsKey(HttpHeaderEnum.WWW_AUTHENTICATE.getValue())); + + validateAuditAuthentication(USER, AUTH_SUCCESS, ComponentTypeEnum.RESOURCE); + + } + + protected void validateAuditAuthentication(String userName, String AuthStatus, ComponentTypeEnum compType) + throws Exception { + if (compType.equals(ComponentTypeEnum.RESOURCE)) { + expectedAuthenticationAudit = new ExpectedAuthenticationAudit(expectedDownloadResourceUrl, userName, + auditAction, AuthStatus); + } else { + expectedAuthenticationAudit = new ExpectedAuthenticationAudit(expectedDownloadServiceUrl, userName, + auditAction, AuthStatus); + } + AuditValidationUtils.validateAuthenticationAudit(expectedAuthenticationAudit); + } + + protected ConsumerDataDefinition createConsumer() { + ConsumerDataDefinition consumer = new ConsumerDataDefinition(); + consumer.setConsumerName(USER); + consumer.setConsumerSalt(SALT); + consumer.setConsumerPassword(HASHED_PASSWORD); + return consumer; + + } + + @Test + public void sendAuthenticatedRequestWithoutHeadersTest() throws Exception, Exception { + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, new HashMap()); + assertEquals("Check response code after download artifact", 401, restResponse.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.AUTH_REQUIRED.name(), new ArrayList(), + restResponse.getResponse()); + assertTrue(restResponse.getHeaderFields().containsKey(WWW_AUTHENTICATE)); + List getAuthenticateHeader = restResponse.getHeaderFields().get(WWW_AUTHENTICATE); + assertEquals("www-authenticate header contains more then one value", 1, getAuthenticateHeader.size()); + assertTrue(getAuthenticateHeader.get(0).equals("Basic realm=" + "\"ASDC\"")); + + validateAuditAuthentication("", AUTH_REQUIRED, ComponentTypeEnum.SERVICE); + } + + @Test + public void sendAuthenticatedRequestTest_userIsNotProvsioned() throws Exception, Exception { + String userName = "shay"; + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader(userName, "123456"); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 403, restResponse.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.AUTH_FAILED.name(), new ArrayList(), + restResponse.getResponse()); + assertFalse(restResponse.getHeaderFields().containsKey(WWW_AUTHENTICATE)); + + validateAuditAuthentication(userName, AUTH_FAILED_USER_NOT_FOUND, ComponentTypeEnum.SERVICE); + } + + @Test + public void sendAuthenticatedRequestTest_userIsNull() throws Exception, Exception { + String userName = ""; + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader(userName, "123456"); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 403, restResponse.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.AUTH_FAILED.name(), new ArrayList(), + restResponse.getResponse()); + assertFalse(restResponse.getHeaderFields().containsKey(WWW_AUTHENTICATE)); + + validateAuditAuthentication(userName, AUTH_FAILED_USER_NOT_FOUND, ComponentTypeEnum.SERVICE); + } + + @Test + public void sendAuthenticatedRequestTest_passwordIsNull() throws Exception, Exception { + String userName = "ci"; + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader(userName, ""); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 403, restResponse.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.AUTH_FAILED.name(), new ArrayList(), + restResponse.getResponse()); + assertFalse(restResponse.getHeaderFields().containsKey(WWW_AUTHENTICATE)); + + validateAuditAuthentication(userName, AUTH_FAILED_INVALID_PASSWORD, ComponentTypeEnum.SERVICE); + } + + @Test + public void sendAuthenticatedRequestTest_passowrdIsNotValidated() throws Exception, Exception { + String userCi = "ci"; + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader(userCi, "98765"); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 403, restResponse.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.AUTH_FAILED.name(), new ArrayList(), + restResponse.getResponse()); + assertFalse(restResponse.getHeaderFields().containsKey(HttpHeaderEnum.WWW_AUTHENTICATE.getValue())); + + validateAuditAuthentication(userCi, AUTH_FAILED_INVALID_PASSWORD, ComponentTypeEnum.SERVICE); + } + + @Test + public void sendAuthenticatedRequestTest_InvalidHeader() throws Exception, Exception { + String userCredentials = USER + ":" + PASSWORD; + byte[] encodeBase64 = Base64.encodeBase64(userCredentials.getBytes()); + String encodedUserCredentials = new String(encodeBase64); + Map authorizationHeader = new HashMap(); + authorizationHeader.put(HttpHeaderEnum.AUTHORIZATION.getValue(), encodedUserCredentials); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 400, restResponse.getErrorCode().intValue()); + assertFalse(restResponse.getHeaderFields().containsKey(HttpHeaderEnum.WWW_AUTHENTICATE.getValue())); + + validateAuditAuthentication("", AUTH_FAILED_INVALID_AUTHENTICATION_HEADER, ComponentTypeEnum.SERVICE); + } + + @Test(enabled = false) + public void sendTwoAuthenticatedRequestsTest() throws Exception, Exception { + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader(USER, PASSWORD); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 200, restResponse.getErrorCode().intValue()); + + RestResponse secondRestResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after second download artifact", 200, + secondRestResponse.getErrorCode().intValue()); + } + + @Test(enabled = false) + public void sendAuthenticatedRequestTest_userValidation_1() throws Exception, Exception { + + ConsumerDataDefinition consumer = new ConsumerDataDefinition(); + consumer.setConsumerName("cI2468"); + consumer.setConsumerPassword(HASHED_PASSWORD); + consumer.setConsumerSalt(SALT); + RestResponse deleteResponse = ConsumerRestUtils.deleteConsumer(consumer, sdncAdminUserDetails); + BaseRestUtils.checkStatusCode(deleteResponse, "delete operation filed", false, 404, 200); + + RestResponse createResponse = ConsumerRestUtils.createConsumer(consumer, sdncAdminUserDetails); + BaseRestUtils.checkCreateResponse(createResponse); + + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader(consumer.getConsumerName(), + PASSWORD); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 200, restResponse.getErrorCode().intValue()); + + deleteResponse = ConsumerRestUtils.deleteConsumer(consumer, sdncAdminUserDetails); + BaseRestUtils.checkStatusCode(deleteResponse, "delete operation filed", false, 404, 200); + } + + // ECOMP Consumer Name - UTF-8 string up to 255 characters containing the + // following characters : ( maybe to limit 4-64 chars ? ) + // Lowercase characters {a-z} + // Uppercase characters {A-Z} + // Numbers {0-9} + // Dash {-}; this character is not supported as the first character in the + // user name + // Period {.}; this character is not supported as the first character in the + // user name + // Underscore {_} + // @Ignore("add manually user:password 24-!68:123456 to + // users-configuration.yaml in runtime") + @Test(enabled = false) + public void sendAuthenticatedRequestTest_userValidation_2() throws Exception, Exception { + ConsumerDataDefinition consumer = new ConsumerDataDefinition(); + consumer.setConsumerName("24-!68"); + consumer.setConsumerPassword(HASHED_PASSWORD); + consumer.setConsumerSalt(SALT); + RestResponse deleteResponse = ConsumerRestUtils.deleteConsumer(consumer, sdncAdminUserDetails); + BaseRestUtils.checkStatusCode(deleteResponse, "delete operation filed", false, 404, 200); + + RestResponse createResponse = ConsumerRestUtils.createConsumer(consumer, sdncAdminUserDetails); + BaseRestUtils.checkCreateResponse(createResponse); + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader(consumer.getConsumerName(), + PASSWORD); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 200, restResponse.getErrorCode().intValue()); + + deleteResponse = ConsumerRestUtils.deleteConsumer(consumer, sdncAdminUserDetails); + BaseRestUtils.checkStatusCode(deleteResponse, "delete operation filed", false, 404, 200); + } + + // this is invalide becouse we do not use the : any more + // @Ignore("can't exectue, yaml file does not allow to enter more then one + // colon continuously (\":\") ") + @Test(enabled = false) + public void sendAuthenticatedRequestTest_userValidation_3() throws Exception, Exception { + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader("a:", "123456"); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 200, restResponse.getErrorCode().intValue()); + } + + // + // * ECOMP Consumer Password - expected to be SHA-2 256 encrypted value ( + // SALT + "real" password ) => maximal length 256 bytes = 32 characters + // Before storing/comparing please convert upper case letter to lower. + // The "normalized" encrypted password should match the following format : + // [a-z0-9] + // @Ignore("add manually user:password 2468:123:456 to + // users-configuration.yaml in runtime") + @Test(enabled = false) + public void sendAuthenticatedRequestTest_passwordValidation_1() throws Exception, Exception { + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader("A1", "123:456"); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 200, restResponse.getErrorCode().intValue()); + } + + // * ECOMP Consumer Password - expected to be SHA-2 256 encrypted value ( + // SALT + "real" password ) => maximal length 256 bytes = 32 characters + // Before storing/comparing please convert upper case letter to lower. + // The "normalized" encrypted password should match the following format : + // [a-z0-9] + @Test(enabled = false) + // @Ignore("add manually user:password 2468:Sq123a456B to + // users-configuration.yaml in runtime") + public void sendAuthenticatedRequestTest_passwordValidation_2() throws Exception, Exception { + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader("B2", "Sq123a456B"); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 200, restResponse.getErrorCode().intValue()); + } + + // * ECOMP Consumer Password - expected to be SHA-2 256 encrypted value ( + // SALT + "real" password ) => maximal length 256 bytes = 32 characters + // Before storing/comparing please convert upper case letter to lower. + // The "normalized" encrypted password should match the following format : + // [a-z0-9] + @Test + // @Ignore("add C3:111T-0-*# to file") + public void sendAuthenticatedRequestTest_passwordValidation_3() throws Exception, Exception { + Map authorizationHeader = BaseRestUtils.addAuthorizeHeader("C3", "111T-0-*#"); + RestResponse restResponse = ArtifactRestUtils.downloadServiceArtifact(serviceDetails, deploymentArtifact, + sdncUserDetails, authorizationHeader); + assertEquals("Check response code after download artifact", 200, restResponse.getErrorCode().intValue()); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/FeProxyTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/FeProxyTest.java new file mode 100644 index 0000000000..e4f7d396be --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/FeProxyTest.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.general; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +public class FeProxyTest extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public FeProxyTest() { + super(name, FeProxyTest.class.getName()); + } + + @Test + public void testFeProxy() throws Exception { + User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + RestResponse allCategoriesTowardsFe = CategoryRestUtils.getAllCategoriesTowardsFe(defaultUser, + BaseRestUtils.RESOURCE_COMPONENT_TYPE); + AssertJUnit.assertEquals("Check response code after get categories towards FE", 200, + allCategoriesTowardsFe.getErrorCode().intValue()); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/ManageEcompConsumerCredentials.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/ManageEcompConsumerCredentials.java new file mode 100644 index 0000000000..9ef8f147be --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/ManageEcompConsumerCredentials.java @@ -0,0 +1,1420 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.general; + +import static org.testng.AssertJUnit.assertEquals; + +import java.util.HashMap; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedEcomConsumerAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ConsumerRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class ManageEcompConsumerCredentials extends ComponentBaseTest { + + protected static final String ADD_ECOMP_USER_CREDENTIALS = "AddECOMPUserCredentials"; + protected static final String DELETE_ECOMP_USER_CREDENTIALS = "DeleteECOMPUserCredentials"; + protected static final String GET_ECOMP_USER_CREDENTIALS = "GetECOMPUserCredentials"; + + public static final String contentTypeHeaderData = "application/json"; + public static final String acceptHeaderData = "application/json"; + + public static final int STATUS_CODE_SUCCESS = 200; + public static final int STATUS_CODE_SUCSESS_CREATED = 201; + public static final int STATUS_CODE_SUCCESS_DELETE_GET = 200; + public static final int STATUS_CODE_INVALID_CONTENT = 400; + public static final int STATUS_CODE_MISSING_DATA = 400; + public static final int STATUS_CODE_MISSING_INFORMATION = 403; + public static final int STATUS_CODE_RESTRICTED_ACCESS = 403; + + public static final int STATUS_CODE_NOT_FOUND = 404; + public static final int STATUS_CODE_RESTRICTED_OPERATION = 409; + + protected static Gson gson = new Gson(); + protected ConsumerDataDefinition consumerDataDefinition; + protected User sdncAdminUserDetails; + protected User sdncDesignerUserDetails; + protected User sdncTesterUserDetails; + protected User sdncGovernorUserDetails; + protected User sdncOpsUserDetails; + + public ManageEcompConsumerCredentials() { + super(name, ManageEcompConsumerCredentials.class.getName()); + } + + @Rule + public static TestName name = new TestName(); + + protected String salt = "123456789012345678901234567890ab"; + protected String password = "123456789012345678901234567890ab123456789012345678901234567890ab"; + protected String ecompUser = "benny"; + + protected Long consumerDetailsLastupdatedtime; + + @BeforeMethod + public void init() throws Exception { + sdncAdminUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncDesignerUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncTesterUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + sdncGovernorUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR); + sdncOpsUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.OPS); + + consumerDataDefinition = new ConsumerDataDefinition(); + consumerDataDefinition.setConsumerName(ecompUser); + consumerDataDefinition.setConsumerPassword(password); + consumerDataDefinition.setConsumerSalt(salt); + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + + } + + // US563681 manage ECOMP consumer credentials - DELETE/GET + @Test + public void deleteEcompCredentialsMethodDelete() throws Exception { + // Create Consumer + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + AssertJUnit.assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + AssertJUnit.assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + // Delete consumer + // DbUtils.deleteFromEsDbByPattern("_all"); + DbUtils.cleanAllAudits(); + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncAdminUserDetails); + AssertJUnit.assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS_DELETE_GET, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCCESS_DELETE_GET); + // Get Consumer to verify that consumer user does not exist + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + AssertJUnit.assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + } + + //// US561728 CREATE ECOMP consumer credentials + @Test + public void createEcompCredentialsMethodPost() throws Exception { + // Create Consumer + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // parse updated response to javaObject + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + // Validate actual consumerData to returned from response + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + } + + @Test(enabled = false) + public void createEcompCredentialsUserAlreayExist() throws Exception { + // Create Consumer + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + + // Create consumer which already exists with different password and Salt + DbUtils.deleteFromEsDbByPattern("_all"); + consumerDataDefinition.setConsumerPassword("zxcvb"); + consumerDataDefinition.setConsumerSalt("1234567890qwertyuiop1234567890as"); + createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer with new data + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + // Delete Consumer + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void createEcompCredentialsByDesigner() throws Exception { // HttpCspUserId + // header + // contains + // Designer + // UserId + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncDesignerUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_RESTRICTED_OPERATION, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncDesignerUserDetails, ActionStatus.RESTRICTED_OPERATION); + } + + @Test + public void createEcompCredentialsByTester() throws Exception { // HttpCspUserId + // header + // contains + // Tester + // UserId + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncTesterUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_RESTRICTED_OPERATION, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncTesterUserDetails, ActionStatus.RESTRICTED_OPERATION); + } + + @Test + public void createEcompCredentialsByOps() throws Exception { // HttpCspUserId + // header + // contains + // OPS + // UserId + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, sdncOpsUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_RESTRICTED_OPERATION, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncOpsUserDetails, ActionStatus.RESTRICTED_OPERATION); + } + + @Test + public void createEcompCredentialsByGovernor() throws Exception { // HttpCspUserId + // header + // contains + // Governor + // UserId + // Create + // Consumer + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncGovernorUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_RESTRICTED_OPERATION, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncGovernorUserDetails, ActionStatus.RESTRICTED_OPERATION); + } + + @Test + public void createEcompCredentialsByNoExistingIUser() throws Exception { + User noSdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + noSdncUserDetails.setRole("blabla"); + noSdncUserDetails.setUserId("bt750h"); + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, noSdncUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_RESTRICTED_OPERATION, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_ACCESS.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser( + consumerDataDefinition.getConsumerName() + "," + consumerDataDefinition.getConsumerSalt().toLowerCase() + + "," + consumerDataDefinition.getConsumerPassword()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("")); + expectedEcomConsumerAuditJavaObject.setModifier("(" + noSdncUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + // user name + @Test + public void createEcompCredentialsUserNameIsNull() throws Exception { + consumerDataDefinition.setConsumerName(null); // SVC4528 + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_DATA, + createConsumerRest.getErrorCode().intValue()); + // verify taht consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerSalt().toLowerCase() + "," + + consumerDataDefinition.getConsumerPassword()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer name")); + expectedEcomConsumerAuditJavaObject + .setModifier(sdncAdminUserDetails.getFullName() + "(" + sdncAdminUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + @Test + public void createEcompCredentialsUserNameIsEmpty() throws Exception { + consumerDataDefinition.setConsumerName(""); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerSalt().toLowerCase() + "," + + consumerDataDefinition.getConsumerPassword()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer name")); + expectedEcomConsumerAuditJavaObject + .setModifier(sdncAdminUserDetails.getFullName() + "(" + sdncAdminUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + @Test + public void createEcompCredentialsUserNameIsNotUTF8() throws Exception { + consumerDataDefinition.setConsumerName("בני"); // SVC4528 + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + } + + @Test + public void createEcompCredentialsUserNameMaxLength() throws Exception { + consumerDataDefinition.setConsumerName( + "_ABCD-.abcdqwertyuiopasdfghjklzxcvbnmqw1234567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890pf34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfgghjklqwertyuiopzaiutrewasdfghjklqwertyuiopzasxcdferf123456.-"); // SVC4528 + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Validate actual consumerData to returned from response + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + // Delete Consumer + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void createEcompCredentialsUserNameExceedMaxLength() throws Exception { + consumerDataDefinition.setConsumerName( + "_ABCD-.abcdqwertyuiopasdfghjklzxcvbnmqw1234567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890pf34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfgghjklqwertyuiopzaiutrewasdfghjklqwertyuiopzasxcdferf123456.--"); // SVC4528 + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.EXCEEDS_LIMIT, "Consumer name", "255"); + } + + @Test + public void createEcompCredentialsUserNameLastCharIsDash() throws Exception { // allowed + consumerDataDefinition.setConsumerName("ABCD34567890pf34567890poiutrew-"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // parse updated response to javaObject , Validate actual consumerData + // to returned from response + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + // Delete Consumer + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void createEcompCredentialsUserNameLastCharIsPeriod() throws Exception { + consumerDataDefinition.setConsumerName("ABCD34567890pf34567890poiutrew."); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // parse updated response to javaObject , Validate actual consumerData + // to returned from response + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + // Delete Consumer + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void createEcompCredentialsUserNameLastCharIsUnderscore() throws Exception { + consumerDataDefinition.setConsumerName("ABCD34567890pf34567890poiutrew_"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // parse updated response to javaObject , Validate actual consumerData + // to returned from response + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + // Delete Consumer + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void createEcompCredentialsUserNameFirstCharIsUnderscore() throws Exception { + consumerDataDefinition.setConsumerName("_ABCD34567890pf34567890poiutre"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // parse updated response to javaObject , Validate actual consumerData + // to returned from response + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + // Delete Consumer + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void createEcompCredentialsUserNameFirstCharIsPeriod() throws Exception { + consumerDataDefinition.setConsumerName(".ABCD34567890pf34567890poiutre"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.INVALID_CONTENT_PARAM, "Consumer name"); + } + + @Test + public void createEcompCredentialsUserNameFirstCharIsDash() throws Exception { // Not + // allowed + consumerDataDefinition.setConsumerName("-ABCD34567890pf34567890poiutre"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.INVALID_CONTENT_PARAM, "Consumer name"); + } + + /// Password + @Test + public void createEcompCredentialsPasswordIsNull() throws Exception { + consumerDataDefinition.setConsumerPassword(null); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_DATA, + createConsumerRest.getErrorCode().intValue()); + // verify taht consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName() + "," + + consumerDataDefinition.getConsumerSalt().toLowerCase()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer password")); + expectedEcomConsumerAuditJavaObject + .setModifier(sdncAdminUserDetails.getFullName() + "(" + sdncAdminUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + @Test + public void createEcompCredentialsPasswordIsEmpty() throws Exception { + consumerDataDefinition.setConsumerPassword(""); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_DATA, + createConsumerRest.getErrorCode().intValue()); + // verify taht consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName() + "," + + consumerDataDefinition.getConsumerSalt().toLowerCase()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer password")); + expectedEcomConsumerAuditJavaObject + .setModifier(sdncAdminUserDetails.getFullName() + "(" + sdncAdminUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + @Test + public void createEcompCredentialsPasswordMaxLength() throws Exception { // password + // must + // be + // 64 + // chars + consumerDataDefinition.setConsumerPassword("123456789012345678901234567890ab123456789012345678901234567890ab"); + // Create Consumer + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // parse updated response to javaObject + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + // Validate actual consumerData to returned from response + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + // Delete Consumer + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void createEcompCredentialsPasswordExceeedMaxLength() throws Exception { // password + // must + // be + // 64 + // chars + consumerDataDefinition.setConsumerPassword("123456789012345678901234567890ab123456789012345678901234567890ab1"); + // Create Consumer + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.INVALID_LENGTH, "Consumer password", "64"); + } + + @Test + public void createEcompCredentiaPasswordValid() throws Exception { + // Password Contains lowercase/uppercase characters and numbers - + // convert upper case letter to lower + consumerDataDefinition.setConsumerPassword("ABCabc1234567890POImnb12345678901234567890POIUzxcvbNMASDFGhjkl12"); + // Create Consumer + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + + } + + //// Salt + @Test + public void createEcompCredentialsSaltIsNull() throws Exception { + // Length must be 32 characters + consumerDataDefinition.setConsumerSalt(null); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_DATA, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName() + "," + + consumerDataDefinition.getConsumerPassword().toLowerCase()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer salt")); + expectedEcomConsumerAuditJavaObject + .setModifier(sdncAdminUserDetails.getFullName() + "(" + sdncAdminUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + + } + + @Test + public void createEcompCredentialsSaltIsEmpty() throws Exception { + consumerDataDefinition.setConsumerSalt(""); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_DATA, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName() + "," + + consumerDataDefinition.getConsumerPassword().toLowerCase()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer salt")); + expectedEcomConsumerAuditJavaObject + .setModifier(sdncAdminUserDetails.getFullName() + "(" + sdncAdminUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + @Test + public void createEcompCredentialsSaltLengthLessThan32() throws Exception { + consumerDataDefinition.setConsumerSalt("123456789012345678901234567890a"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.INVALID_LENGTH, "Consumer salt"); + + } + + // Bug + @Test + public void createEcompCredentialsSaltLengthMoreThan32() throws Exception { // Length + // must + // be + // 32 + // characters + // - + // SVC4529 + // "Error: + // Invalid + // Content. + // %1 + // exceeds + // limit + // of + // %2 + // characters." + consumerDataDefinition.setConsumerSalt("123456789012345678901234567890abc"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.INVALID_LENGTH, "Consumer salt"); + + } + + @Test + public void createEcompCredentialsSaltUppercaseCharacters() throws Exception { + // Contains uppercase characters– exception invalid content + consumerDataDefinition.setConsumerSalt("123456789012345678901234567890AB"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // verify that consumer didn't created + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_CONTENT_PARAM.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName() + "," + + consumerDataDefinition.getConsumerSalt() + "," + consumerDataDefinition.getConsumerPassword()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer salt")); + expectedEcomConsumerAuditJavaObject + .setModifier(sdncAdminUserDetails.getFullName() + "(" + sdncAdminUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + // USER_ID (USER_ID is taken from USER_ID header) + + @Test + public void createEcompCredentialsHttpCspUserIdIsEmpty() throws Exception { + // USER_ID is taken from USER_ID header + sdncAdminUserDetails.setUserId(""); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_INFORMATION, + createConsumerRest.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName() + "," + + consumerDataDefinition.getConsumerSalt() + "," + consumerDataDefinition.getConsumerPassword()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer salt")); + expectedEcomConsumerAuditJavaObject.setModifier(""); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + @Test + public void createEcompCredentialsHttpCspUserIdIsNull() throws Exception { // USER_ID + // is + // taken + // from + // USER_ID + // header + sdncAdminUserDetails.setUserId(null); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_INFORMATION, + createConsumerRest.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName() + "," + + consumerDataDefinition.getConsumerSalt() + "," + consumerDataDefinition.getConsumerPassword()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer salt")); + expectedEcomConsumerAuditJavaObject.setModifier(""); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + @Test + public void createEcompCredentialsHttpCspUserIdHeaderIsMissing() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumerHttpCspAtuUidIsMissing(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_INFORMATION, + createConsumerRest.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName() + "," + + consumerDataDefinition.getConsumerSalt() + "," + consumerDataDefinition.getConsumerPassword()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("Consumer salt")); + expectedEcomConsumerAuditJavaObject.setModifier(""); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + ADD_ECOMP_USER_CREDENTIALS); + } + + // add USER_ID in json body + @Test + public void createEcompCredentiaJsonBodyContainLastModfierAtuid() throws Exception { + // Add USER_ID (not admin) to json - we will ignore and create the user + HashMap jsonMap = new HashMap(); + jsonMap.put("consumerName", "benny"); + jsonMap.put("consumerPassword", "123456789012345678901234567890ab123456789012345678901234567890ab"); + jsonMap.put("consumerSalt", "123456789012345678901234567890ab"); + jsonMap.put("lastModfierAtuid", "cs0008"); // designer + Gson gson = new Gson(); + ConsumerDataDefinition consumer = gson.fromJson(jsonMap.toString(), ConsumerDataDefinition.class); + + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumer, sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Validate actual consumerData to returned from response + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumer, getConsumerDataObject); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumer, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumer, sdncAdminUserDetails, + STATUS_CODE_SUCSESS_CREATED); + // Delete consumer + ConsumerRestUtils.deleteConsumer(consumer, sdncAdminUserDetails); + } + + @Test + public void createEcompCredentialsUserNameNotAllowedCharacters() throws Exception { + char invalidChars[] = { '`', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '+', '=', '<', '>', '?', '/', + '"', ':', '}', ']', '[', '{', '|', '\\', ' ', '\t', '\n' }; + for (int i = 0; i < invalidChars.length; i++) { + DbUtils.deleteFromEsDbByPattern("_all"); + consumerDataDefinition.setConsumerName(invalidChars[i] + "ABCdef123"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.INVALID_CONTENT_PARAM, "Consumer name"); + } + } + + @Test + public void createEcompCredentialsPasswordIsInvalid() throws Exception { + char invalidChars[] = { '`', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '+', '=', '<', '>', '?', '/', + '"', ':', '}', ']', '[', '{', '|', '\\', ' ', '\t', '\n' }; + for (int i = 0; i < invalidChars.length; i++) { + DbUtils.deleteFromEsDbByPattern("_all"); + consumerDataDefinition.setConsumerPassword( + "ABC" + invalidChars[i] + "ABCabc1234567890POImnb12345678901234567890POIUzxcvbNMASDFGhj"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.INVALID_CONTENT_PARAM, "Consumer password"); + } + } + + @Test + public void createEcompCredentialsSaltNotAllowedCharacters() throws Exception { // Salt + // must + // be + // 32 + // chars + char invalidChars[] = { '`', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '+', '=', '<', '>', '?', '/', + '"', ':', '}', ']', '[', '{', '|', '\\', ' ', '\t', '\n' }; + for (int i = 0; i < invalidChars.length; i++) { + DbUtils.deleteFromEsDbByPattern("_all"); + consumerDataDefinition.setConsumerSalt(invalidChars[i] + "1234567890123456789012345678901"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_INVALID_CONTENT, + createConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.createEcompConsumerAuditFailure(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.INVALID_CONTENT_PARAM, "Consumer salt"); + } + } + + @Test + public void createEcompCredentialsPasswordEncoded() throws Exception { + consumerDataDefinition.setConsumerPassword("0a0dc557c3bf594b1a48030e3e99227580168b21f44e285c69740b8d5b13e33b"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // parse updated response to javaObject + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + // Validate actual consumerData to returned from response + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(ADD_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCSESS_CREATED); + } + + // + + @Test + public void deleteEcompUserAlreayDeleted() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + // Delete ECOMP consumer + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS_DELETE_GET, + deleteConsumerRest.getErrorCode().intValue()); + // Try to delete ECOMP consumer already deleted + DbUtils.deleteFromEsDbByPattern("_all"); + deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.ECOMP_USER_NOT_FOUND, consumerDataDefinition.getConsumerName()); + } + + @Test + public void deleteEcompUserByTester() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + // Delete consumer + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncTesterUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_OPERATION, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncTesterUserDetails, ActionStatus.RESTRICTED_OPERATION); + // Verify that consumer is not deleted + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + } + + @Test + public void deleteEcompUserByOps() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + // Delete consumer + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncOpsUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_OPERATION, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncOpsUserDetails, ActionStatus.RESTRICTED_OPERATION); + // Verify that consumer is not deleted + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + } + + @Test + public void deleteEcompUserByGovernor() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + // Delete consumer + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncGovernorUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_OPERATION, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncGovernorUserDetails, ActionStatus.RESTRICTED_OPERATION); + // Verify that consumer is not deleted + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + } + + @Test + public void deleteEcompUserByDesigner() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + // Delete consumer + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncDesignerUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_OPERATION, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncDesignerUserDetails, ActionStatus.RESTRICTED_OPERATION); + // Verify that consumer is not deleted + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + } + + @Test + public void deleteEcompUserByNoExistingIUser() throws Exception { + User noSdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + noSdncUserDetails.setRole("blabla"); + noSdncUserDetails.setUserId("bt750h"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + // Delete consumer + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, noSdncUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_ACCESS, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_ACCESS.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(ADD_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("")); + expectedEcomConsumerAuditJavaObject.setModifier("(" + noSdncUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + DELETE_ECOMP_USER_CREDENTIALS); + // Verify that consumer is not deleted + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + } + + @Test + public void deleteEcompCredentialsUserDoesNotExist() throws Exception { + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.ECOMP_USER_NOT_FOUND, consumerDataDefinition.getConsumerName()); + + } + + @Test + public void deleteEcompCredentialsUserNameIsNull() throws Exception { + DbUtils.deleteFromEsDbByPattern("_all"); + consumerDataDefinition.setConsumerName(null); + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.ECOMP_USER_NOT_FOUND, consumerDataDefinition.getConsumerName()); + } + + @Test + public void deleteEcompCredentialsUserNameMaxLength() throws Exception { + DbUtils.deleteFromEsDbByPattern("_all"); + consumerDataDefinition.setConsumerName( + "_BCD-.abcdqwertyuiopasdfghjklzxcvbnmqw1234567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890pf34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfgghjklqwertyuiopzaiutrewasdfghjklqwertyuiopzasxcdferf123456.--"); // SVC4528 + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.ECOMP_USER_NOT_FOUND, consumerDataDefinition.getConsumerName()); + } + + @Test + public void deleteEcompCredentialsUserNameExceedMaxLength() throws Exception { + DbUtils.deleteFromEsDbByPattern("_all"); + consumerDataDefinition.setConsumerName( + "_XXXBCD-.abcdqwertyuiopasdfghjklzxcvbnmqw1234567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890pf34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfgghjklqwertyuiopzaiutrewasdfghjklqwertyuiopzasxcdferf123456.--"); // SVC4528 + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.ECOMP_USER_NOT_FOUND, consumerDataDefinition.getConsumerName()); + } + + @Test + public void deleteEcompCredentialsHttpCspUserIdHeaderIsMissing() throws Exception { + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse createConsumerRest = ConsumerRestUtils.deleteConsumerHttpCspAtuUidIsMissing(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_MISSING_INFORMATION, + createConsumerRest.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(DELETE_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc()); + expectedEcomConsumerAuditJavaObject.setModifier(""); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + DELETE_ECOMP_USER_CREDENTIALS); + } + + @Test + public void deleteEcompCredentialsNameIsUpperCase() throws Exception { + consumerDataDefinition.setConsumerName("benny"); + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + // Delete consumer + DbUtils.deleteFromEsDbByPattern("_all"); + consumerDataDefinition.setConsumerName("BENNY"); + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + deleteConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(DELETE_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.ECOMP_USER_NOT_FOUND, consumerDataDefinition.getConsumerName()); + // Get Consumer to verify that consumer user was not deleted + consumerDataDefinition.setConsumerName("benny"); + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + } + + @Test + public void getEcompCredentialsMethodGet() throws Exception { + // Create Consumer + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // parse updated response to javaObject + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + // Validate actual consumerData to returned from response + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + DbUtils.deleteFromEsDbByPattern("_all"); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(GET_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCCESS_DELETE_GET); + // Delete consumer + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void getEcompUserAlreayDeleted() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + // Delete ECOMP consumer + RestResponse deleteConsumerRest = ConsumerRestUtils.deleteConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS_DELETE_GET, + deleteConsumerRest.getErrorCode().intValue()); + DbUtils.deleteFromEsDbByPattern("_all"); + // Try to get ECOMP consumer already deleted + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(GET_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.ECOMP_USER_NOT_FOUND, consumerDataDefinition.getConsumerName()); + } + + @Test + public void getEcompUserByTester() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer by Tester user + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncTesterUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_OPERATION, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(GET_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncTesterUserDetails, ActionStatus.RESTRICTED_OPERATION); + // Get Consumer by Admin + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void getEcompUserByOps() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer by Ops user + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncOpsUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_OPERATION, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(GET_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncOpsUserDetails, ActionStatus.RESTRICTED_OPERATION); + // Get Consumer by Admin + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void getEcompUserByGovernor() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer by Ops user + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncGovernorUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_OPERATION, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(GET_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncGovernorUserDetails, ActionStatus.RESTRICTED_OPERATION); + // Get Consumer by Admin + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void getEcompUserByDesigner() throws Exception { + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // Get Consumer by Designer user + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncDesignerUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_OPERATION, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(GET_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncDesignerUserDetails, ActionStatus.RESTRICTED_OPERATION); + // Get Consumer by Admin + getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } + + @Test + public void getEcompUserByNoExistingIUser() throws Exception { + User noSdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + noSdncUserDetails.setRole("blabla"); + noSdncUserDetails.setUserId("bt750h"); + // Get Consumer + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, noSdncUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_RESTRICTED_ACCESS, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_ACCESS.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(GET_ECOMP_USER_CREDENTIALS); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc("")); + expectedEcomConsumerAuditJavaObject.setModifier("(" + noSdncUserDetails.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, + GET_ECOMP_USER_CREDENTIALS); + } + + @Test + public void getEcompCredentialsUserDoesNotExist() throws Exception { + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(GET_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.ECOMP_USER_NOT_FOUND, consumerDataDefinition.getConsumerName()); + + } + + @Test + public void getEcompCredentialsUserNameIsNull() throws Exception { + DbUtils.deleteFromEsDbByPattern("_all"); + consumerDataDefinition.setConsumerName(null); + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_NOT_FOUND, + getConsumerRest.getErrorCode().intValue()); + // Audit validation + AuditValidationUtils.deleteEcompConsumerAuditFailure(GET_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, ActionStatus.ECOMP_USER_NOT_FOUND, consumerDataDefinition.getConsumerName()); + } + + @Test + public void getEcompCredentialsUserNameMaxLength() throws Exception { + consumerDataDefinition.setConsumerName( + "_ABCD-.abcdqwertyuiopasdfghjklzxcvbnmqw1234567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfg34567890pf34567890poiutrewasdfghjklqwertyuiopzaiutrewasdfgghjklqwertyuiopzaiutrewasdfghjklqwertyuiopzasxcdferf123456.-"); // SVC4528 + RestResponse createConsumerRest = ConsumerRestUtils.createConsumer(consumerDataDefinition, + sdncAdminUserDetails); + assertEquals("Check response code after create Consumer", STATUS_CODE_SUCSESS_CREATED, + createConsumerRest.getErrorCode().intValue()); + // parse updated response to javaObject + ConsumerDataDefinition getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(createConsumerRest); + // Validate actual consumerData to returned from response + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Get Consumer + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse getConsumerRest = ConsumerRestUtils.getConsumer(consumerDataDefinition, sdncAdminUserDetails); + assertEquals("Check response code after get Consumer", STATUS_CODE_SUCCESS, + getConsumerRest.getErrorCode().intValue()); + getConsumerDataObject = ConsumerRestUtils.parseComsumerResp(getConsumerRest); + ConsumerRestUtils.validateConsumerReqVsResp(consumerDataDefinition, getConsumerDataObject); + // Audit validation + AuditValidationUtils.ecompConsumerAuditSuccess(GET_ECOMP_USER_CREDENTIALS, consumerDataDefinition, + sdncAdminUserDetails, STATUS_CODE_SUCCESS_DELETE_GET); + // Delete consumer + ConsumerRestUtils.deleteConsumer(consumerDataDefinition, sdncAdminUserDetails); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/UuidTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/UuidTest.java new file mode 100644 index 0000000000..acb7e15c6c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/general/UuidTest.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.general; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.CatalogRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.common.api.Constants; +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +public class UuidTest extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public UuidTest() { + super(name, UuidTest.class.getName()); + config = Config.instance(); + } + + @Test + public void testE2EUuidHeaderReturnedAndPreserved() throws IOException { + UUID randomUUID = UUID.randomUUID(); + String uuidStr = randomUUID.toString(); + RestResponse allTagsTowardsCatalogFe = CatalogRestUtils.getAllCategoriesTowardsCatalogFeWithUuid(uuidStr); + AssertJUnit.assertEquals(allTagsTowardsCatalogFe.getErrorCode(), new Integer(200)); + List list = allTagsTowardsCatalogFe.getHeaderFields().get(Constants.X_ECOMP_REQUEST_ID_HEADER); + // check that header is returned + AssertJUnit.assertTrue(list != null && !list.isEmpty()); + String receivedUuid = list.get(0); + // Check that same uuid returned + AssertJUnit.assertEquals(uuidStr, receivedUuid); + } + + @Test + public void testUuidHeaderGeneratedBe() throws IOException { + RestResponse allTagsTowardsCatalogBe = CatalogRestUtils.getAllCategoriesTowardsCatalogBe(); + List list = allTagsTowardsCatalogBe.getHeaderFields().get(Constants.X_ECOMP_REQUEST_ID_HEADER); + // check that response was OK + assertEquals(allTagsTowardsCatalogBe.getErrorCode(), new Integer(200)); + // check that header is returned + assertTrue(list != null && !list.isEmpty()); + String uuid = list.get(0); + // Check there is no conversion error + UUID.fromString(uuid); + } + + @Test + public void testE2EOptionsNoUuid() throws IOException { + RestResponse allTagsTowardsCatalogFe = ResourceRestUtils.sendOptionsTowardsCatalogFeWithUuid(); + assertEquals(allTagsTowardsCatalogFe.getErrorCode(), new Integer(200)); + List list = allTagsTowardsCatalogFe.getHeaderFields().get(Constants.X_ECOMP_REQUEST_ID_HEADER); + // check that header is returned (generated by BE) + assertTrue(list != null && !list.isEmpty()); + String receivedUuid = list.get(0); + // Check there is no conversion error + UUID.fromString(receivedUuid); + } + + @Test + public void testE2EMethodNotAllowedWithUuid() throws IOException { + UUID randomUUID = UUID.randomUUID(); + String uuidStr = randomUUID.toString(); + RestResponse allTagsTowardsCatalogFe = ResourceRestUtils + .putAllCategoriesTowardsCatalogFeWithUuidNotAllowed(uuidStr); + assertEquals(allTagsTowardsCatalogFe.getErrorCode(), new Integer(405)); + List list = allTagsTowardsCatalogFe.getHeaderFields().get(Constants.X_ECOMP_REQUEST_ID_HEADER); + // check that header is returned (generated by BE) + assertTrue(list != null && !list.isEmpty()); + String receivedUuid = list.get(0); + // Check that same uuid returned + assertEquals(uuidStr, receivedUuid); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/CsarUtilsTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/CsarUtilsTest.java new file mode 100644 index 0000000000..650ed619b7 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/CsarUtilsTest.java @@ -0,0 +1,460 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.imports; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.FileUtils; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ArtifactUiDownloadData; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.common.util.YamlToObjectConverter; +import org.testng.annotations.Test; +import org.yaml.snakeyaml.Yaml; + +public class CsarUtilsTest extends ComponentBaseTest { + + public static final String ASSET_TOSCA_TEMPLATE = "assettoscatemplate"; + + @Rule + public static TestName name = new TestName(); + + public CsarUtilsTest() { + super(name, CsarUtilsTest.class.getName()); + } + + @Test(enabled = true) + public void createServiceCsarBasicTest() throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.VENDOR_LICENSE, resourceVF, UserRoleEnum.DESIGNER, + true, true); + resourceVF = (Resource) AtomicOperationUtils + .changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF, service, UserRoleEnum.DESIGNER, true); + + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + byte[] downloadCSAR = downloadCSAR(sdncModifierDetails, service); + + csarBasicValidation(service, downloadCSAR); + } + + @Test(enabled = true) + public void createResourceCsarBasicTest() throws Exception { + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + resourceVF = (Resource) AtomicOperationUtils + .changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + byte[] downloadCSAR = downloadCSAR(sdncModifierDetails, resourceVF); + + csarBasicValidation(resourceVF, downloadCSAR); + } + + @Test(enabled = true) + public void createServiceCsarInclDeploymentArtTest() throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + + Resource resourceVF1 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + Resource resourceVF2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + + resourceVF1 = (Resource) AtomicOperationUtils + .changeComponentState(resourceVF1, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + resourceVF2 = (Resource) AtomicOperationUtils + .changeComponentState(resourceVF2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF1, service, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF2, service, UserRoleEnum.DESIGNER, true); + + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.YANG_XML, service, UserRoleEnum.DESIGNER, true, true); + + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + byte[] downloadCSAR = downloadCSAR(sdncModifierDetails, service); + + csarBasicValidation(service, downloadCSAR); + + validateServiceCsar(resourceVF1, resourceVF2, service, downloadCSAR, 3, 5, 1); + } + + @Test(enabled = true) + public void createResourceCsarInclDeploymentArtTest() throws Exception { + + Resource resourceVF1 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.YANG_XML, resourceVF1, UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT_ARTIFACT, resourceVF1, UserRoleEnum.DESIGNER, true, true); + + resourceVF1 = (Resource) AtomicOperationUtils + .changeComponentState(resourceVF1, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + byte[] downloadCSAR = downloadCSAR(sdncModifierDetails, resourceVF1); + + csarBasicValidation(resourceVF1, downloadCSAR); + + validateVFCsar(resourceVF1, downloadCSAR, 1, 0, 1, 1); + } + + private void csarBasicValidation(Component mainComponent, byte[] downloadCSAR) { + try (ByteArrayInputStream ins = new ByteArrayInputStream(downloadCSAR); + ZipInputStream zip = new ZipInputStream(ins);) { + + String resourceYaml = null; + byte[] buffer = new byte[1024]; + ZipEntry nextEntry = zip.getNextEntry(); + StringBuffer sb = new StringBuffer(); + int len; + + while ((len = zip.read(buffer)) > 0) { + sb.append(new String(buffer, 0, len)); + } + + assertTrue(nextEntry.getName().equals("TOSCA-Metadata/TOSCA.meta")); + + sb.setLength(0); + nextEntry = zip.getNextEntry(); + + while ((len = zip.read(buffer)) > 0) { + sb.append(new String(buffer, 0, len)); + } + + resourceYaml = sb.toString(); + + YamlToObjectConverter yamlToObjectConverter = new YamlToObjectConverter(); + ArtifactDefinition artifactDefinition = mainComponent.getToscaArtifacts() + .get(ASSET_TOSCA_TEMPLATE); + String fileName = artifactDefinition.getArtifactName(); + assertEquals("Tosca-Template file name: ", "Definitions/" + fileName, nextEntry.getName()); + assertTrue("Tosca template Yaml validation: ", yamlToObjectConverter.isValidYaml(resourceYaml.getBytes())); + + ins.close(); + zip.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void validateServiceCsar(Component certifiedVFC1, Component certifiedVFC2, Service fetchedService, + byte[] resultByte, int toscaEntryIndexToPass, int generatorEntryIndexToPass, + int deploymentArtifactIndexToPass) { + + // TODO Test to validate everything is right (comment out after testing) + /*try { + FileUtils.writeByteArrayToFile(new File("c:/TestCSAR/" + fetchedService.getName() + ".zip"), resultByte); + } catch (IOException e) { + // Auto-generated catch block + e.printStackTrace(); + }*/ + + try (ByteArrayInputStream ins = new ByteArrayInputStream(resultByte); + ZipInputStream zip = new ZipInputStream(ins);) { + + String resourceYaml = null; + byte[] buffer = new byte[1024]; + ZipEntry nextEntry = zip.getNextEntry(); + StringBuffer sb = new StringBuffer(); + int len; + + while ((len = zip.read(buffer)) > 0) { + sb.append(new String(buffer, 0, len)); + } + + assertTrue(nextEntry.getName().equals("TOSCA-Metadata/TOSCA.meta")); + + YamlToObjectConverter yamlToObjectConverter = new YamlToObjectConverter(); + + int toscaEntryIndex = 0; + int generatorEntryIndex = 0; + int deploymentArtifactIndex = 0; + String fileName = null; + ArtifactDefinition artifactDefinition; + Component componentToValidate = null; + + artifactDefinition = fetchedService.getToscaArtifacts().get(ASSET_TOSCA_TEMPLATE); + String serviceFileName = artifactDefinition.getArtifactName(); + artifactDefinition = certifiedVFC1.getToscaArtifacts().get(ASSET_TOSCA_TEMPLATE); + String vfc1FileName = artifactDefinition.getArtifactName(); + artifactDefinition = certifiedVFC2.getToscaArtifacts().get(ASSET_TOSCA_TEMPLATE); + String vfc2FileName = artifactDefinition.getArtifactName(); + + while ((nextEntry = zip.getNextEntry()) != null) { + sb.setLength(0); + + while ((len = zip.read(buffer)) > 0) { + sb.append(new String(buffer, 0, len)); + } + + String entryName = nextEntry.getName(); + + resourceYaml = sb.toString(); + if (entryName.contains(serviceFileName)) { + componentToValidate = fetchedService; + fileName = "Definitions/" + serviceFileName; + + assertEquals("Validate entry Name", (fileName), nextEntry.getName()); + assertTrue(yamlToObjectConverter.isValidYaml(resourceYaml.getBytes())); + validateContent(resourceYaml, componentToValidate); + ++toscaEntryIndex; + continue; + } + + if (entryName.contains(vfc1FileName)) { + componentToValidate = certifiedVFC1; + fileName = "Definitions/" + vfc1FileName; + + assertEquals("Validate entry Name", (fileName), nextEntry.getName()); + assertTrue(yamlToObjectConverter.isValidYaml(resourceYaml.getBytes())); + validateContent(resourceYaml, componentToValidate); + ++toscaEntryIndex; + continue; + } + if (entryName.contains(vfc2FileName)) { + componentToValidate = certifiedVFC2; + fileName = "Definitions/" + vfc2FileName; + + assertEquals("Validate entry Name", (fileName), nextEntry.getName()); + assertTrue(yamlToObjectConverter.isValidYaml(resourceYaml.getBytes())); + validateContent(resourceYaml, componentToValidate); + ++toscaEntryIndex; + continue; + } + + if (entryName.contains(".xml") && !entryName.startsWith("Artifacts/AAI")) { + ++deploymentArtifactIndex; + continue; + } + + if (entryName.startsWith("Artifacts/AAI")) { + ++generatorEntryIndex; + continue; + } + + assertTrue("Unexpected entry: " + entryName, true); + } + assertEquals("Validate amount of entries", toscaEntryIndexToPass, toscaEntryIndex); + assertEquals("Validate amount of generated AAI artifacts", generatorEntryIndexToPass, generatorEntryIndex); + assertEquals("Validate amount of generated Deployment artifacts", deploymentArtifactIndexToPass, + deploymentArtifactIndex); + + ins.close(); + zip.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void validateVFCsar(Component certifiedVF, byte[] resultByte, int toscaEntryIndexToPass, int ymlDeploymentArtifactIndexToPass, + int xmlDeploymentArtifactIndexToPass, int heatEnvDeploymentArtifactIndexToPass) { + + // TODO Test to validate everything is right (comment out after testing) + /*try { + FileUtils.writeByteArrayToFile(new File("c:/TestCSAR/" + fetchedService.getName() + ".zip"), resultByte); + } catch (IOException e) { + // Auto-generated catch block + e.printStackTrace(); + }*/ + + try (ByteArrayInputStream ins = new ByteArrayInputStream(resultByte); + ZipInputStream zip = new ZipInputStream(ins);) { + + String resourceYaml = null; + byte[] buffer = new byte[1024]; + ZipEntry nextEntry = zip.getNextEntry(); + StringBuffer sb = new StringBuffer(); + int len; + + while ((len = zip.read(buffer)) > 0) { + sb.append(new String(buffer, 0, len)); + } + + assertTrue(nextEntry.getName().equals("TOSCA-Metadata/TOSCA.meta")); + + YamlToObjectConverter yamlToObjectConverter = new YamlToObjectConverter(); + + int toscaEntryIndex = 0; + int ymlEntryIndex = 0; + int xmlArtifactsIndex = 0; + int heatEnvDeploymentArtifactIndex = 0; + String fileName = null; + ArtifactDefinition artifactDefinition; + Component componentToValidate = null; + + artifactDefinition = certifiedVF.getToscaArtifacts().get(ASSET_TOSCA_TEMPLATE); + String vfFileName = artifactDefinition.getArtifactName(); + + while ((nextEntry = zip.getNextEntry()) != null) { + sb.setLength(0); + + while ((len = zip.read(buffer)) > 0) { + sb.append(new String(buffer, 0, len)); + } + + String entryName = nextEntry.getName(); + + resourceYaml = sb.toString(); + if (entryName.contains(vfFileName)) { + componentToValidate = certifiedVF; + fileName = "Definitions/" + vfFileName; + + assertEquals("Validate entry Name", (fileName), nextEntry.getName()); + assertTrue(yamlToObjectConverter.isValidYaml(resourceYaml.getBytes())); + validateContent(resourceYaml, componentToValidate); + ++toscaEntryIndex; + continue; + } + + if (entryName.contains(".xml") && entryName.startsWith("Artifacts/")) { + ++xmlArtifactsIndex; + continue; + } + + if (entryName.contains(".sh") && entryName.startsWith("Artifacts/")) { + ++heatEnvDeploymentArtifactIndex; + continue; + } + + if (entryName.contains(".yml") && entryName.startsWith("Artifacts/")) { + ++ymlEntryIndex; + continue; + } + + assertTrue("Unexpected entry: " + entryName, false); + } + assertEquals("Validate amount of entries", toscaEntryIndexToPass, toscaEntryIndex); + assertEquals("Validate amount of YAML artifacts", ymlDeploymentArtifactIndexToPass, ymlEntryIndex); + assertEquals("Validate amount of generated XML artifacts", xmlDeploymentArtifactIndexToPass, + xmlArtifactsIndex); + assertEquals("Validate amount of generated HEAT ENV artifacts", heatEnvDeploymentArtifactIndexToPass, + heatEnvDeploymentArtifactIndex); + + ins.close(); + zip.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void validateContent(String content, Component component) { + Yaml yaml = new Yaml(); + + InputStream inputStream = new ByteArrayInputStream(content.getBytes()); + @SuppressWarnings("unchecked") + Map load = (Map) yaml.load(inputStream); + @SuppressWarnings("unchecked") + Map metadata = (Map) load.get("metadata"); + assertNotNull(metadata); + + String name = (String) metadata.get("name"); + assertNotNull(name); + assertEquals("Validate component name", component.getName(), name); + + String invariantUUID = (String) metadata.get("invariantUUID"); + assertNotNull(invariantUUID); + assertEquals("Validate component invariantUUID", component.getInvariantUUID(), invariantUUID); + + String UUID = (String) metadata.get("UUID"); + assertNotNull(UUID); + assertEquals("Validate component invariantUUID", component.getUUID(), UUID); + + String type = (String) metadata.get("type"); + assertNotNull(type); + if (component.getComponentType().equals(ComponentTypeEnum.SERVICE)) { + assertEquals("Validate component type", component.getComponentType().getValue(), type); + } else { + assertEquals("Validate component type", ((Resource) component).getResourceType(), + ResourceTypeEnum.valueOf(type)); + } + } + + private byte[] downloadCSAR(User sdncModifierDetails, Component createdComponent) throws Exception { + + String artifactUniqeId = createdComponent.getToscaArtifacts().get("assettoscacsar").getUniqueId(); + RestResponse getCsarResponse = null; + + switch (createdComponent.getComponentType()) { + case RESOURCE: + getCsarResponse = ArtifactRestUtils.downloadResourceArtifactInternalApi(createdComponent.getUniqueId(), + sdncModifierDetails, artifactUniqeId); + break; + case SERVICE: + getCsarResponse = ArtifactRestUtils.downloadServiceArtifactInternalApi(createdComponent.getUniqueId(), + sdncModifierDetails, artifactUniqeId); + break; + default: + break; + } + + assertNotNull(getCsarResponse); + BaseRestUtils.checkSuccess(getCsarResponse); + + ArtifactUiDownloadData artifactUiDownloadData = ResponseParser.parseToObject(getCsarResponse.getResponse(), + ArtifactUiDownloadData.class); + + assertNotNull(artifactUiDownloadData); + + byte[] fromUiDownload = artifactUiDownloadData.getBase64Contents().getBytes(); + byte[] decodeBase64 = Base64.decodeBase64(fromUiDownload); + + return decodeBase64; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ExportToscaTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ExportToscaTest.java new file mode 100644 index 0000000000..163504fbb0 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ExportToscaTest.java @@ -0,0 +1,458 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.imports; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.apache.commons.codec.binary.Base64; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ArtifactUiDownloadData; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstInputsMap; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceInput; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.InputsRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.BaseValidationUtils; +import org.openecomp.sdc.common.api.Constants; +import org.testng.annotations.Test; +import org.yaml.snakeyaml.Yaml; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; + +public class ExportToscaTest extends ComponentBaseTest { + @Rule + public static TestName name = new TestName(); + + public ExportToscaTest() { + super(name, ExportToscaTest.class.getName()); + } + + @Test(enabled = true) + public void exportVfModuleTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + Resource createdResource = createVfFromCSAR(sdncModifierDetails, "VSPPackage"); + + Map load = downloadAndParseToscaTemplate(sdncModifierDetails, createdResource); + assertNotNull(load); + Map topology_template = (Map) load.get("topology_template"); + assertNotNull(topology_template); + Map groups = (Map) topology_template.get("groups"); + assertNotNull(groups); + List groupsOrigin = createdResource.getGroups(); + + assertEquals("Validate groups size", groupsOrigin.size(), groups.size()); + for (GroupDefinition group : groupsOrigin) { + Map groupTosca = (Map) groups.get(group.getName()); + assertNotNull(groupTosca); + + Map metadata = (Map) groupTosca.get("metadata"); + assertNotNull(metadata); + + String invariantUUID; + String name; + String UUID; + String version; + Map properties = (Map) groupTosca.get("properties"); + + if (group.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE)) { + invariantUUID = (String) metadata.get("vfModuleModelInvariantUUID"); + name = (String) metadata.get("vfModuleModelName"); + UUID = (String) metadata.get("vfModuleModelUUID"); + version = (String) metadata.get("vfModuleModelVersion"); + assertNotNull(properties); + + String vf_module_type = (String) properties.get("vf_module_type"); + List props = group.getProperties(); + for (PropertyDataDefinition prop : props) { + if (prop.getName().equals(Constants.IS_BASE)) { + String value = prop.getValue() == null ? prop.getDefaultValue() : prop.getValue(); + boolean bvalue = Boolean.parseBoolean(value); + if (bvalue) { + assertEquals("Validate vf_module_type", "Base", vf_module_type); + } else { + assertEquals("Validate vf_module_type", "Expansion", vf_module_type); + } + break; + } + } + String vf_module_description = (String) properties.get("vf_module_description"); + assertEquals("Validate vf_module_description", group.getDescription(), vf_module_description); + + Boolean volume_group = (Boolean) properties.get("volume_group"); + boolean isVolume = false; + List artifactsList = group.getArtifacts(); + List artifacts = new ArrayList<>(); + if (artifactsList != null && !artifactsList.isEmpty()) { + ArtifactDefinition masterArtifact = findMasterArtifact(createdResource.getDeploymentArtifacts(), + artifacts, artifactsList); + if (masterArtifact.getArtifactType().equalsIgnoreCase(ArtifactTypeEnum.HEAT_VOL.getType())) { + isVolume = true; + } + } + assertEquals("Validate volume_group", isVolume, volume_group); + + } else { + invariantUUID = (String) metadata.get("invariantUUID"); + name = (String) metadata.get("name"); + UUID = (String) metadata.get("UUID"); + version = (String) metadata.get("version"); + assertNull(properties); + + } + assertEquals("Validate InvariantUUID", group.getInvariantUUID(), invariantUUID); + assertEquals("Validate name", group.getName(), name); + assertEquals("Validate UUID", group.getGroupUUID(), UUID); + assertEquals("Validate version", group.getVersion(), version); + + } + } + + @Test(enabled = true) + public void exportCsarInputsTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + Resource createdResource = createVfFromCSAR(sdncModifierDetails, "csar_1"); + Map load = downloadAndParseToscaTemplate(sdncModifierDetails, createdResource); + assertNotNull(load); + + Map topology_template = (Map) load.get("topology_template"); + assertNotNull(topology_template); + + Map inputs = (Map) topology_template.get("inputs"); + assertNotNull(inputs); + + List inputsFromResource = createdResource.getInputs(); + assertEquals("validate inputs size", inputsFromResource.size(), inputs.size()); + for (InputDefinition inputDef : inputsFromResource) { + Map inputInFile = (Map) inputs.get(inputDef.getName()); + assertNotNull(inputInFile); + validateInput(inputDef, inputInFile); + } + List componentInstances = createdResource.getComponentInstances(); + Map> componentInstancesProperties = createdResource + .getComponentInstancesProperties(); + Map node_templates = (Map) topology_template.get("node_templates"); + assertNotNull(node_templates); + + JsonParser jsonParser = new JsonParser(); + + for (Map.Entry> entry : componentInstancesProperties.entrySet()) { + + Optional findFirst = componentInstances.stream() + .filter(ci -> ci.getUniqueId().equals(entry.getKey())).findFirst(); + assertTrue(findFirst.isPresent()); + String resourceName = findFirst.get().getName(); + Map instance = (Map) node_templates.get(resourceName); + assertNotNull(instance); + Map properties = (Map) instance.get("properties"); + + for (ComponentInstanceProperty cip : entry.getValue()) { + if (cip.getValueUniqueUid() != null && !cip.getValueUniqueUid().isEmpty()) { + assertNotNull(properties); + if (cip.getValue().contains("get_input")) { + Object prop = properties.get(cip.getName()); + assertNotNull(prop); + + Gson gson = new Gson(); + String json = gson.toJson(prop); + assertEquals("validate json property", cip.getValue(), json); + } + + } + } + + } + + } + + @Test + public void importExportCsarWithJsonPropertyType() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String payloadName = "jsonPropertyTypeTest.csar"; + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + String rootPath = System.getProperty("user.dir"); + Path path = null; + byte[] data = null; + String payloadData = null; + path = Paths.get(rootPath + "/src/test/resources/CI/csars/jsonPropertyTypeTest.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + resourceDetails.setCsarUUID(payloadName); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + ComponentInstance pmaaServer = resource.getComponentInstances().stream() + .filter(p -> p.getName().equals("pmaa_server_0")).findAny().get(); + ComponentInstanceProperty jsonProp = resource.getComponentInstancesProperties().get(pmaaServer.getUniqueId()) + .stream().filter(p -> p.getType().equals(ToscaPropertyType.JSON.getType())).findAny().get(); + String jsonValue = "{\"pmaa.sb_nic\":{\"address\":{\"get_input\":\"pmaa_dpu_fixed_ip\"},\"cidr\":{\"get_input\":\"pmaa_dpu_cidr\"},\"gateway\":{\"get_input\":\"pmaa_dpu_gateway\"}}}"; + assertEquals(jsonProp.getValue(), jsonValue); + // download and compare + Map load = downloadAndParseToscaTemplate(sdncModifierDetails, resource); + assertNotNull(load); + Map topology_template = (Map) load.get("topology_template"); + assertNotNull(topology_template); + Map nodes = (Map) topology_template.get("node_templates"); + assertNotNull(nodes); + Map pmaaServerObj = (Map) nodes.get("pmaa_server_0"); + assertNotNull(pmaaServerObj); + Map props = (Map) pmaaServerObj.get("properties"); + assertNotNull(props); + Map jsonPropObj = (Map) props.get("metadata"); + assertNotNull(jsonPropObj); + Gson gson = new Gson(); + String json = gson.toJson(jsonPropObj); + assertEquals(json, jsonValue); + } + + @Test(enabled = true) + public void exportServiceInputValue() throws Exception { + //1 create vf as certified + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + Resource createdResource = createVfFromCSAR(sdncModifierDetails, "csar_1"); + RestResponse checkinState = LifecycleRestUtils.changeComponentState(createdResource, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + BaseRestUtils.checkSuccess(checkinState); + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService("ciNewtestservice1", ServiceCategoriesEnum.MOBILITY, sdncModifierDetails.getUserId()); + + //2 create service + RestResponse createServiceResponse = ServiceRestUtils.createService(serviceDetails, sdncModifierDetails); + ResourceRestUtils.checkCreateResponse(createServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(createServiceResponse.getResponse(), Service.class); + + //3 create vf instance in service + ComponentInstanceReqDetails componentInstanceDetails = ElementFactory.getComponentInstance(createdResource); + RestResponse createComponentInstance = ComponentInstanceRestUtils.createComponentInstance(componentInstanceDetails, sdncModifierDetails, service); + ResourceRestUtils.checkCreateResponse(createComponentInstance); + + RestResponse getService = ServiceRestUtils.getService(service.getUniqueId()); + BaseRestUtils.checkSuccess(getService); + service = ResponseParser.parseToObjectUsingMapper(getService.getResponse(), Service.class); + + //4 download tosca template + Map tosca = downloadAndParseToscaTemplate(sdncModifierDetails, service); + assertNotNull(tosca); + Map topology_template = (Map) tosca.get("topology_template"); + assertNotNull(topology_template); + + //5 validate no inputs in service + Map inputs = (Map) tosca.get("inputs"); + assertNull(inputs); + + List componentInstances = service.getComponentInstances(); + assertNotNull(componentInstances); + assertEquals(1, componentInstances.size()); + ComponentInstance vfi = componentInstances.get(0); + + //6 add instance inputs in service + RestResponse getComponentInstanceInputsResponse = InputsRestUtils.getComponentInstanceInputs(service, vfi); + BaseValidationUtils.checkSuccess(getComponentInstanceInputsResponse); + List instanceInputs = new Gson().fromJson(getComponentInstanceInputsResponse.getResponse(), new TypeToken>(){}.getType()); + // Take only the 2 first inputs + List inputsToAdd = instanceInputs.stream().limit(2).collect(Collectors.toList()); + + //7 Build component instances input map to add to server + ComponentInstInputsMap buildComponentInstInputsMap = buildComponentInstInputsMap(vfi.getUniqueId(), inputsToAdd); + RestResponse addInputResponse = InputsRestUtils.addInput(service, buildComponentInstInputsMap, UserRoleEnum.DESIGNER); + BaseValidationUtils.checkSuccess(addInputResponse); + + //8 validate inputs in service + //8.1 download tosca template + getService = ServiceRestUtils.getService(service.getUniqueId()); + BaseRestUtils.checkSuccess(getService); + service = ResponseParser.parseToObjectUsingMapper(getService.getResponse(), Service.class); + + tosca = downloadAndParseToscaTemplate(sdncModifierDetails, service); + assertNotNull(tosca); + topology_template = (Map) tosca.get("topology_template"); + assertNotNull(topology_template); + + //8.2 validate inputs in service + inputs = (Map) topology_template.get("inputs"); + assertNotNull(inputs); + assertEquals(2, inputs.size()); + + //validate created inputs vs inputs in Tosca inputs section + final Map inputsFinal = inputs; + buildComponentInstInputsMap.getComponentInstanceInputsMap().values().forEach(listPerInstance ->{ + listPerInstance.forEach(input ->{ + Map inputInMap = (Map)inputsFinal.get(input.getName()); + assertNotNull(inputInMap); + }); + }); + Map> componentInstancesInputs = service.getComponentInstancesInputs(); + + //validate created inputs vs inputs in Tosca instance input value + List vfiInputs = componentInstancesInputs.get(vfi.getUniqueId()); + assertNotNull(vfiInputs); + assertEquals(2, vfiInputs.size()); + + Map node_templates = (Map) topology_template.get("node_templates"); + assertNotNull(node_templates); + + Map instance = (Map) node_templates.get(vfi.getName()); + assertNotNull(instance); + Map properties = (Map)instance.get("properties"); + assertNotNull(properties); + + vfiInputs.forEach(vfiInput ->{ + Map inputPropValueInTosca = (Map)properties.get(vfiInput.getName() ); + assertNotNull(inputPropValueInTosca); + String instaneInputName = (String)inputPropValueInTosca.get("get_input"); + assertNotNull(instaneInputName); + Map inputInMap = (Map)inputsFinal.get(instaneInputName); + assertNotNull(inputInMap); + }); + + + } + + + // ---------------------------------------- + private void validateInput(InputDefinition inputDef, Map inputInFile) { + assertEquals("validate input type", inputDef.getType(), (String) inputInFile.get("type")); + + if (inputDef.getDefaultValue() == null) { + assertNull(inputInFile.get("default")); + } else { + assertNotNull(inputInFile.get("default")); + String value = inputDef.getDefaultValue().replace("\"", ""); + value = value.replace(" ", ""); + String expValue = inputInFile.get("default").toString().replace(" ", ""); + assertEquals("validate input default", value, expValue); + } + assertEquals("validate input description", inputDef.getDescription(), (String) inputInFile.get("description")); + } + + private Map downloadAndParseToscaTemplate(User sdncModifierDetails, Component createdComponent) + throws Exception { + String artifactUniqeId = createdComponent.getToscaArtifacts().get("assettoscatemplate").getUniqueId(); + RestResponse toscaTemplate; + + if ( createdComponent.getComponentType() == ComponentTypeEnum.RESOURCE ){ + toscaTemplate = ArtifactRestUtils.downloadResourceArtifactInternalApi( + createdComponent.getUniqueId(), sdncModifierDetails, artifactUniqeId); + + }else{ + toscaTemplate = ArtifactRestUtils.downloadServiceArtifactInternalApi( + createdComponent.getUniqueId(), sdncModifierDetails, artifactUniqeId); + } + BaseRestUtils.checkSuccess(toscaTemplate); + + ArtifactUiDownloadData artifactUiDownloadData = ResponseParser.parseToObject(toscaTemplate.getResponse(), + ArtifactUiDownloadData.class); + byte[] fromUiDownload = artifactUiDownloadData.getBase64Contents().getBytes(); + byte[] decodeBase64 = Base64.decodeBase64(fromUiDownload); + Yaml yaml = new Yaml(); + + InputStream inputStream = new ByteArrayInputStream(decodeBase64); + + Map load = (Map) yaml.load(inputStream); + return load; + } + + + public ArtifactDefinition findMasterArtifact(Map deplymentArtifact, + List artifacts, List artifactsList) { + for (String artifactUid : artifactsList) { + for (Entry entry : deplymentArtifact.entrySet()) { + ArtifactDefinition artifact = entry.getValue(); + if (artifactUid.equalsIgnoreCase(artifact.getUniqueId())) { + artifacts.add(artifact); + } + + } + } + ArtifactDefinition masterArtifact = null; + for (ArtifactDefinition artifactInfo : artifacts) { + String atrifactType = artifactInfo.getArtifactType(); + if (atrifactType.equalsIgnoreCase(ArtifactTypeEnum.HEAT_VOL.getType()) + || atrifactType.equalsIgnoreCase(ArtifactTypeEnum.HEAT_NET.getType())) { + masterArtifact = artifactInfo; + continue; + } + if (atrifactType.equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType())) { + masterArtifact = artifactInfo; + break; + } + } + return masterArtifact; + } + private ComponentInstInputsMap buildComponentInstInputsMap (String addToInput, List inputs) { + Map> map = new HashMap<>(); + map.put(addToInput, inputs); + ComponentInstInputsMap componentInstInputsMap = new ComponentInstInputsMap(); + componentInstInputsMap.setComponentInstanceInputsMap(map); + return componentInstInputsMap; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportCsarResourceTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportCsarResourceTest.java new file mode 100644 index 0000000000..1b559aaaad --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportCsarResourceTest.java @@ -0,0 +1,1751 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.imports; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.WordUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.GroupProperty; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.GroupRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ImportRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class ImportCsarResourceTest extends ComponentBaseTest { + private static Logger log = LoggerFactory.getLogger(ImportCsarResourceTest.class.getName()); + @Rule + public static TestName name = new TestName(); + + Gson gson = new Gson(); + + public ImportCsarResourceTest() { + super(name, ImportCsarResourceTest.class.getName()); + } + + private String buildAssertMessage(String expectedString, String actualString) { + return String.format("expected is : %s , actual is: %s", expectedString, actualString); + } + + /** + * + * User Story : US640615 [BE] - Extend create VF API with Import TOSCA CSAR + */ + + @Test(enabled = true) + public void createResourceFromCsarHappy() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("AF7F231969C5463F9C968570070E8877"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + String expectedCsarUUID = resourceDetails.getCsarUUID(); + String expectedToscaResourceName = "org.openecomp.resource.vf." + WordUtils.capitalize(resourceDetails.getName().toLowerCase()); + + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, resource.getCsarUUID()), expectedCsarUUID.equals(resource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, resource.getToscaResourceName()), expectedToscaResourceName.equals(resource.getToscaResourceName())); + + RestResponse getResourceResponse = ResourceRestUtils.getResource(resource.getUniqueId()); + Resource getResource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, getResource.getCsarUUID()), expectedCsarUUID.equals(getResource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, getResource.getToscaResourceName()), expectedToscaResourceName.equals(getResource.getToscaResourceName())); + } + + @Test(enabled = true) + public void emptyStringInCsarUUIDFieldTest() throws Exception { + String emptyString = ""; + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(emptyString); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(null, resource.getComponentInstances()); + + String expectedToscaResourceName = "org.openecomp.resource.vf." + WordUtils.capitalize(resourceDetails.getName().toLowerCase()); + + assertTrue("csarUUID : " + buildAssertMessage(emptyString, resource.getCsarUUID()), resource.getCsarUUID() == emptyString); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, resource.getToscaResourceName()), expectedToscaResourceName.equals(resource.getToscaResourceName())); + + RestResponse getResourceResponse = ResourceRestUtils.getResource(resource.getUniqueId()); + Resource getResource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + assertTrue("csarUUID : " + buildAssertMessage(emptyString, getResource.getCsarUUID()), getResource.getCsarUUID() == emptyString); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, getResource.getToscaResourceName()), expectedToscaResourceName.equals(getResource.getToscaResourceName())); + } + + @Test(enabled = true) + public void createResourceFromScratchTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(null, resource.getComponentInstances()); + + String expectedToscaResourceName = "org.openecomp.resource.vf." + WordUtils.capitalize(resourceDetails.getName().toLowerCase()); + + assertTrue("csarUUID : " + buildAssertMessage(null, resource.getCsarUUID()), resource.getCsarUUID() == null); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, resource.getToscaResourceName()), expectedToscaResourceName.equals(resource.getToscaResourceName())); + + RestResponse getResourceResponse = ResourceRestUtils.getResource(resource.getUniqueId()); + Resource getResource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + assertTrue("csarUUID : " + buildAssertMessage(null, getResource.getCsarUUID()), getResource.getCsarUUID() == null); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, getResource.getToscaResourceName()), expectedToscaResourceName.equals(getResource.getToscaResourceName())); + } + + @Test(enabled = true) + public void fileNotCsarTypeTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("valid_vf_zip"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_NOT_FOUND.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void missingToscaMetadataFolderTest() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("toscaFolderNotExists"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void missingToscaMetaFileTest() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("toscaMetaFileNotExists"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void toscaMetaFileOutsideTheFolderTest() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("toscaMetaOutsideTheFolder"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void caseSensitiveTest_1() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("caseSensitiveTest_1"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void caseSensitiveTest_2() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("caseSensitiveTest_2"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void missingOneLineInToscaMetaFileTest() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("missingOneLineInToscaMeta"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void noCSARVersionTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("noCSARVersion"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void noCreatedByValueTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("noCreatedByValue"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void noEntryDefinitionsValueTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("noEntryDefinitionsValue"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void noTOSCAMetaFileVersionValueTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("noTOSCAMetaFileVersionValue"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void invalidCsarVersionInMetaFileTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("invalidCsarVersion"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + + resourceDetails.setCsarUUID("invalidCsarVersion2"); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + + resourceDetails.setCsarUUID("invalidCsarVersion3"); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + + resourceDetails.setCsarUUID("invalidCsarVersion4"); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + + resourceDetails.setCsarUUID("invalidCsarVersion5"); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + + } + + @Test(enabled = true) + public void validCsarVersionInMetaFileTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("validCsarVersion"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + String expectedCsarUUID = resourceDetails.getCsarUUID(); + String expectedToscaResourceName = "org.openecomp.resource.vf." + WordUtils.capitalize(resourceDetails.getName().toLowerCase()); + + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, resource.getCsarUUID()), expectedCsarUUID.equals(resource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, resource.getToscaResourceName()), expectedToscaResourceName.equals(resource.getToscaResourceName())); + + RestResponse getResourceResponse = ResourceRestUtils.getResource(resource.getUniqueId()); + Resource getResource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, getResource.getCsarUUID()), expectedCsarUUID.equals(getResource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, getResource.getToscaResourceName()), expectedToscaResourceName.equals(getResource.getToscaResourceName())); + } + + @Test(enabled = true) + public void underscoreInToscaMetaFileVersionNameTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("underscoreInsteadOfDash"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void missingEntryDefintionInMetaFileTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("missingEntryDefintionPair"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = false) + public void noNewLineAfterBLock0Test() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("noNewLineAfterBLock0"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void moreThanOneYamlFileTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("moreThenOneYamlFile"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + String expectedCsarUUID = resourceDetails.getCsarUUID(); + String expectedToscaResourceName = "org.openecomp.resource.vf." + WordUtils.capitalize(resourceDetails.getName().toLowerCase()); + + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, resource.getCsarUUID()), expectedCsarUUID.equals(resource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, resource.getToscaResourceName()), expectedToscaResourceName.equals(resource.getToscaResourceName())); + + RestResponse getResourceResponse = ResourceRestUtils.getResource(resource.getUniqueId()); + Resource getResource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, getResource.getCsarUUID()), expectedCsarUUID.equals(getResource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, getResource.getToscaResourceName()), expectedToscaResourceName.equals(getResource.getToscaResourceName())); + } + + @Test(enabled = true) + public void moreThanOneMetaFileTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("moreThanOneMetaFile"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + String expectedCsarUUID = resourceDetails.getCsarUUID(); + String expectedToscaResourceName = "org.openecomp.resource.vf." + WordUtils.capitalize(resourceDetails.getName().toLowerCase()); + + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, resource.getCsarUUID()), expectedCsarUUID.equals(resource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, resource.getToscaResourceName()), expectedToscaResourceName.equals(resource.getToscaResourceName())); + + RestResponse getResourceResponse = ResourceRestUtils.getResource(resource.getUniqueId()); + Resource getResource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, getResource.getCsarUUID()), expectedCsarUUID.equals(getResource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, getResource.getToscaResourceName()), expectedToscaResourceName.equals(getResource.getToscaResourceName())); + } + + @Test(enabled = true) + public void csarNotContainsYamlAndMetaFilesTest() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("notContainYamlAndMetaFiles"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void csarNotContainsYamlFileTest() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("notContainYamlFile"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + variables.add("Definitions/tosca_mock_vf.yaml"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.YAML_NOT_FOUND_IN_CSAR.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void missingCsarFileTest() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("abc"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_NOT_FOUND.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void longNamesInToscaMetaFileTest_1() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("longNamesInToscaMetaFile1"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void longNamesInToscaMetaFileTest_2() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("longNamesInToscaMetaFile2"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void longNamesInToscaMetaFileTest_3() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("longNamesInToscaMetaFile3"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void longNamesInToscaMetaFileTest_4() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("longNamesInToscaMetaFile4"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void longNamesInToscaMetaFileTest_5() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("longNamesInToscaMetaFile5"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + // possible to have more than four lines in block 0 + // @Test (enabled = true) + public void fiveLinesAsBlock0Test() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + resourceDetails.setCsarUUID("fiveLinesAsBlock0"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + List variables = new ArrayList(); + variables.add(resourceDetails.getCsarUUID()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.CSAR_INVALID_FORMAT.name(), variables, createResource.getResponse()); + } + + @Test(enabled = true) + public void lifecycleChangingToResourceFromCsarTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("valid_vf"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertTrue("0.1".equals(resource.getVersion())); + assertTrue(LifeCycleStatesEnum.CHECKOUT.getComponentState().equals(resource.getLifecycleState().toString())); + + String designerUserId = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId(); + String testerUserId = ElementFactory.getDefaultUser(UserRoleEnum.TESTER).getUserId(); + String csarUniqueId = resourceDetails.getUniqueId(); + assertNotNull(csarUniqueId); + + RestResponse lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUserId, LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUserId, LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUserId, LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUserId, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUserId, LifeCycleStatesEnum.STARTCERTIFICATION); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUserId, LifeCycleStatesEnum.CERTIFY); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUserId, LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + + resource = ResponseParser.parseToObjectUsingMapper(lifecycleChangeResponse.getResponse(), Resource.class); + Map allVersions = resource.getAllVersions(); + assertEquals(2, allVersions.keySet().size()); + assertEquals(2, allVersions.values().size()); + Set keySet = allVersions.keySet(); + assertTrue(keySet.contains("1.0")); + assertTrue(keySet.contains("1.1")); + } + + @Test(enabled = true) + public void csarWithJsonPromEnvTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("VSPPackageJsonProp.csar"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + } + + @Test(enabled = true) + public void uploadArtifactToResourceFromCsarTest() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("valid_vf"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + + User designer = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ArtifactReqDetails artifactDetails = ElementFactory.getDefaultArtifact("firstArtifact"); + String firstArtifactLabel = artifactDetails.getArtifactLabel(); + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(artifactDetails, designer, resourceDetails.getUniqueId()); + ArtifactRestUtils.checkSuccess(addInformationalArtifactToResource); + RestResponse getResourceResponse = ResourceRestUtils.getResource(resourceDetails.getUniqueId()); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + Map informationalArtifacts = resource.getArtifacts(); + assertEquals(1, informationalArtifacts.keySet().size()); + Set keySet = informationalArtifacts.keySet(); + assertTrue(keySet.contains(firstArtifactLabel.toLowerCase())); + Collection values = informationalArtifacts.values(); + assertEquals(1, values.size()); + Iterator iterator = values.iterator(); + while (iterator.hasNext()) { + ArtifactDefinition actualArtifact = iterator.next(); + assertTrue(firstArtifactLabel.equals(actualArtifact.getArtifactDisplayName())); + } + + RestResponse lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designer.getUserId(), LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designer.getUserId(), LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + + ArtifactReqDetails artifactDetails2 = ElementFactory.getDefaultArtifact("secondArtifact"); + artifactDetails2.setArtifactName("secondArtifact"); + addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource(artifactDetails2, designer, resourceDetails.getUniqueId()); + ArtifactRestUtils.checkSuccess(addInformationalArtifactToResource); + + getResourceResponse = ResourceRestUtils.getResource(resourceDetails.getUniqueId()); + resource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + informationalArtifacts = resource.getArtifacts(); + assertEquals(2, informationalArtifacts.keySet().size()); + keySet = informationalArtifacts.keySet(); + assertTrue(keySet.contains(firstArtifactLabel.toLowerCase())); + assertTrue(keySet.contains(artifactDetails2.getArtifactLabel().toLowerCase())); + values = informationalArtifacts.values(); + assertEquals(2, values.size()); + ArtifactDefinition[] actualArtifacts = values.toArray(new ArtifactDefinition[2]); + assertTrue(firstArtifactLabel.equals(actualArtifacts[0].getArtifactDisplayName())); + assertTrue(artifactDetails2.getArtifactLabel().equals(actualArtifacts[1].getArtifactDisplayName())); + } + + /* + * // @Test (enabled = true) public void createUpdateImportResourceFromCsarArtifactsWereNotChangedTest() throws Exception { // User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); // //back original scar RestResponse + * copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", "VF_RI2_G4_withArtifacts.csar"); BaseRestUtils.checkSuccess(copyRes); + * + * // resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); // RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); resourceDetails.setName("test5"); + * resourceDetails.setCsarUUID("VF_RI2_G4_withArtifacts.csar"); resourceDetails.setCsarVersion("1"); // String invariantUUID = resource.getInvariantUUID(); // // RestResponse changeResourceState = + * LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); // assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + * + * // BaseRestUtils.checkSuccess(copyRes); // //change name (temporary) resourceDetails.setCsarVersion("2"); resourceDetails.setName("test6"); createResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, + * resourceDetails.getUniqueId()); Resource updatedResource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); Map updatedArtifacts = updatedResource.getDeploymentArtifacts(); for + * (Entry artifactEntry : resource.getDeploymentArtifacts().entrySet()) { if (updatedArtifacts.containsKey(artifactEntry.getKey())) { ArtifactDefinition currArt = updatedArtifacts.get(artifactEntry.getKey()); + * assertEquals(currArt.getArtifactVersion(), artifactEntry.getValue().getArtifactVersion()); assertEquals(currArt.getArtifactUUID(), artifactEntry.getValue().getArtifactUUID()); assertEquals(currArt.getArtifactChecksum(), + * artifactEntry.getValue().getArtifactChecksum()); } } // resourceDetails = ElementFactory.getDefaultResource(); // resourceDetails.setName("test5"); // resourceDetails.setCsarUUID("VF_RI2_G4_withArtifacts.csar"); } + */ + + @Test(enabled = true) + public void createImportResourceFromCsarDissotiateArtifactFromGroupTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", "VF_RI2_G4_withArtifacts.csar"); + + // create new resource from Csar + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("VF_RI2_G4_withArtifacts.csar"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + String invariantUUID = resource.getInvariantUUID(); + + // add artifact from metadata (resource metadata should be updated) + // RestResponse addInformationalArtifactToResource = + // ArtifactRestUtils.addInformationalArtifactToResource(ElementFactory.getDefaultArtifact(), + // sdncModifierDetails, resourceDetails.getUniqueId()); + // ArtifactRestUtils.checkSuccess(addInformationalArtifactToResource); + resourceDetails.setName("test4"); + RestResponse updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + assertEquals(invariantUUID, resource.getInvariantUUID()); + + // wrong RI (without node types, resource shouldn't be updated) + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_dissociate.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + // change name (temporary) + resourceDetails.setName("test4"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + assertEquals(invariantUUID, resource.getInvariantUUID()); + + // back original scar + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + } + + @Test(enabled = true) + public void createImportResourceFromCsarNewgroupTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", "VF_RI2_G4_withArtifacts.csar"); + + // create new resource from Csar + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("VF_RI2_G4_withArtifacts.csar"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + String invariantUUID = resource.getInvariantUUID(); + + // update scar + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_UpdateToscaAndArtifacts.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + + resourceDetails.setName("test2"); + // change resource metaData (resource should be updated) + resourceDetails.setDescription("It is new description bla bla bla"); + RestResponse updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + assertEquals(invariantUUID, resource.getInvariantUUID()); + + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + } + + @Test(enabled = true) + public void createImportResourceFromCsarGetGroupTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // RestResponse copyRes = + // copyCsarRest(sdncModifierDetails,"VF_RI2_G4_withArtifacts_a.csar","VF_RI2_G4_withArtifacts.csar"); + + // create new resource from Csar + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("VSPPackage"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + String invariantUUID = resource.getInvariantUUID(); + List groups = resource.getGroups(); + + GroupDefinition groupWithArtifact = groups.stream().filter(p -> p.getArtifacts() != null && !p.getArtifacts().isEmpty()).findFirst().get(); + + RestResponse groupRest = GroupRestUtils.getGroupById(resource, groupWithArtifact.getUniqueId(), sdncModifierDetails); + BaseRestUtils.checkSuccess(groupRest); + + GroupDefinition groupWithoutArtifact = groups.stream().filter(p -> p.getArtifacts() == null || p.getArtifacts().isEmpty()).findFirst().get(); + + groupRest = GroupRestUtils.getGroupById(resource, groupWithoutArtifact.getUniqueId(), sdncModifierDetails); + BaseRestUtils.checkSuccess(groupRest); + } + + @Test(enabled = true) + public void createImportResourceFromCsarUITest() throws Exception { + RestResponse getResource = null; + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String payloadName = "valid_vf.csar"; + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + String rootPath = System.getProperty("user.dir"); + Path path = null; + byte[] data = null; + String payloadData = null; + + path = Paths.get(rootPath + "/src/main/resources/ci/valid_vf.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + // create new resource from Csar + resourceDetails.setCsarUUID(payloadName); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + RestResponse changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // change composition (resource should be updated) + path = Paths.get(rootPath + "/src/main/resources/ci/valid_vf_b.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + // change name + resourceDetails.setName("test1"); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(2, resource.getComponentInstances().size()); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // change name + resourceDetails.setName("test2"); + // change resource metaData (resource should be updated) + resourceDetails.setDescription("It is new description bla bla bla"); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(2, resource.getComponentInstances().size()); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // wrong RI (without node types, resource shouldn't be updated) + path = Paths.get(rootPath + "/src/main/resources/ci/valid_vf_c.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + // change name + resourceDetails.setName("test3"); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkErrorResponse(createResource, ActionStatus.INVALID_NODE_TEMPLATE, "Definitions/tosca_mock_vf.yaml", "nodejs", "tosca.nodes.Weber"); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(null, resource); + getResource = ResourceRestUtils.getResourceByNameAndVersion(sdncModifierDetails.getUserId(), "test3", resourceDetails.getVersion()); + BaseRestUtils.checkErrorResponse(getResource, ActionStatus.RESOURCE_NOT_FOUND, "test3"); + + // create new resource from other Csar + resourceDetails = ElementFactory.getDefaultImportResource(); + path = Paths.get(rootPath + "/src/main/resources/ci/VF_RI2_G4_withArtifacts.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + resourceDetails.setPayloadName("VF_RI2_G4_withArtifacts.csar"); + resourceDetails.setName("test4"); + resourceDetails.setCsarUUID("VF_RI2_G4_withArtifacts.csar"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // wrong RI (with node types) resource shouldn't be created + resourceDetails.setCsarUUID("VF_RI2_G4_withArtifacts_b.csar"); + path = Paths.get(rootPath + "/src/main/resources/ci/VF_RI2_G4_withArtifacts_b.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + resourceDetails.setPayloadName("VF_RI2_G4_withArtifacts_b.csar"); + resourceDetails.setName("test5"); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkErrorResponse(createResource, ActionStatus.INVALID_NODE_TEMPLATE, "Definitions/VF_RI2_G1.yaml", "ps04_port_0", "org.openecomp.resource.cp.nodes.heat.network.neutron.Portur"); + } + + @Test(enabled = true) + public void createUpdateImportResourceFromCsarUITest() throws Exception { + RestResponse getResource = null; + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String payloadName = "valid_vf.csar"; + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + String rootPath = System.getProperty("user.dir"); + Path path = null; + byte[] data = null; + String payloadData = null; + + path = Paths.get(rootPath + "/src/main/resources/ci/valid_vf.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + // create new resource from Csar + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + RestResponse changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // change composition and update resource + path = Paths.get(rootPath + "/src/main/resources/ci/valid_vf_b.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + resourceDetails.setUniqueId(resource.getUniqueId()); + // change name + RestResponse updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resource.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + assertEquals(2, resource.getComponentInstances().size()); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // change name + resourceDetails.setName("test2"); + // change resource metaData (resource should be updated) + resourceDetails.setDescription("It is new description bla bla bla"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resource.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + assertEquals(2, resource.getComponentInstances().size()); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // try to update resource with wrong RI (without node types, resource + // shouldn't be updated) + path = Paths.get(rootPath + "/src/main/resources/ci/valid_vf_c.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + // change name + resourceDetails.setName("test3"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resource.getUniqueId()); + BaseRestUtils.checkErrorResponse(updateResource, ActionStatus.INVALID_NODE_TEMPLATE, "Definitions/tosca_mock_vf.yaml", "nodejs", "tosca.nodes.Weber"); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + assertEquals(null, resource); + getResource = ResourceRestUtils.getResourceByNameAndVersion(sdncModifierDetails.getUserId(), "test3", resourceDetails.getVersion()); + BaseRestUtils.checkErrorResponse(getResource, ActionStatus.RESOURCE_NOT_FOUND, "test3"); + } + + @Test(enabled = true) + public void createUpdateImportResourceFromCsarTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = null; + RestResponse getResource = null; + ResourceReqDetails resourceDetails = null; + RestResponse updateResource = null; + RestResponse createResource = null; + Resource resource = null; + RestResponse changeResourceState = null; + + // create new resource from Csar + copyRes = copyCsarRest(sdncModifierDetails, "valid_vf_a.csar", "valid_vf.csar"); + resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("valid_vf.csar"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + String invariantUUID = resource.getInvariantUUID(); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // change composition and update resource + copyRes = copyCsarRest(sdncModifierDetails, "valid_vf_b.csar", "valid_vf.csar"); + BaseRestUtils.checkSuccess(copyRes); + // change name + resourceDetails.setName("test1"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resource.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + assertEquals(2, resource.getComponentInstances().size()); + assertEquals(invariantUUID, resource.getInvariantUUID()); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // back original scar + copyRes = copyCsarRest(sdncModifierDetails, "valid_vf_a.csar", "valid_vf.csar"); + BaseRestUtils.checkSuccess(copyRes); + + // change name + resourceDetails.setName("test2"); + // change resource metaData and update resource + resourceDetails.setDescription("It is new description bla bla bla"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resource.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + assertEquals(invariantUUID, resource.getInvariantUUID()); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // back original scar + copyRes = copyCsarRest(sdncModifierDetails, "valid_vf_a.csar", "valid_vf.csar"); + BaseRestUtils.checkSuccess(copyRes); + + // try to update resource with wrong RI (without node types, resource + // shouldn't be updated) + copyRes = copyCsarRest(sdncModifierDetails, "valid_vf_c.csar", "valid_vf.csar"); + BaseRestUtils.checkSuccess(copyRes); + // change name (temporary) + resourceDetails.setName("test3"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resource.getUniqueId()); + BaseRestUtils.checkErrorResponse(updateResource, ActionStatus.INVALID_NODE_TEMPLATE, "Definitions/tosca_mock_vf.yaml", "nodejs", "tosca.nodes.Weber"); + + getResource = ResourceRestUtils.getResourceByNameAndVersion(sdncModifierDetails.getUserId(), "test3", resourceDetails.getVersion()); + BaseRestUtils.checkErrorResponse(getResource, ActionStatus.RESOURCE_NOT_FOUND, "test3"); + getResource = ResourceRestUtils.getResourceByNameAndVersion(sdncModifierDetails.getUserId(), "test2", resourceDetails.getVersion()); + BaseRestUtils.checkSuccess(getResource); + + // back original scar + copyRes = copyCsarRest(sdncModifierDetails, "valid_vf_a.csar", "valid_vf.csar"); + BaseRestUtils.checkSuccess(copyRes); + + // create new resource from Csar + // back original scar + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + + resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("TEST01"); + resourceDetails.setCsarUUID("VF_RI2_G4_withArtifacts.csar"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // scar with wrong RI + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_b.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + resourceDetails.setDescription("BLA BLA BLA"); + // wrong RI (with node types) resource shouldn't be created + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resourceDetails.getUniqueId()); + BaseRestUtils.checkErrorResponse(updateResource, ActionStatus.INVALID_NODE_TEMPLATE, "Definitions/VF_RI2_G1.yaml", "ps04_port_0", "org.openecomp.resource.cp.nodes.heat.network.neutron.Portur"); + // back original scar + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + } + + @Test(enabled = true) + public void createUpdateImportResourceFromCsarWithArtifactsTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = null; + ResourceReqDetails resourceDetails = null; + RestResponse updateResource = null; + RestResponse createResource = null; + Resource resource = null; + RestResponse changeResourceState = null; + + // back original scar + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + + resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("TEST01"); + resourceDetails.setCsarUUID("VF_RI2_G4_withArtifacts.csar"); + resourceDetails.setCsarVersion("1"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + // create new resource from Csar + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + List requiredArtifactsOld = resource.getDeploymentArtifacts().get("heat5").getRequiredArtifacts(); + assertTrue(requiredArtifactsOld != null && !requiredArtifactsOld.isEmpty() && requiredArtifactsOld.size() == 3); + assertTrue(requiredArtifactsOld.contains("hot-nimbus-pcm-volumes_v1.0.yaml")); + assertTrue(requiredArtifactsOld.contains("nested-pcm_v1.0.yaml")); + assertTrue(requiredArtifactsOld.contains("hot-nimbus-oam-volumes_v1.0.yaml")); + + // update scar with new artifacts + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_updated.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + resourceDetails.setDescription("BLA BLA BLA"); + resourceDetails.setCsarVersion("2"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + + List requiredArtifactsNew = resource.getDeploymentArtifacts().get("heat5").getRequiredArtifacts(); + assertTrue(requiredArtifactsNew != null && !requiredArtifactsNew.isEmpty() && requiredArtifactsNew.size() == 3); + assertTrue(requiredArtifactsNew.contains("hot-nimbus-swift-container_v1.0.yaml")); + assertTrue(requiredArtifactsNew.contains("hot-nimbus-oam-volumes_v1.0.yaml")); + assertTrue(requiredArtifactsNew.contains("nested-oam_v1.0.yaml")); + + // back original scar + copyRes = copyCsarRest(sdncModifierDetails, "VF_RI2_G4_withArtifacts_a.csar", "VF_RI2_G4_withArtifacts.csar"); + BaseRestUtils.checkSuccess(copyRes); + } + + @Test(enabled = true) + public void createUpdateImportWithPropertiesFromCsarUITest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String payloadName = "valid_vf.csar"; + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + String rootPath = System.getProperty("user.dir"); + Path path = null; + byte[] data = null; + String payloadData = null; + + path = Paths.get(rootPath + "/src/main/resources/ci/valid_vf.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + // create new resource from Csar + resourceDetails.setCsarUUID(payloadName); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + RestResponse changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // change composition (add new RI with specified property values) + path = Paths.get(rootPath + "/src/main/resources/ci/valid_vf_d.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + // change name + resourceDetails.setName("test1"); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(6, resource.getComponentInstances().size()); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + // change composition (add new specified property values to existing RI) + path = Paths.get(rootPath + "/src/main/resources/ci/valid_vf_f.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + // change name + resourceDetails.setName("test2"); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(6, resource.getComponentInstances().size()); + + } + + public static RestResponse copyCsarRest(User sdncModifierDetails, String sourceCsarUuid, String targetCsarUuid) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.COPY_CSAR_USING_SIMULATOR, config.getCatalogBeHost(), config.getCatalogBePort(), sourceCsarUuid, targetCsarUuid); + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + + RestResponse copyCsarResponse = http.httpSendPost(url, "dummy", headersMap); + if (copyCsarResponse.getErrorCode() != 200) { + return null; + } + return copyCsarResponse; + + } + + public static RestResponse getCsarRest(User sdncModifierDetails, String sourceCsarUuid) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_CSAR_USING_SIMULATOR, config.getCatalogBeHost(), config.getCatalogBePort(), sourceCsarUuid); + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + + RestResponse copyCsarResponse = http.httpSendGet(url, headersMap); + if (copyCsarResponse.getErrorCode() != 200) { + return null; + } + return copyCsarResponse; + + } + + @Test(enabled = true) + public void updateResourceFromCsarHappy() throws Exception { + RestResponse copyRes = copyCsarRest(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), "valid_vf_a.csar", "valid_vf.csar"); + BaseRestUtils.checkSuccess(copyRes); + // create + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("valid_vf"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + String expectedCsarUUID = resourceDetails.getCsarUUID(); + String expectedToscaResourceName = "org.openecomp.resource.vf." + WordUtils.capitalize(resourceDetails.getName().toLowerCase()); + + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, resource.getCsarUUID()), expectedCsarUUID.equals(resource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, resource.getToscaResourceName()), expectedToscaResourceName.equals(resource.getToscaResourceName())); + + RestResponse getResourceResponse = ResourceRestUtils.getResource(resource.getUniqueId()); + Resource getResource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, getResource.getCsarUUID()), expectedCsarUUID.equals(getResource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, getResource.getToscaResourceName()), expectedToscaResourceName.equals(getResource.getToscaResourceName())); + + RestResponse updateResource = ResourceRestUtils.updateResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + + } + + @Test(enabled = true) + public void createResourceFromCsarWithGroupsHappy() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("csarWithGroups"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + assertEquals("verify there are 2 groups", 2, resource.getGroups().size()); + + Map compNameToUniqueId = resource.getComponentInstances().stream().collect(Collectors.toMap(p -> p.getName(), p -> p.getUniqueId())); + + // Verify 2 members on group1 + // members: [ app_server, mongo_server ] + String[] membersNameGroup1 = { "app_server", "mongo_server" }; + verifyMembersInResource(resource, compNameToUniqueId, "group1", membersNameGroup1); + // Verify 4 members on group2 + // members: [ mongo_db, nodejs, app_server, mongo_server ] + String[] membersNameGroup2 = { "app_server", "mongo_server", "mongo_db", "nodejs" }; + verifyMembersInResource(resource, compNameToUniqueId, "group2", membersNameGroup2); + + // Check OUT + resourceDetails.setUniqueId(resource.getUniqueId()); + RestResponse changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + changeResourceState = LifecycleRestUtils.changeResourceState(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + + Resource checkedOutResource = ResponseParser.parseToObjectUsingMapper(changeResourceState.getResponse(), Resource.class); + compNameToUniqueId = checkedOutResource.getComponentInstances().stream().collect(Collectors.toMap(p -> p.getName(), p -> p.getUniqueId())); + + // Verify 2 members on group1 + // members: [ app_server, mongo_server ] + verifyMembersInResource(checkedOutResource, compNameToUniqueId, "group1", membersNameGroup1); + // Verify 4 members on group2 + // members: [ mongo_db, nodejs, app_server, mongo_server ] + verifyMembersInResource(checkedOutResource, compNameToUniqueId, "group2", membersNameGroup2); + + } + + private void verifyMembersInResource(Resource resource, Map compNameToUniqueId, String groupName, String[] membersName) { + GroupDefinition groupDefinition = resource.getGroups().stream().filter(p -> p.getName().equals(groupName)).findFirst().get(); + assertEquals("Verify number of members", membersName.length, groupDefinition.getMembers().size()); + Map createdMembers = groupDefinition.getMembers(); + Arrays.asList(membersName).forEach(p -> { + assertTrue("check member name exist", createdMembers.containsKey(p)); + }); + + verifyMembers(createdMembers, compNameToUniqueId); + } + + @Test(enabled = true) + public void createResourceFromCsarWithGroupsAndPropertiesHappy() throws Exception { + + RestResponse importNewGroupTypeByName = ImportRestUtils.importNewGroupTypeByName("myHeatStack1", UserRoleEnum.ADMIN); + // BaseRestUtils.checkCreateResponse(importNewGroupTypeByName); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("csarWithGroupsWithProps"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + + assertEquals("verify there are 2 groups", 2, resource.getGroups().size()); + + Map compNameToUniqueId = resource.getComponentInstances().stream().collect(Collectors.toMap(p -> p.getName(), p -> p.getUniqueId())); + + // Verify 2 members on group1 + // members: [ app_server, mongo_server ] + List groupDefinition1 = resource.getGroups().stream().filter(p -> p.getName().equals("group1")).collect(Collectors.toList()); + assertEquals("Verify number of members", 2, groupDefinition1.get(0).getMembers().size()); + Map createdMembers = groupDefinition1.get(0).getMembers(); + verifyMembers(createdMembers, compNameToUniqueId); + + List properties = groupDefinition1.get(0).getProperties(); + assertEquals("Verify number of members", 2, properties.size()); + + PropertyDataDefinition heatFiles = properties.stream().filter(p -> p.getName().equals("heat_files")).findFirst().get(); + assertNotNull("check heat files not empty", heatFiles); + List heatFilesValue = new ArrayList<>(); + heatFilesValue.add("heat1.yaml"); + heatFilesValue.add("heat2.yaml"); + String heatFilesJson = gson.toJson(heatFilesValue); + log.debug(heatFiles.getValue()); + assertEquals("check heat files value", heatFilesJson, heatFiles.getValue()); + + PropertyDataDefinition urlCredential = properties.stream().filter(p -> p.getName().equals("url_credential")).findFirst().get(); + assertNotNull("check heat files not empty", urlCredential); + log.debug(urlCredential.getValue()); + assertEquals("check url credential", "{\"protocol\":\"protocol1\",\"keys\":{\"keya\":\"valuea\",\"keyb\":\"valueb\"}}", urlCredential.getValue()); + } + + @Test(enabled = true) + public void createResourceFromCsarWithGroupsAndPropertyInvalidValue() throws Exception { + + RestResponse importNewGroupTypeByName = ImportRestUtils.importNewGroupTypeByName("myHeatStack1", UserRoleEnum.ADMIN); + // BaseRestUtils.checkCreateResponse(importNewGroupTypeByName); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("csarWithGroupsInvalidPropertyValue"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + BaseRestUtils.checkStatusCode(createResource, "Check bad request error", false, 400); + + } + + @Test(enabled = true) + public void createResourceFromCsarWithGroupsAndInvalidPropertyName() throws Exception { + + RestResponse importNewGroupTypeByName = ImportRestUtils.importNewGroupTypeByName("myHeatStack1", UserRoleEnum.ADMIN); + // BaseRestUtils.checkCreateResponse(importNewGroupTypeByName); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("csarWithGroupsPropertyNotExist"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + BaseRestUtils.checkStatusCode(createResource, "Check bad request error", false, 400); + BaseRestUtils.checkErrorResponse(createResource, ActionStatus.GROUP_PROPERTY_NOT_FOUND, "url_credential111", "group1", "org.openecomp.groups.MyHeatStack1"); + + } + + @Test(enabled = true) + public void createResourceFromCsarGroupTypeNotExist() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("csarWithGroupsInvalidGroupType"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + BaseRestUtils.checkStatusCode(createResource, "Check bad request error", false, 400); + BaseRestUtils.checkErrorResponse(createResource, ActionStatus.GROUP_TYPE_IS_INVALID, "org.openecomp.groups.stamGroupType"); + + } + + @Test(enabled = true) + public void createResourceFromCsarMemberNotExist() throws Exception { + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("csarWithGroupsInvalidMember"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + BaseRestUtils.checkStatusCode(createResource, "Check bad request error", false, 400); + BaseRestUtils.checkErrorResponse(createResource, ActionStatus.GROUP_INVALID_COMPONENT_INSTANCE, "mycomp", "mygroup", ValidationUtils.normaliseComponentName(resourceDetails.getName()), "VF"); + + } + + @Test(enabled = true) + public void createResourceFromCsarMemberNotAllowed() throws Exception { + + RestResponse importNewGroupTypeByName = ImportRestUtils.importNewGroupTypeByName("myHeatStack2", UserRoleEnum.ADMIN); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("csarWithGroupsNotAllowedMember"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + BaseRestUtils.checkStatusCode(createResource, "Check bad request error", false, 400); + BaseRestUtils.checkErrorResponse(createResource, ActionStatus.GROUP_INVALID_TOSCA_NAME_OF_COMPONENT_INSTANCE, "nodejs", "group1", "org.openecomp.groups.MyHeatStack2"); + + } + + @Test(enabled = true) + public void getResourceFromCsarUuidHappy() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("tam"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(6, resource.getComponentInstances().size()); + + String expectedCsarUUID = resourceDetails.getCsarUUID(); + String expectedToscaResourceName = "org.openecomp.resource.vf." + WordUtils.capitalize(resourceDetails.getName().toLowerCase()); + + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, resource.getCsarUUID()), expectedCsarUUID.equals(resource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, resource.getToscaResourceName()), expectedToscaResourceName.equals(resource.getToscaResourceName())); + + RestResponse getResourceResponse = ResourceRestUtils.getLatestResourceFromCsarUuid(resource.getCsarUUID()); + Resource getResource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), Resource.class); + assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, getResource.getCsarUUID()), expectedCsarUUID.equals(getResource.getCsarUUID())); + assertTrue("toscaResourceName : " + buildAssertMessage(expectedToscaResourceName, getResource.getToscaResourceName()), expectedToscaResourceName.equals(getResource.getToscaResourceName())); + } + + @Test(enabled = true) + public void getResourceFromCsarResourceNotFound() throws Exception { + String csarUUID = "tam"; + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + + RestResponse resResponse = ResourceRestUtils.getLatestResourceFromCsarUuid(csarUUID); + + BaseRestUtils.checkStatusCode(resResponse, "Check bad request error", false, 400); + BaseRestUtils.checkErrorResponse(resResponse, ActionStatus.RESOURCE_FROM_CSAR_NOT_FOUND, csarUUID); + + } + + @Test(enabled = true) + public void getResourceFromMissingCsar() throws Exception { + String csarUUID = "abcdefg12345"; + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID(csarUUID); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + + RestResponse resResponse = ResourceRestUtils.getLatestResourceFromCsarUuid(csarUUID); + + BaseRestUtils.checkStatusCode(resResponse, "Check bad request error", false, 400); + BaseRestUtils.checkErrorResponse(resResponse, ActionStatus.RESOURCE_FROM_CSAR_NOT_FOUND, csarUUID); + + } + + @Test(enabled = true) + public void createUpdateCertifiedImportResourceFromCsarTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes = copyCsarRest(sdncModifierDetails, "valid_vf_a.csar", "valid_vf.csar"); + RestResponse updateResponse = null; + String oldName = null; + // create new resource from Csar + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("valid_vf.csar"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + String invariantUUID = resource.getInvariantUUID(); + + // change metadata + // resource name, icon, vendor name, category, template derivedFrom + oldName = resourceDetails.getName(); + resourceDetails.setName("test1"); + resourceDetails.setIcon("newicon"); + resourceDetails.setVendorName("newname"); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkErrorResponse(createResource, ActionStatus.VSP_ALREADY_EXISTS, "valid_vf.csar", oldName); + + updateResponse = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResponse); + + LifecycleRestUtils.certifyResource(resourceDetails); + // change metadata + // resource name, icon, vendor name, category, template derivedFrom + resourceDetails.setName("test2"); + resourceDetails.setIcon("new icon1"); + resourceDetails.setVendorName("new name1"); + resourceDetails.setDescription("bla bla bla"); + updateResponse = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResponse); + resource = ResponseParser.parseToObjectUsingMapper(updateResponse.getResponse(), Resource.class); + assertEquals(5, resource.getComponentInstances().size()); + assertEquals(invariantUUID, resource.getInvariantUUID()); + assertEquals(resource.getName(), "test1"); + assertEquals(resource.getIcon(), "newicon"); + assertEquals(resource.getVendorName(), "newname"); + assertEquals(resource.getDescription(), "bla bla bla"); + assertEquals(resource.getTags().contains("test2"), false); + } + + @Test + public void createImportRIRelationByCapNameFromCsarUITest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String payloadName = "vmmc_relate_by_cap_name.csar"; + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + String rootPath = System.getProperty("user.dir"); + Path path = null; + byte[] data = null; + String payloadData = null; + + path = Paths.get(rootPath + "/src/test/resources/CI/csars/vmmc_relate_by_cap_name.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + // create new resource from Csar + resourceDetails.setCsarUUID(payloadName); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + // assert all relations created + assertEquals(80, resource.getComponentInstancesRelations().size()); + } + + @Test + public void createImportRIRelationByCapNameFromCsarUITest2() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String payloadName = "vf_relate_by_cap_name.csar"; + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + String rootPath = System.getProperty("user.dir"); + Path path = null; + byte[] data = null; + String payloadData = null; + + path = Paths.get(rootPath + "/src/test/resources/CI/csars/vf_relate_by_cap_name.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + // create new resource from Csar + resourceDetails.setCsarUUID(payloadName); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + // assert relations created: 1.by name: virtual_linkable. 2.by name: + // link + Map nodes = resource.getComponentInstances().stream().collect(Collectors.toMap(n -> n.getName(), n -> n)); + Map capabilities = nodes.get("elinenode").getCapabilities().get("tosca.capabilities.network.Linkable").stream().collect(Collectors.toMap(e -> e.getName(), e -> e)); + String cp1Uid = nodes.get("cp1node").getUniqueId(); + String cp2Uid = nodes.get("cp2node").getUniqueId(); + Map> mappedByReqOwner = resource.getComponentInstancesRelations().stream().collect(Collectors.groupingBy(e -> e.getFromNode())); + assertEquals(mappedByReqOwner.get(cp1Uid).get(0).getRelationships().get(0).getCapabilityUid(), capabilities.get("virtual_linkable").getUniqueId()); + assertEquals(mappedByReqOwner.get(cp2Uid).get(0).getRelationships().get(0).getCapabilityUid(), capabilities.get("link").getUniqueId()); + } + + @Test(enabled = true) + public void importCsarCheckVfHeatEnv() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("csar_1"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + + Map deploymentArtifacts = resource.getDeploymentArtifacts(); + assertNotNull(deploymentArtifacts); + // 2 lisence, 1 heat, 1 heatenv + assertEquals(4, deploymentArtifacts.size()); + + ArtifactDefinition artifactHeat = deploymentArtifacts.get("heat0"); + assertNotNull(artifactHeat); + + ArtifactDefinition artifactHeatEnv = deploymentArtifacts.get("heat0env"); + assertNotNull(artifactHeatEnv); + + assertEquals(artifactHeat.getUniqueId(), artifactHeatEnv.getGeneratedFromId()); + assertEquals("VF HEAT ENV", artifactHeatEnv.getArtifactDisplayName()); + assertEquals("HEAT_ENV", artifactHeatEnv.getArtifactType()); + assertEquals("VF Auto-generated HEAT Environment deployment artifact", artifactHeatEnv.getDescription()); + + String designerUserId = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId(); + String testerUserId = ElementFactory.getDefaultUser(UserRoleEnum.TESTER).getUserId(); + RestResponse lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUserId, LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUserId, LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUserId, LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUserId, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUserId, LifeCycleStatesEnum.STARTCERTIFICATION); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + lifecycleChangeResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUserId, LifeCycleStatesEnum.CERTIFY); + LifecycleRestUtils.checkSuccess(lifecycleChangeResponse); + Resource certifiedResource = ResponseParser.parseToObjectUsingMapper(lifecycleChangeResponse.getResponse(), Resource.class); + + + User modifier = new User(); + modifier.setUserId(designerUserId); + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService("newtestservice1", ServiceCategoriesEnum.MOBILITY, designerUserId); + + RestResponse serviceRes = ServiceRestUtils.createService(serviceDetails, modifier); + ResourceRestUtils.checkCreateResponse(serviceRes); + Service service = ResponseParser.parseToObjectUsingMapper(serviceRes.getResponse(), Service.class); + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory.getComponentInstance(certifiedResource); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, modifier, service.getUniqueId(), service.getComponentType()); + BaseRestUtils.checkCreateResponse(createResourceInstanceResponse); + RestResponse serviceByGet = ServiceRestUtils.getService(service.getUniqueId()); + service = ResponseParser.parseToObjectUsingMapper(serviceByGet.getResponse(), Service.class); + + List componentInstances = service.getComponentInstances(); + assertNotNull(componentInstances); + + assertEquals(1, componentInstances.size()); + ComponentInstance ci = componentInstances.get(0); + Map instDepArtifacts = ci.getDeploymentArtifacts(); + assertNotNull(instDepArtifacts); + ArtifactDefinition instArtifactHeat = instDepArtifacts.get("heat0"); + assertNotNull(instArtifactHeat); + + ArtifactDefinition instArtifactHeatEnv = instDepArtifacts.get("heat0env"); + assertNotNull(instArtifactHeatEnv); + assertEquals(artifactHeat.getUniqueId(), instArtifactHeatEnv.getGeneratedFromId()); + assertEquals("HEAT ENV", instArtifactHeatEnv.getArtifactDisplayName()); + assertEquals("HEAT_ENV", instArtifactHeatEnv.getArtifactType()); + + assertEquals(artifactHeat.getUniqueId(), instArtifactHeat.getUniqueId()); + //different artifacts + assertTrue( !artifactHeatEnv.getUniqueId().equals(instArtifactHeat.getUniqueId()) ); + + + } + + @Test(enabled = true) + public void createAndUpdateCsarCheckVfHeatEnv() throws Exception { + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setCsarUUID("orig2G_org"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + + Map deploymentArtifacts = resource.getDeploymentArtifacts(); + assertNotNull(deploymentArtifacts); + + assertEquals(13, deploymentArtifacts.size()); + + ArtifactDefinition artifactHeat = deploymentArtifacts.get("heat0"); + assertNotNull(artifactHeat); + + ArtifactDefinition artifactHeatEnv = deploymentArtifacts.get("heat0env"); + assertNotNull(artifactHeatEnv); + + assertEquals(artifactHeat.getUniqueId(), artifactHeatEnv.getGeneratedFromId()); + assertEquals("VF HEAT ENV", artifactHeatEnv.getArtifactDisplayName()); + assertEquals("HEAT_ENV", artifactHeatEnv.getArtifactType()); + assertEquals("VF Auto-generated HEAT Environment deployment artifact", artifactHeatEnv.getDescription()); + + List groups = resource.getGroups(); + assertEquals(2, groups.size()); + GroupDefinition group1 = groups.stream().filter(p -> p.getName().contains("module-0")).findAny().get(); + GroupDefinition group2 = groups.stream().filter(p -> p.getName().contains("module-1")).findAny().get(); + assertEquals(11, group1.getArtifacts().size()); + assertEquals(3, group2.getArtifacts().size()); + + resourceDetails.setCsarUUID("orig2G_update"); + + RestResponse updateResource = ResourceRestUtils.updateResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + + + Map deploymentArtifactsUpd = resource.getDeploymentArtifacts(); + assertNotNull(deploymentArtifactsUpd); + + assertEquals(13, deploymentArtifactsUpd.size()); + + ArtifactDefinition artifactHeatUpd = deploymentArtifacts.get("heat0"); + assertNotNull(artifactHeatUpd); + + ArtifactDefinition artifactHeatEnvUpd = deploymentArtifacts.get("heat0env"); + assertNotNull(artifactHeatEnvUpd); + + groups = resource.getGroups(); + assertEquals(2, groups.size()); + assertEquals(7, groups.get(0).getArtifacts().size()); + assertEquals(7, groups.get(1).getArtifacts().size()); + + + } + + @Test + public void importInnerVfcWithArtifactsSucceed() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String rootPath = System.getProperty("user.dir"); + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + + String payloadName = "ImportArtifactsToVFC.csar"; + Path path = Paths.get(rootPath + "/src/test/resources/CI/csars/ImportArtifactsToVFC.csar"); + byte[] data = Files.readAllBytes(path); + String payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + List componentInstances = resource.getComponentInstances(); + List reducedComponentInstances = componentInstances.stream() + .filter(ci->ci.getNormalizedName().contains("server_sm")) + .collect(Collectors.toList()); + assertTrue(!reducedComponentInstances.isEmpty() && reducedComponentInstances.size() == 2); + reducedComponentInstances.stream().forEach(ci->isValidArtifacts(ci)); + + payloadName = "ImportArtifactsToVFC_empty.csar"; + path = Paths.get(rootPath + "/src/test/resources/CI/csars/ImportArtifactsToVFC_empty.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setName(resourceDetails.getName()+"2"); + resourceDetails.setPayloadData(payloadData); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + componentInstances = resource.getComponentInstances(); + reducedComponentInstances = componentInstances.stream() + .filter(ci->ci.getNormalizedName().contains("server_sm")) + .collect(Collectors.toList()); + assertTrue(!reducedComponentInstances.isEmpty() && reducedComponentInstances.size() == 2); + reducedComponentInstances.stream() + .forEach(ci->assertTrue( + (ci.getDeploymentArtifacts()==null || ci.getDeploymentArtifacts().isEmpty()) && + (ci.getArtifacts()==null || ci.getArtifacts().isEmpty())) + ); + } + + private void isValidArtifacts(ComponentInstance ci) { + assertTrue(!ci.getDeploymentArtifacts().isEmpty() && ci.getDeploymentArtifacts().size() == 11); + ci.getDeploymentArtifacts().values().stream() + .forEach(a->assertTrue(a.getArtifactName().startsWith("Some"))); + + assertTrue(!ci.getArtifacts().isEmpty() && ci.getArtifacts().size() == 1); + ci.getArtifacts().values().stream() + .forEach(a->assertTrue(a.getArtifactName().startsWith("Process"))); + } + + private void verifyMembers(Map createdMembers, Map compNameToUniqueId) { + for (Map.Entry entry : createdMembers.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + String comparedValue = compNameToUniqueId.get(key); + + assertEquals("compare instance ids", comparedValue, value); + } + + } + + private static Map prepareHeadersMap(String userId) { + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + if (userId != null) { + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), userId); + } + return headersMap; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportGenericResourceCITest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportGenericResourceCITest.java new file mode 100644 index 0000000000..110fa0f53c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportGenericResourceCITest.java @@ -0,0 +1,600 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.imports; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.http.HttpStatus; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.entity.mime.content.StringBody; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.ImportTestTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.RespJsonKeysEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.TODO.ImportCapabilityTypeCITest; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ImportRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +import fj.data.Either; + +public class ImportGenericResourceCITest extends ComponentBaseTest { + private static Logger log = LoggerFactory.getLogger(ImportGenericResourceCITest.class.getName()); + private static final String FILE_NAME_MY_COMPUTE = "tosca.nodes.MyCompute"; + private static final String RESOURCE_NAME_UPDATE_COMPUTE = "userUpdateCompute"; + private static final String RESOURCE_NAME_MY_COMPUTE = "myCompute"; + private static final String RESOURCE_NAME_USER_COMPUTE = "userCompute"; + private static final String FILE_NAME_USER_COMPUTE = "tosca.nodes.userCompute"; + @Rule + public static TestName name = new TestName(); + + public ImportGenericResourceCITest() { + super(name, ImportGenericResourceCITest.class.getName()); + } + + @BeforeClass + public static void beforeImportClass() throws IOException { + ImportCapabilityTypeCITest.importAllCapabilityTypes(); + // removeAllNormativeTypeResources(); + // importAllNormativeTypesResources(UserRoleEnum.ADMIN); + } + + static Config config = Config.instance(); + + public static Map removeAllNormativeTypeResources() throws ClientProtocolException, IOException { + Map normativeExistInDB = new HashMap<>(); + + for (NormativeTypesEnum current : NormativeTypesEnum.values()) { + Boolean existedBeforeDelete = ImportRestUtils.removeNormativeTypeResource(current); + normativeExistInDB.put(current, existedBeforeDelete); + } + return normativeExistInDB; + } + + public static Either getNormativeTypeResource(NormativeTypesEnum current) throws ClientProtocolException, IOException { + return getResource(current.getNormativeName(), "1.0"); + } + + @Test + public void importAllTestResources() throws Exception { + for (ImportTestTypesEnum currResource : ImportTestTypesEnum.values()) { + DbUtils.cleanAllAudits(); + + RestResponse importResponse = ImportRestUtils.importTestResource(currResource, UserRoleEnum.ADMIN); + // System.err.println("import Resource + // "+"<"+currResource+">"+"response: + // "+importResponse.getErrorCode()); + ImportRestUtils.validateImportTestTypesResp(currResource, importResponse); + if (currResource.getvalidateAudit() == true) { + // validate audit + String baseVersion = "1.0"; + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(currResource.getActionStatus().name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + String auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setModifierUid(UserRoleEnum.ADMIN.getUserId()); + expectedResourceAuditJavaObject.setModifierName(UserRoleEnum.ADMIN.getUserName()); + expectedResourceAuditJavaObject.setResourceName(currResource.getNormativeName()); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion(baseVersion); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.toString()); + expectedResourceAuditJavaObject.setComment(null); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + List variables = (currResource.getErrorParams() != null ? currResource.getErrorParams() : new ArrayList()); + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + AuditValidationUtils.validateAuditImport(expectedResourceAuditJavaObject, auditAction); + } + } + } + + // ----------------------------------------------------------------------------------- + protected void validateMyComputeCapabilities(Map map) { + assertTrue(map.containsKey("capabilities")); + Map capabilities = (Map) map.get("capabilities"); + assertTrue(capabilities.containsKey("tosca.capabilities.Container")); + List hostCapList = (List) capabilities.get("tosca.capabilities.Container"); + assertFalse(hostCapList.isEmpty()); + Map hostCap = (Map) hostCapList.get(0); + validateField(hostCap, "type", "tosca.capabilities.Container"); + validateField(hostCap, "name", "host"); + validateField(hostCap, "validSourceTypes", Arrays.asList(new String[] { "tosca.nodes.SoftwareComponent" })); + + assertTrue(capabilities.containsKey("tosca.capabilities.Endpoint.Admin")); + List endPointCapList = (List) capabilities.get("tosca.capabilities.Endpoint.Admin"); + assertFalse(endPointCapList.isEmpty()); + Map endPointCap = (Map) endPointCapList.get(0); + validateField(endPointCap, "name", "endpoint"); + validateField(endPointCap, "type", "tosca.capabilities.Endpoint.Admin"); + + assertTrue(capabilities.containsKey("tosca.capabilities.OperatingSystem")); + List osCapList = (List) capabilities.get("tosca.capabilities.OperatingSystem"); + assertFalse(osCapList.isEmpty()); + Map osCap = (Map) osCapList.get(0); + validateField(osCap, "name", "os"); + validateField(osCap, "type", "tosca.capabilities.OperatingSystem"); + + assertTrue(capabilities.containsKey("tosca.capabilities.Scalable")); + List scalableCapList = (List) capabilities.get("tosca.capabilities.Scalable"); + assertFalse(scalableCapList.isEmpty()); + Map scalableCap = (Map) scalableCapList.get(0); + validateField(scalableCap, "name", "scalable"); + validateField(scalableCap, "type", "tosca.capabilities.Scalable"); + + assertTrue(capabilities.containsKey("tosca.capabilities.network.Bindable")); + List bindingCapList = (List) capabilities.get("tosca.capabilities.network.Bindable"); + assertFalse(bindingCapList.isEmpty()); + Map bindingCap = (Map) bindingCapList.get(0); + validateField(bindingCap, "name", "binding"); + validateField(bindingCap, "type", "tosca.capabilities.network.Bindable"); + + } + + protected void validateMyComputeResource(String resourceName, String resourceVersion, String expectedState) throws ClientProtocolException, IOException { + Either eitherMyCompute = getResource(resourceName, resourceVersion); + assertTrue(eitherMyCompute.isLeft()); + String testComputeYml = eitherMyCompute.left().value(); + + Map map = new HashMap(); + map = (Map) new Gson().fromJson(testComputeYml, map.getClass()); + + validateMyComputeBasicFields(map, resourceName, resourceVersion, expectedState); + + validateMyComputeCapabilities(map); + + validateMyComputeRequirements(map); + validateField(map, RespJsonKeysEnum.RESOURCE_VERSION.getRespJsonKeyName(), resourceVersion); + + } + + protected void validateMyComputeResource(String uid, String resourceName, String resourceVersion, String expectedState) throws ClientProtocolException, IOException { + RestResponse resourceResponse = ResourceRestUtils.getResource(uid); + ResourceRestUtils.checkSuccess(resourceResponse); + String testComputeYml = resourceResponse.getResponse(); + + // Either eitherMyCompute = getResource(resourceName, + // resourceVersion); + // assertTrue( eitherMyCompute.isLeft() ); + // String testComputeYml = eitherMyCompute.left().value(); + + Map map = new HashMap(); + map = (Map) new Gson().fromJson(testComputeYml, map.getClass()); + + validateMyComputeBasicFields(map, resourceName, resourceVersion, expectedState); + + validateMyComputeCapabilities(map); + + validateMyComputeRequirements(map); + validateField(map, RespJsonKeysEnum.RESOURCE_VERSION.getRespJsonKeyName(), resourceVersion); + + } + + protected void validateMyComputeResourceAfterUpdate(String uid, String resourceName, String resourceVersion, String expectedState) throws ClientProtocolException, IOException { + RestResponse resourceResponse = ResourceRestUtils.getResource(uid); + ResourceRestUtils.checkSuccess(resourceResponse); + String testComputeYml = resourceResponse.getResponse(); + + // Either eitherMyCompute = getResource(resourceName, + // resourceVersion); + // assertTrue( eitherMyCompute.isLeft() ); + + // String testComputeYml = eitherMyCompute.left().value(); + + Map map = new HashMap(); + map = (Map) new Gson().fromJson(testComputeYml, map.getClass()); + + validateMyComputeBasicFields(map, resourceName, resourceVersion, expectedState); + validateField(map, RespJsonKeysEnum.DESCRIPTION.getRespJsonKeyName(), "Short description"); + validateField(map, RespJsonKeysEnum.VENDOR_NAME.getRespJsonKeyName(), "UserVendor"); + validateField(map, RespJsonKeysEnum.VENDOR_RELEASE.getRespJsonKeyName(), "1.1.2"); + + // validateMyComputeCapabilities(map); + // AssertJUnit.assertTrue(map.containsKey("capabilities")); + // Map capabilities = (Map) + // map.get("capabilities"); + // AssertJUnit.assertTrue(capabilities.containsKey("host")); + // Map hostCap = (Map) + // capabilities.get("host"); + // validateField(hostCap, "type", "tosca.capabilities.Container"); + // validateField(hostCap, "validSourceTypes", Arrays.asList(new + // String[]{"tosca.nodes.SoftwareComponent"})); + // + // AssertJUnit.assertTrue(capabilities.containsKey("endpoint")); + // Map endPointCap = (Map) + // capabilities.get("endpoint"); + // validateField(endPointCap, "type", + // "tosca.capabilities.Endpoint.Admin"); + + assertTrue(map.containsKey("capabilities")); + Map capabilities = (Map) map.get("capabilities"); + assertTrue(capabilities.containsKey("tosca.capabilities.Container")); + List hostCapList = (List) capabilities.get("tosca.capabilities.Container"); + assertFalse(hostCapList.isEmpty()); + Map hostCap = (Map) hostCapList.get(0); + validateField(hostCap, "type", "tosca.capabilities.Container"); + validateField(hostCap, "name", "host"); + validateField(hostCap, "validSourceTypes", Arrays.asList(new String[] { "tosca.nodes.SoftwareComponent" })); + + assertTrue(capabilities.containsKey("tosca.capabilities.Endpoint.Admin")); + List endPointCapList = (List) capabilities.get("tosca.capabilities.Endpoint.Admin"); + assertFalse(endPointCapList.isEmpty()); + Map endPointCap = (Map) endPointCapList.get(0); + validateField(endPointCap, "name", "endpoint"); + validateField(endPointCap, "type", "tosca.capabilities.Endpoint.Admin"); + + validateMyComputeRequirements(map); + validateField(map, RespJsonKeysEnum.RESOURCE_VERSION.getRespJsonKeyName(), resourceVersion); + + } + + protected void validateMyComputeRequirements(Map map) { + assertTrue(map.containsKey("requirements")); + Map requirements = (Map) map.get("requirements"); + + assertTrue(requirements.containsKey("tosca.capabilities.Attachment")); + List localStorageReqList = (List) requirements.get("tosca.capabilities.Attachment"); + assertFalse(localStorageReqList.isEmpty()); + Map localStorageReq = (Map) localStorageReqList.get(0); + validateField(localStorageReq, "capability", "tosca.capabilities.Attachment"); + validateField(localStorageReq, "node", "tosca.nodes.BlockStorage"); + validateField(localStorageReq, "relationship", "tosca.relationships.AttachesTo"); + validateField(localStorageReq, "name", "local_storage"); + } + + protected void validateMyComputeBasicFields(Map map, String resourceName, String resourceVersion, String expectedState) { + validateField(map, RespJsonKeysEnum.IS_ABSTRACT.getRespJsonKeyName(), false); + // validateField(map, RespJsonKeysEnum.CATEGORIES.getRespJsonKeyName(), + // categoryDefinition); + // validateField(map, RespJsonKeysEnum.UNIQUE_ID.getRespJsonKeyName(), + // UniqueIdBuilder.buildResourceUniqueId(resourceName, + // resourceVersion)); + validateField(map, RespJsonKeysEnum.RESOURCE_NAME.getRespJsonKeyName(), resourceName); + validateField(map, RespJsonKeysEnum.TAGS.getRespJsonKeyName(), Arrays.asList(new String[] { resourceName })); + validateField(map, RespJsonKeysEnum.LIFE_CYCLE_STATE.getRespJsonKeyName(), expectedState); + + validateField(map, RespJsonKeysEnum.DERIVED_FROM.getRespJsonKeyName(), Arrays.asList(new String[] { "tosca.nodes.Root" })); + } + + protected static void validateField(Map map, String jsonField, Object expectedValue) { + if (expectedValue == null) { + assertTrue(!map.containsKey(jsonField)); + } else { + assertTrue("map does not contain field " + jsonField, map.containsKey(jsonField)); + Object foundValue = map.get(jsonField); + compareElements(expectedValue, foundValue); + } + } + + protected static void compareElements(Object expectedValue, Object foundValue) { + if (expectedValue instanceof String) { + assertTrue(foundValue instanceof String); + assertTrue(foundValue.equals(expectedValue)); + } + + else if (expectedValue instanceof Boolean) { + assertTrue(foundValue instanceof Boolean); + assertTrue(foundValue == expectedValue); + } else if (expectedValue instanceof Map) { + assertTrue(foundValue instanceof Map); + Map foundMap = (Map) foundValue; + Map excpectedMap = (Map) expectedValue; + assertTrue(foundMap.size() == excpectedMap.size()); + Iterator foundkeyItr = foundMap.keySet().iterator(); + while (foundkeyItr.hasNext()) { + String foundKey = foundkeyItr.next(); + assertTrue(excpectedMap.containsKey(foundKey)); + compareElements(excpectedMap.get(foundKey), foundMap.get(foundKey)); + } + + } else if (expectedValue instanceof List) { + assertTrue(foundValue instanceof List); + List foundList = (List) foundValue; + List excpectedList = (List) expectedValue; + assertTrue(foundList.size() == excpectedList.size()); + for (int i = 0; i < foundList.size(); i++) { + compareElements(excpectedList.get(i), foundList.get(i)); + } + + } else if (expectedValue instanceof CategoryDefinition) { + assertTrue(foundValue instanceof Map); + CategoryDefinition expCat = (CategoryDefinition) expectedValue; + Map actCat = (Map) foundValue; + assertEquals(expCat.getName(), actCat.get("name")); + + // assertEquals(expCat.getSubcategories().get(0).getName(), + // actCat.get("subcategories").getName()); + } else { + assertTrue(foundValue.equals(expectedValue)); + } + } + + public static void restoreToOriginalState(Map originalState, UserRoleEnum userRole) throws IOException { + removeAllNormativeTypeResources(); + + Iterator> iterator = originalState.entrySet().iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + Boolean isExistBeforeDelete = entry.getValue(); + if (isExistBeforeDelete) { + importNormativeResource(entry.getKey(), userRole); + } + } + + } + + public static void importAllNormativeTypesResources(UserRoleEnum userRole) throws IOException { + for (NormativeTypesEnum currResource : NormativeTypesEnum.values()) { + Either resource = getResource(currResource.getNormativeName(), "1.0"); + if (resource.isRight()) { + importNormativeResource(currResource, userRole); + } + } + + } + + protected static Integer importNormativeResource(NormativeTypesEnum resource, UserRoleEnum userRole) throws IOException { + return importResource(resource.getFolderName(), userRole, true); + } + + protected static Integer importResource(String folderName, UserRoleEnum userRole, boolean isNormative) throws IOException { + Config config = Utils.getConfig(); + CloseableHttpResponse response = null; + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + + mpBuilder.addPart("resourceZip", new FileBody(getZipFile(folderName))); + mpBuilder.addPart("resourceMetadata", new StringBody(getJsonStringOfFile(folderName, folderName + ".json"), ContentType.APPLICATION_JSON)); + + String url = String.format(Urls.IMPORT_RESOURCE_NORMATIVE, config.getCatalogBeHost(), config.getCatalogBePort()); + if (!isNormative) { + url = String.format(Urls.IMPORT_USER_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort()); + } + + CloseableHttpClient client = HttpClients.createDefault(); + try { + HttpPost httpPost = new HttpPost(url); + httpPost.addHeader("USER_ID", userRole.getUserId()); + httpPost.setEntity(mpBuilder.build()); + response = client.execute(httpPost); + return response.getStatusLine().getStatusCode(); + } finally { + closeResponse(response); + closeHttpClient(client); + + } + } + + public static void closeHttpClient(CloseableHttpClient client) { + try { + if (client != null) { + client.close(); + } + } catch (IOException e) { + log.debug("failed to close client or response: ", e); + } + } + + public static void closeResponse(CloseableHttpResponse response) { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + log.debug("failed to close client or response: ", e); + } + } + + protected static String getJsonStringOfFile(String folderName, String fileName) throws IOException { + String sourceDir = config.getImportResourceConfigDir(); + sourceDir += File.separator + "normative-types"; + + java.nio.file.Path filePath = FileSystems.getDefault().getPath(sourceDir + File.separator + folderName, fileName); + byte[] fileContent = Files.readAllBytes(filePath); + String content = new String(fileContent); + return content; + } + + protected static File getZipFile(String elementName) throws IOException { + String sourceDir = config.getImportResourceConfigDir(); + sourceDir += File.separator + "normative-types"; + + java.nio.file.Path filePath = FileSystems.getDefault().getPath(sourceDir + File.separator + elementName, "normative-types-new-" + elementName + ".zip"); + return filePath.toFile(); + } + + protected static String getTestJsonStringOfFile(String folderName, String fileName) throws IOException { + String sourceDir = config.getImportResourceTestsConfigDir(); + java.nio.file.Path filePath = FileSystems.getDefault().getPath(sourceDir + File.separator + folderName, fileName); + byte[] fileContent = Files.readAllBytes(filePath); + String content = new String(fileContent); + return content; + } + + protected static File getTestZipFile(String elementName) throws IOException { + String sourceDir = config.getImportResourceTestsConfigDir(); + + java.nio.file.Path filePath = FileSystems.getDefault().getPath(sourceDir + File.separator + elementName, "normative-types-new-" + elementName + ".zip"); + return filePath.toFile(); + } + + protected static Either getResource(String name, String version) throws IOException { + RestResponse resource = ResourceRestUtils.getResourceByNameAndVersion(UserRoleEnum.DESIGNER.getUserId(), name, version); + if (resource.getErrorCode() == ImportRestUtils.STATUS_CODE_GET_SUCCESS) { + return Either.left(resource.getResponse()); + // return Either.right(true); + + } + return Either.right(false); + } + + @Test + public void testImportWithRequirmentsAndCapabilities() throws IOException { + String fileName = FILE_NAME_MY_COMPUTE; + RestResponse response = ImportRestUtils.importNormativeResourceByName(RESOURCE_NAME_MY_COMPUTE, UserRoleEnum.ADMIN); + Integer statusCode = response.getErrorCode(); + assertTrue(statusCode == ImportRestUtils.STATUS_CODE_IMPORT_SUCCESS); + String uid = ResponseParser.getUniqueIdFromResponse(response); + validateMyComputeResource(uid, fileName, "1.0", "CERTIFIED"); + } + + @Test + public void testImportWithUpdateNormativeType() throws IOException { + String fileName = FILE_NAME_MY_COMPUTE; + RestResponse response = ImportRestUtils.importNormativeResourceByName(RESOURCE_NAME_MY_COMPUTE, UserRoleEnum.ADMIN); + Integer statusCode = response.getErrorCode(); + assertTrue(statusCode == BaseRestUtils.STATUS_CODE_IMPORT_SUCCESS); + String uid = ResponseParser.getUniqueIdFromResponse(response); + validateMyComputeResource(uid, fileName, "1.0", "CERTIFIED"); + + // update + response = ImportRestUtils.importNormativeResourceByName(RESOURCE_NAME_MY_COMPUTE, UserRoleEnum.ADMIN); + statusCode = response.getErrorCode(); + assertTrue(statusCode == ImportRestUtils.STATUS_CODE_UPDATE_SUCCESS); + uid = ResponseParser.getUniqueIdFromResponse(response); + validateMyComputeResource(uid, fileName, "2.0", "CERTIFIED"); + + } + + @Test + public void testImportWithInvalidDefaultValue() throws IOException { + RestResponse response = ImportRestUtils.importNewResourceByName("portInvalidDefaultValue", UserRoleEnum.DESIGNER); + assertTrue(response.getErrorCode() == HttpStatus.SC_BAD_REQUEST); + } + + @Test + public void testImportUserResource() throws IOException { + String fileName = FILE_NAME_USER_COMPUTE; + RestResponse response = ImportRestUtils.importNewResourceByName(RESOURCE_NAME_USER_COMPUTE, UserRoleEnum.DESIGNER); + Integer statusCode = response.getErrorCode(); + assertTrue(statusCode == ImportRestUtils.STATUS_CODE_IMPORT_SUCCESS); + String uid = ResponseParser.getUniqueIdFromResponse(response); + validateMyComputeResource(uid, fileName, "0.1", "NOT_CERTIFIED_CHECKOUT"); + + } + + @Test + public void testImportAndUpdateUserResource() throws IOException { + String fileName = FILE_NAME_USER_COMPUTE; + RestResponse response = ImportRestUtils.importNewResourceByName(RESOURCE_NAME_USER_COMPUTE, UserRoleEnum.DESIGNER); + Integer statusCode = response.getErrorCode(); + assertTrue(statusCode == ImportRestUtils.STATUS_CODE_IMPORT_SUCCESS); + String uid = ResponseParser.getUniqueIdFromResponse(response); + validateMyComputeResource(uid, fileName, "0.1", "NOT_CERTIFIED_CHECKOUT"); + response = ImportRestUtils.importNewResourceByName(RESOURCE_NAME_UPDATE_COMPUTE, UserRoleEnum.DESIGNER); + statusCode = response.getErrorCode(); + assertTrue(statusCode == ImportRestUtils.STATUS_CODE_UPDATE_SUCCESS); + uid = ResponseParser.getUniqueIdFromResponse(response); + validateMyComputeResourceAfterUpdate(uid, fileName, "0.1", "NOT_CERTIFIED_CHECKOUT"); + + } + + @Test + public void testImportAndUpdateChangesUserResource() throws IOException { + String fileName = FILE_NAME_USER_COMPUTE; + RestResponse response = ImportRestUtils.importNewResourceByName(RESOURCE_NAME_USER_COMPUTE, UserRoleEnum.DESIGNER); + Integer statusCode = response.getErrorCode(); + assertTrue(statusCode == ImportRestUtils.STATUS_CODE_IMPORT_SUCCESS); + String uid = ResponseParser.getUniqueIdFromResponse(response); + validateMyComputeResource(uid, fileName, "0.1", "NOT_CERTIFIED_CHECKOUT"); + // Either resource = getResource(fileName, "0.1"); + // assertTrue(resource.isLeft()); + + response = ImportRestUtils.importNewResourceByName(RESOURCE_NAME_UPDATE_COMPUTE, UserRoleEnum.DESIGNER); + statusCode = response.getErrorCode(); + assertTrue(statusCode == ImportRestUtils.STATUS_CODE_UPDATE_SUCCESS); + validateMyComputeResourceAfterUpdate(uid, fileName, "0.1", "NOT_CERTIFIED_CHECKOUT"); + + } + + @Test + public void testImportCheckoutAndUpdateUserResource() throws IOException { + String fileName = FILE_NAME_USER_COMPUTE; + RestResponse response = ImportRestUtils.importNormativeResourceByName(RESOURCE_NAME_USER_COMPUTE, UserRoleEnum.ADMIN); + Integer statusCode = response.getErrorCode(); + assertTrue(statusCode == ImportRestUtils.STATUS_CODE_IMPORT_SUCCESS); + String uid = ResponseParser.getUniqueIdFromResponse(response); + validateMyComputeResource(uid, fileName, "1.0", "CERTIFIED"); + + response = ImportRestUtils.importNewResourceByName(RESOURCE_NAME_USER_COMPUTE, UserRoleEnum.DESIGNER); + statusCode = response.getErrorCode(); + assertEquals("check response code after update resource", ImportRestUtils.STATUS_CODE_UPDATE_SUCCESS, statusCode.intValue()); + uid = ResponseParser.getUniqueIdFromResponse(response); + validateMyComputeResource(uid, fileName, "1.1", "NOT_CERTIFIED_CHECKOUT"); + + } + + @Test + public void importNormativeTypesTesterUserRole() throws Exception { + Integer statusCode = ImportRestUtils.importNormativeResourceByName(RESOURCE_NAME_MY_COMPUTE, UserRoleEnum.TESTER).getErrorCode(); + assertTrue(statusCode == ImportRestUtils.RESTRICTED_OPERATION); + } + + @Test + public void importNormativeTypesDesignerUserRole() throws Exception { + Integer statusCode = ImportRestUtils.importNormativeResourceByName(RESOURCE_NAME_MY_COMPUTE, UserRoleEnum.DESIGNER).getErrorCode(); + assertTrue(statusCode == 409); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportNewResourceCITest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportNewResourceCITest.java new file mode 100644 index 0000000000..c069f984d2 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportNewResourceCITest.java @@ -0,0 +1,1529 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.imports; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.apache.http.HttpStatus; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceRespJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.ImportTestTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.ArtifactUtils; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.Convertor; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ImportRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ResourceValidationUtils; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.exception.ResponseFormat; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class ImportNewResourceCITest extends ComponentBaseTest { + + // public static UserUtils userUtils = new UserUtils(); + // public ResourceUtils resourceUtils = new ResourceUtils(); + // public AuditValidationUtils AuditValidationUtils = new + // AuditValidationUtils(); + // protected ArtifactUtils artifactUtils = new ArtifactUtils(); + + protected String resourceVersion = null; + protected String auditAction = null; + public User sdncModifierDetails = new User(); + protected String artifactName1 = "data_artifact1.sh"; + protected String artifactName2 = "data_artifact2.sh"; + protected String interfaze = "standard"; + protected String interfaceArtifactName = "data_interface1.sh"; + + private String SPECIAL_CHARACTERS = "~!#@~$%^*()[];:'\"|\\/"; + + public ResourceReqDetails resourceDetails = new ResourceReqDetails(); + + public Gson gson = new Gson(); + + @Rule + public static TestName name = new TestName(); + + public ImportNewResourceCITest() { + super(name, ImportNewResourceCITest.class.getName()); + } + + @BeforeMethod + public void before() throws Exception { + + // init user + sdncModifierDetails.setUserId(UserRoleEnum.ADMIN.getUserId()); + // init resource details + resourceDetails = ElementFactory.getDefaultResource("importResource4test", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, "jh0003"); + } + + @Test + public void importAllTestResources_toValidateNewAPI() throws Exception { + + for (ImportTestTypesEnum currResource : ImportTestTypesEnum.values()) { + // clean audit + DbUtils.cleanAllAudits(); + + // import testResources trough newResource API + RestResponse importResponse = ImportRestUtils.importNewResourceByName(currResource.getFolderName(), + UserRoleEnum.ADMIN); + System.err.println("import Resource " + "<" + currResource.getFolderName() + ">" + "response: " + + importResponse.getErrorCode()); + + // validate response + ImportRestUtils.validateImportTestTypesResp(currResource, importResponse); + if (currResource.getvalidateAudit() == true) { + // validate audit + // String baseVersion="0.1"; + String baseVersion = ""; + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(currResource.getActionStatus().name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + String auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setModifierUid(UserRoleEnum.ADMIN.getUserId()); + expectedResourceAuditJavaObject.setModifierName(UserRoleEnum.ADMIN.getUserName()); + expectedResourceAuditJavaObject.setResourceName(currResource.getNormativeName()); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion(baseVersion); + expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setComment(null); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + List variables = (currResource.getErrorParams() != null ? currResource.getErrorParams() + : new ArrayList()); + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + AuditValidationUtils.validateAuditImport(expectedResourceAuditJavaObject, auditAction); + } + } + } + + protected RestResponse importNewResource(UserRoleEnum userRoleEnum) throws Exception { + + // init user + sdncModifierDetails.setUserId(userRoleEnum.getUserId()); + // init resource details + resourceDetails = ElementFactory.getDefaultResource("importResource4test", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, "jh0003"); + // clean ES DB + DbUtils.cleanAllAudits(); + // import new resource (expected checkOut state) + RestResponse importResponse = ImportRestUtils.importNewResourceByName("importResource4test", userRoleEnum); + return importResponse; + } + + @Test(enabled = false) + public void importUIResource() throws IOException { + String payload = "tosca_definitions_version: tosca_simple_yaml_1_0_0\r\n" + "node_types: \r\n" + + " org.openecomp.resource.importResource4test:\r\n" + " derived_from: tosca.nodes.Root\r\n" + + " description: someDesc"; + + String encodedPayload = new String(Base64.encodeBase64(payload.getBytes())); + + String json = "{\r\n" + " \"resourceName\": \"importResource4test\",\r\n" + + " \"payloadName\": \"importResource4test.yml\",\r\n" + + " \"categories\": [{\"name\": \"Application L4+\",\"normalizedName\": \"application l4+\",\"uniqueId\": \"resourceNewCategory.application l4+\",\"subcategories\": [{\"name\": \"Web Server\"}]}],\r\n" + + " \"description\": \"ResourceDescription\",\r\n" + " \"vendorName\": \"VendorName\",\r\n" + + " \"vendorRelease\": \"VendorRelease\",\r\n" + " \"contactId\": \"AT1234\",\r\n" + + " \"icon\": \"router\",\r\n" + " \"tags\": [\r\n" + " \"importResource4test\"\r\n" + " ],\r\n" + + " \"payloadData\": \"" + encodedPayload + "\"\r\n" + "}"; + + String md5 = GeneralUtility.calculateMD5ByString(json); + + Map headers = new HashMap(); + headers.put(Constants.MD5_HEADER, md5); + headers.put(Constants.USER_ID_HEADER, UserRoleEnum.ADMIN.getUserId()); + headers.put(Constants.CONTENT_TYPE_HEADER, "application/json"); + + String url = String.format(Urls.CREATE_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort()); + + HttpRequest httpUtil = new HttpRequest(); + RestResponse httpSendPost = httpUtil.httpSendPost(url, json, headers); + Integer errorCode = httpSendPost.getErrorCode(); + assertTrue(errorCode == HttpStatus.SC_CREATED); + + } + + // TODO DE171337 + @Test(enabled = false) + public void importNewResource_suc() throws Exception { + + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + + // validate response + + resourceVersion = "0.1"; + + // ResourceRespJavaObject resourceRespJavaObject = + // Convertor.constructFieldsForRespValidation(resourceDetails, + // resourceVersion); + // resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // ResourceValidationUtils.validateResp(importResponse, + // resourceRespJavaObject); + // + // //validate get response + // + // RestResponse resourceGetResponse = + // ResourceRestUtils.getResource(sdncModifierDetails, resourceVersion); + // ResourceValidationUtils.validateResp(resourceGetResponse, + // resourceRespJavaObject); + Resource resourceFromImport = ResponseParser.convertResourceResponseToJavaObject(importResponse.getResponse()); + assertNotNull(resourceFromImport); + + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceRespJavaObject.getUniqueId()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + + // validate + ResourceValidationUtils.validateModelObjects(resourceFromImport, resourceFromGet); + + // validate audit + resourceDetails.setVersion(resourceDetails.getVersion()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + + auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setToscaNodeType(resourceFromGet.getToscaResourceName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void importNewResource_byTester_failed() throws Exception { + + RestResponse importResponse = importNewResource(UserRoleEnum.TESTER); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 409, importResponse.getErrorCode().intValue()); + + } + + // TODO DE171337 + @Test(enabled = false) + public void importNewResource_existInCheckout_updateVendorName_updateCategory() throws Exception { + + // import new resource + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + + // clean audit + DbUtils.cleanAllAudits(); + + // import new resource while resource already exist in other state + importResponse = ImportRestUtils.importNewResourceByName("importResource4testUpdateVendorNameAndCategory", + UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 200, importResponse.getErrorCode().intValue()); + + // validate response + Resource resourceFromImport = ResponseParser.convertResourceResponseToJavaObject(importResponse.getResponse()); + assertNotNull(resourceFromImport); + + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceRespJavaObject.getUniqueId()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + + // validate + ResourceValidationUtils.validateModelObjects(resourceFromImport, resourceFromGet); + + // validate audit + resourceDetails.setVersion(resourceDetails.getVersion()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails); + + auditAction = "ResourceImport"; + resourceVersion = "0.1"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setPrevVersion(resourceVersion); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setToscaNodeType(resourceFromGet.getToscaResourceName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + @Test + public void importNewResource_perfromByAdmin_ownedBy_diffrentUser() throws Exception { + + RestResponse importResponse = importNewResource(UserRoleEnum.DESIGNER); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + + Resource resourceFromImport = ResponseParser.convertResourceResponseToJavaObject(importResponse.getResponse()); + // clean audit + DbUtils.cleanAllAudits(); + + importResponse = importNewResource(UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_IN_CHECKOUT_STATE.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), importResponse.getErrorCode()); + + String[] split = resourceFromImport.getLastUpdaterFullName().split(" "); + String firstName = split[0]; + String lastName = split[1]; + List variables = Arrays.asList(resourceFromImport.getName(), "resource", firstName, lastName, + resourceFromImport.getLastUpdaterUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_IN_CHECKOUT_STATE.name(), variables, + importResponse.getResponse()); + + } + + @Test + public void importNewResource_perfromByDesigner_ownedBy_diffrentUser() throws Exception { + + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + Resource resourceFromImport = ResponseParser.convertResourceResponseToJavaObject(importResponse.getResponse()); + // clean audit + DbUtils.cleanAllAudits(); + + importResponse = importNewResource(UserRoleEnum.DESIGNER); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_IN_CHECKOUT_STATE.name()); + assertEquals("Check response code after adding artifact", errorInfo.getCode(), importResponse.getErrorCode()); + + String[] split = resourceFromImport.getLastUpdaterFullName().split(" "); + String firstName = split[0]; + String lastName = split[1]; + List variables = Arrays.asList(resourceFromImport.getName(), "resource", firstName, lastName, + resourceFromImport.getLastUpdaterUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_IN_CHECKOUT_STATE.name(), variables, + importResponse.getResponse()); + + } + + @Test(enabled = false) + public void importNewResource_nameSpace_vf() throws Exception { + RestResponse importResponse = ImportRestUtils.importNewResourceByName("importResource4testVF", + UserRoleEnum.DESIGNER); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResponse.getResponse()); + assertTrue(resourceRespJavaObject.getResourceType().equals(ResourceTypeEnum.VF)); + + } + + @Test + public void importNewResource_nameSpace_vfc() throws Exception { + RestResponse importResponse = ImportRestUtils.importNewResourceByName("importResource4testVFC", + UserRoleEnum.DESIGNER); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResponse.getResponse()); + assertTrue(resourceRespJavaObject.getResourceType().equals(ResourceTypeEnum.VFC)); + } + + @Test + public void importNewResource_nameSpace_vl() throws Exception { + RestResponse importResponse = ImportRestUtils.importNewResourceByName("importResource4testVL", + UserRoleEnum.DESIGNER); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResponse.getResponse()); + assertTrue(resourceRespJavaObject.getResourceType().equals(ResourceTypeEnum.VL)); + + } + + @Test + public void importNewResource_nameSpace_cp() throws Exception { + RestResponse importResponse = ImportRestUtils.importNewResourceByName("importResource4testCP", + UserRoleEnum.DESIGNER); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResponse.getResponse()); + assertTrue(resourceRespJavaObject.getResourceType().equals(ResourceTypeEnum.CP)); + } + + @Test + public void importNewResource_nameSpace_unknown() throws Exception { + RestResponse importResponse = ImportRestUtils.importNewResourceByName("importResource4test", + UserRoleEnum.DESIGNER); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResponse.getResponse()); + assertTrue(resourceRespJavaObject.getResourceType().equals(ResourceTypeEnum.VFC)); + + } + + @Test + public void importNewResource_MissingNameSpace() throws Exception { + RestResponse importResponse = ImportRestUtils.importNewResourceByName("importResource4testMissingNameSpace", + UserRoleEnum.DESIGNER); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 400, importResponse.getErrorCode().intValue()); + + } + + // TODO DE171337 + @Test(enabled = false) + public void importNewResource_existInCheckOut() throws Exception { + + // import new resource + + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + + // clean audit + DbUtils.cleanAllAudits(); + + // import new resource while resource already exist in CHECKOUT state + + importResponse = ImportRestUtils.importNewResourceByName("importResource4test", UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 200, importResponse.getErrorCode().intValue()); + + // validate response + Resource resourceFromImport = ResponseParser.convertResourceResponseToJavaObject(importResponse.getResponse()); + assertNotNull(resourceFromImport); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceRespJavaObject.getUniqueId()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + + // validate + ResourceValidationUtils.validateModelObjects(resourceFromImport, resourceFromGet); + + // validate audit + resourceDetails.setVersion(resourceDetails.getVersion()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails); + + auditAction = "ResourceImport"; + resourceVersion = "0.1"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setPrevVersion(resourceVersion); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setToscaNodeType(resourceFromGet.getToscaResourceName()); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + // TODO DE171337 + @Test(enabled = false) + public void importNewResource_existIn_CheckIn_state() throws Exception { + + // import new resource + + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + // checkIn resource + + resourceVersion = resourceDetails.getVersion(); + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + + assertNotNull("check response object is not null after import resource", checkInResponse); + assertEquals("Check response code after checkout resource", 200, checkInResponse.getErrorCode().intValue()); + + // clean audit + DbUtils.cleanAllAudits(); + + // import new resource while resource already exist in CHECKIN state + + importResponse = ImportRestUtils.importNewResourceByName("importResource4test", UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 200, importResponse.getErrorCode().intValue()); + + // validate response + Resource resourceFromImport = ResponseParser.convertResourceResponseToJavaObject(importResponse.getResponse()); + assertNotNull(resourceFromImport); + + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceRespJavaObject.getUniqueId()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + + // validate + ResourceValidationUtils.validateModelObjects(resourceFromImport, resourceFromGet); + + // validate audit + resourceDetails.setVersion(resourceDetails.getVersion()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails); + + resourceVersion = "0.2"; + auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setPrevVersion(resourceVersion); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setToscaNodeType(resourceFromGet.getToscaResourceName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + @Test + public void importNewResource_existIn_Ready4cert_state_performByTester() throws Exception { + // import new resource + + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceVersion = resourceDetails.getVersion(); + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + // add mandatory artifacts + // // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // resourceGetResponse); + resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // checkIn resource + resourceVersion = resourceDetails.getVersion(); + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + + assertNotNull("check response object is not null after import resource", checkInResponse); + assertEquals("Check response code after checkout resource", 200, checkInResponse.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(checkInResponse.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(checkInResponse.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // req4cert resource + RestResponse request4cert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertNotNull("check response object is not null after resource request for certification", request4cert); + assertEquals("Check response code after checkout resource", 200, request4cert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(request4cert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(request4cert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // clean audit + DbUtils.cleanAllAudits(); + + // import new resource while resource already exist in CHECKIN state + importResponse = ImportRestUtils.importNewResourceByName("importResource4test", UserRoleEnum.TESTER); + + // validate response + resourceVersion = resourceDetails.getVersion(); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + assertNotNull("check response object is not null after create resouce", importResponse); + assertNotNull("check error code exists in response after create resource", importResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), importResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), variables, + importResponse.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + + String auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setResourceName(""); + expectedResourceAuditJavaObject.setModifierUid(UserRoleEnum.TESTER.getUserId()); + expectedResourceAuditJavaObject.setModifierName(UserRoleEnum.TESTER.getUserName()); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + // TODO DE171337 + @Test(enabled = false) + public void importNewResource_existIn_Ready4cert_state_performByDesigner() throws Exception { + // import new resource + + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceVersion = resourceDetails.getVersion(); + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + // add mandatory artifacts + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // resourceGetResponse); + resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // checkIn resource + resourceVersion = resourceDetails.getVersion(); + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + assertNotNull("check response object is not null after import resource", checkInResponse); + assertEquals("Check response code after checkout resource", 200, checkInResponse.getErrorCode().intValue()); + + // req4cert resource + RestResponse request4cert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertNotNull("check response object is not null after resource request for certification", request4cert); + assertEquals("Check response code after checkout resource", 200, request4cert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(request4cert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(request4cert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // clean audit + DbUtils.cleanAllAudits(); + + // import new resource while resource already exist in other state + importResponse = ImportRestUtils.importNewResourceByName("importResource4test", UserRoleEnum.DESIGNER); + + // validate response + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_SENT_FOR_CERTIFICATION.name()); + assertNotNull("check response object is not null after create resouce", importResponse); + assertNotNull("check error code exists in response after create resource", importResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), importResponse.getErrorCode()); + String[] split = resourceFromGet.getLastUpdaterFullName().split(" "); + String firstName = split[0]; + String lastName = split[1]; + List variables = Arrays.asList(resourceFromGet.getName(), "resource", firstName, lastName, + resourceFromGet.getLastUpdaterUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_SENT_FOR_CERTIFICATION.name(), variables, + importResponse.getResponse()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + String auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setModifierUid(UserRoleEnum.DESIGNER.getUserId()); + expectedResourceAuditJavaObject.setModifierName(UserRoleEnum.DESIGNER.getUserName()); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.READY_FOR_CERTIFICATION).toString()); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setPrevVersion(resourceVersion); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setToscaNodeType(resourceFromGet.getToscaResourceName()); + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + // TODO DE171337 + @Test(enabled = false) + public void importNewResource_existIn_Ready4cert_state_performByAdmin() throws Exception { + + // import new resource + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceVersion = resourceDetails.getVersion(); + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + + // add mandatory artifacts + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // resourceGetResponse); + resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // checkIn resource + resourceVersion = resourceDetails.getVersion(); + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + assertNotNull("check response object is not null after import resource", checkInResponse); + assertEquals("Check response code after checkout resource", 200, checkInResponse.getErrorCode().intValue()); + + // req4cert resource + RestResponse request4cert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertNotNull("check response object is not null after resource request for certification", request4cert); + assertEquals("Check response code after checkout resource", 200, request4cert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(request4cert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(request4cert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // clean audit + DbUtils.cleanAllAudits(); + + // import new resource while resource already exist in other state + importResponse = ImportRestUtils.importNewResourceByName("importResource4test", UserRoleEnum.ADMIN); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 200, importResponse.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(importResponse.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(request4cert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + resourceVersion = resourceDetails.getVersion(); + // resourceVersion="0.2"; + + // validate response + Resource resourceFromImport = ResponseParser.convertResourceResponseToJavaObject(importResponse.getResponse()); + assertNotNull(resourceFromImport); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + + // validate get response + resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceRespJavaObject.getUniqueId()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + + // validate + ResourceValidationUtils.validateModelObjects(resourceFromImport, resourceFromGet); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setPrevVersion(resourceVersion); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setToscaNodeType(resourceFromGet.getToscaResourceName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + @Test + public void importNewResource_existIn_CerInProgress_state_performByTester() throws Exception { + + // import new resource + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceVersion = resourceDetails.getVersion(); + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + + // add mandatory artifacts + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // resourceGetResponse); + resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // checkIn resource + resourceVersion = resourceDetails.getVersion(); + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + assertNotNull("check response object is not null after import resource", checkInResponse); + assertEquals("Check response code after checkout resource", 200, checkInResponse.getErrorCode().intValue()); + + // req4cert resource + RestResponse request4cert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertNotNull("check response object is not null after resource request for certification", request4cert); + assertEquals("Check response code after checkout resource", 200, request4cert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(request4cert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(request4cert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // startCert + RestResponse startCert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertNotNull("check response object is not null after resource request start certification", startCert); + assertEquals("Check response code after checkout resource", 200, startCert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(startCert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(startCert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // clean audit + DbUtils.cleanAllAudits(); + + // import new resource while resource already exist in other state + importResponse = ImportRestUtils.importNewResourceByName("importResource4test", UserRoleEnum.TESTER); + + // validate response + resourceVersion = resourceDetails.getVersion(); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + assertNotNull("check response object is not null after create resouce", importResponse); + assertNotNull("check error code exists in response after create resource", importResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), importResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), variables, + importResponse.getResponse()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + String auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setResourceName(""); + expectedResourceAuditJavaObject.setModifierUid(UserRoleEnum.TESTER.getUserId()); + expectedResourceAuditJavaObject.setModifierName(UserRoleEnum.TESTER.getUserName()); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + // TODO DE171337 + @Test(enabled = false) + public void importNewResource_existIn_CerInProgress_state_performByDesigner() throws Exception { + + User sdncAdminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // import new resource + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceVersion = resourceDetails.getVersion(); + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + + // add mandatory artifacts + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // resourceGetResponse); + resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // checkIn resource + resourceVersion = resourceDetails.getVersion(); + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + assertNotNull("check response object is not null after import resource", checkInResponse); + assertEquals("Check response code after checkout resource", 200, checkInResponse.getErrorCode().intValue()); + + // req4cert resource + RestResponse request4cert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertNotNull("check response object is not null after resource request for certification", request4cert); + assertEquals("Check response code after checkout resource", 200, request4cert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(request4cert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(request4cert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // startCert + RestResponse startCert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertNotNull("check response object is not null after resource request start certification", startCert); + assertEquals("Check response code after checkout resource", 200, startCert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(startCert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(startCert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + resourceVersion = resourceDetails.getVersion(); + + // clean audit + DbUtils.cleanAllAudits(); + + // import new resource while resource already exist in other state + importResponse = ImportRestUtils.importNewResourceByName("importResource4test", UserRoleEnum.DESIGNER); + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE.name()); + assertNotNull("check response object is not null after create resouce", importResponse); + assertNotNull("check error code exists in response after create resource", importResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), importResponse.getErrorCode()); + List variables = Arrays.asList(resourceDetails.getName(), "resource", sdncAdminUser.getFirstName(), + sdncAdminUser.getLastName(), sdncAdminUser.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE.name(), + variables, importResponse.getResponse()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + String auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setModifierUid(UserRoleEnum.DESIGNER.getUserId()); + expectedResourceAuditJavaObject.setModifierName(UserRoleEnum.DESIGNER.getUserName()); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.CERTIFICATION_IN_PROGRESS).toString()); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setPrevVersion(resourceVersion); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setToscaNodeType(resourceFromGet.getToscaResourceName()); + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + // TODO DE171337 + @Test(enabled = false) + public void importNewResource_existIn_CerInProgress_state_performByAdmin() throws Exception { + + User sdncAdminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // import new resource + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceVersion = resourceDetails.getVersion(); + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + + // add mandatory artifacts + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // resourceGetResponse); + resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // checkIn resource + resourceVersion = resourceDetails.getVersion(); + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + assertNotNull("check response object is not null after import resource", checkInResponse); + assertEquals("Check response code after checkout resource", 200, checkInResponse.getErrorCode().intValue()); + + // req4cert resource + RestResponse request4cert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertNotNull("check response object is not null after resource request for certification", request4cert); + assertEquals("Check response code after checkout resource", 200, request4cert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(request4cert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(request4cert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + // startCert + RestResponse startCert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertNotNull("check response object is not null after resource request start certification", startCert); + assertEquals("Check response code after checkout resource", 200, startCert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(startCert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(startCert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + resourceVersion = resourceDetails.getVersion(); + + // clean audit + DbUtils.cleanAllAudits(); + + // import new resource while resource already exist in other state + importResponse = ImportRestUtils.importNewResourceByName("importResource4test", UserRoleEnum.ADMIN); + + // validate response + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE.name()); + assertNotNull("check response object is not null after create resouce", importResponse); + assertNotNull("check error code exists in response after create resource", importResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), importResponse.getErrorCode()); + List variables = Arrays.asList(resourceDetails.getName(), "resource", sdncAdminUser.getFirstName(), + sdncAdminUser.getLastName(), sdncAdminUser.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE.name(), + variables, importResponse.getResponse()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + String auditAction = "ResourceImport"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setModifierUid(UserRoleEnum.ADMIN.getUserId()); + expectedResourceAuditJavaObject.setModifierName(UserRoleEnum.ADMIN.getUserName()); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.CERTIFICATION_IN_PROGRESS).toString()); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setPrevVersion(resourceVersion); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setToscaNodeType(resourceFromGet.getToscaResourceName()); + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + // TODO DE171337 + // @Test(enabled = false) + // public void + // importNewResource_existIn_Certified_state_chnage_reqAndCap_byDesigner() + // throws Exception{ + // + // // Andrey - set default artifact details + // ArtifactDefinition artifactDefinition = + // artifactUtils.constructDefaultArtifactInfo(); + // + // // import new resource + // RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + // assertNotNull("check response object is not null after import resource", + // importResponse); + // assertNotNull("check error code exists in response after import + // resource", importResponse.getErrorCode()); + // assertEquals("Check response code after import resource", 201, + // importResponse.getErrorCode().intValue()); + // String resourceId = + // ResponseParser.getUniqueIdFromResponse(importResponse); + // resourceDetails = + // ResponseParser.parseToObject(importResponse.getResponse(), + // ResourceReqDetails.class); + // resourceVersion = resourceDetails.getVersion(); + // RestResponse resourceGetResponse = + // ResourceRestUtils.getResource(sdncModifierDetails, + // resourceDetails.getUniqueId()); + // assertEquals("Check response code after get resource", 200, + // resourceGetResponse.getErrorCode().intValue()); + // Resource resourceFromGet = + // ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + // assertNotNull(resourceFromGet); + // + // // add mandatory artifacts + // // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // resourceGetResponse); + // resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + // resourceDetails.getUniqueId()); + // assertEquals("Check response code after get resource", 200, + // resourceGetResponse.getErrorCode().intValue()); + // resourceFromGet = + // ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + // assertNotNull(resourceFromGet); + // resourceDetails = + // ResponseParser.parseToObject(importResponse.getResponse(), + // ResourceReqDetails.class); + // resourceDetails.setVersion(resourceFromGet.getVersion()); + // + // // add artifact + // artifactDefinition.setArtifactName(artifactName1); + // ArtifactRestUtils.addInformationalArtifactToResource(resourceDetails, + // sdncModifierDetails, resourceVersion , artifactDefinition); + // + // // add artifact + // artifactDefinition.setArtifactName(artifactName2); + // resourceUtils.add_artifact(resourceDetails, sdncModifierDetails, + // resourceVersion , artifactDefinition); + // + // // add interface + // artifactDefinition.setArtifactName(interfaceArtifactName); + // ResourceRestUtils.add_interface(resourceDetails, sdncModifierDetails, + // resourceVersion , artifactDefinition); + // + // //construct fields for validation + // resourceVersion="1.0"; + // + // ResourceRespJavaObject resourceRespJavaObject = + // Convertor.constructFieldsForRespValidation(resourceDetails, + // resourceVersion); + // ArrayList artifacts = new ArrayList(); + // + // artifacts.add(resourceId+":"+artifactName1); + // artifacts.add(resourceId+":"+artifactName2); + // resourceRespJavaObject.setArtifacts(artifacts); + // ArrayList interfaces = new ArrayList(); + // + // interfaces.add(interfaze); + // resourceRespJavaObject.setInterfaces(interfaces); + // + // // checkIn resource + // resourceVersion = resourceDetails.getVersion(); + // String checkinComment = "good checkin"; + // String checkinComentJson = "{\"userRemarks\": \""+checkinComment+"\"}"; + // RestResponse checkInResponse = + // LifecycleRestUtils.changeResourceState(resourceDetails, + // sdncModifierDetails, resourceVersion, LifeCycleStatesEnum.CHECKIN, + // checkinComentJson); + // assertNotNull("check response object is not null after import resource", + // checkInResponse); + // assertEquals("Check response code after checkout resource", 200, + // checkInResponse.getErrorCode().intValue()); + // + // // req4cert resource + // RestResponse request4cert = + // LifecycleRestUtils.changeResourceState(resourceDetails, + // sdncModifierDetails, resourceVersion, + // LifeCycleStatesEnum.CERTIFICATIONREQUEST); + // assertNotNull("check response object is not null after resource request + // for certification", request4cert); + // assertEquals("Check response code after checkout resource", 200, + // request4cert.getErrorCode().intValue()); + // resourceFromGet = + // ResponseParser.convertResourceResponseToJavaObject(request4cert.getResponse()); + // assertNotNull(resourceFromGet); + // resourceDetails = + // ResponseParser.parseToObject(request4cert.getResponse(), + // ResourceReqDetails.class); + // resourceDetails.setVersion(resourceFromGet.getVersion()); + // + // // startCert + // RestResponse startCert = + // LifecycleRestUtils.changeResourceState(resourceDetails, + // sdncModifierDetails, resourceVersion, + // LifeCycleStatesEnum.STARTCERTIFICATION); + // assertNotNull("check response object is not null after resource request + // start certification", startCert); + // assertEquals("Check response code after checkout resource", 200, + // startCert.getErrorCode().intValue()); + // resourceFromGet = + // ResponseParser.convertResourceResponseToJavaObject(startCert.getResponse()); + // assertNotNull(resourceFromGet); + // resourceDetails = ResponseParser.parseToObject(startCert.getResponse(), + // ResourceReqDetails.class); + // resourceDetails.setVersion(resourceFromGet.getVersion()); + // + // // certify + // RestResponse certify = + // LifecycleRestUtils.changeResourceState(resourceDetails, + // sdncModifierDetails, resourceVersion, LifeCycleStatesEnum.CERTIFY); + // assertNotNull("check response object is not null after resource request + // certify", certify); + // assertEquals("Check response code after certify resource", 200, + // certify.getErrorCode().intValue()); + // resourceFromGet = + // ResponseParser.convertResourceResponseToJavaObject(certify.getResponse()); + // assertNotNull(resourceFromGet); + // resourceDetails = ResponseParser.parseToObject(certify.getResponse(), + // ResourceReqDetails.class); + // resourceDetails.setVersion(resourceFromGet.getVersion()); + // + // // clean audit + // DbUtils.cleanAllAudits(); + // + // // change resource details + // + // // import new resource while resource already exist in other state + // importResponse = + // ImportRestUtils.importNewResourceByName("importResource4testUpdateWithoutReqCap", + // UserRoleEnum.ADMIN); + // assertNotNull("check response object is not null after import resource", + // importResponse); + // assertNotNull("check error code exists in response after import + // resource", importResponse.getErrorCode()); + // assertEquals("Check response code after import resource", 200, + // importResponse.getErrorCode().intValue()); + // resourceDetails = + // ResponseParser.parseToObject(importResponse.getResponse(), + // ResourceReqDetails.class); + // resourceVersion = resourceDetails.getVersion(); + // resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + // resourceDetails.getUniqueId()); + // assertEquals("Check response code after get resource", 200, + // resourceGetResponse.getErrorCode().intValue()); + // resourceFromGet = + // ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + // assertNotNull(resourceFromGet); + // + // // validate response + // Resource resourceFromImport = + // ResponseParser.convertResourceResponseToJavaObject(importResponse.getResponse()); + // assertNotNull(resourceFromImport); + // + // resourceDetails = + // ResponseParser.parseToObject(importResponse.getResponse(), + // ResourceReqDetails.class); + // resourceRespJavaObject = + // Convertor.constructFieldsForRespValidation(resourceDetails); + // resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // + // // validate get response + // resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + // resourceRespJavaObject.getUniqueId()); + // resourceFromGet = + // ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + // assertNotNull(resourceFromGet); + // + // // validate + // ResourceValidationUtils.validateModelObjects(resourceFromImport, + // resourceFromGet); + // + // // validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // Convertor.constructFieldsForAuditValidation(resourceDetails, + // resourceVersion); + // auditAction="ResourceImport"; + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setPrevVersion(resourceVersion); + // expectedResourceAuditJavaObject.setStatus("200"); + // expectedResourceAuditJavaObject.setDesc("OK"); + // expectedResourceAuditJavaObject.setToscaNodeType(resourceFromGet.getToscaResourceName()); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + // } + + @Test + public void importNewResource_uuidTest() throws Exception { + RestResponse importResponse = importNewResource(UserRoleEnum.ADMIN); + + assertNotNull("check response object is not null after import resource", importResponse); + assertNotNull("check error code exists in response after import resource", importResponse.getErrorCode()); + assertEquals("Check response code after import resource", 201, importResponse.getErrorCode().intValue()); + String oldUuid = ResponseParser.getValueFromJsonResponse(importResponse.getResponse(), "uuid"); + + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceVersion = resourceDetails.getVersion(); + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + Resource resourceFromGet = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + // add mandatory artifacts + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // resourceGetResponse); + resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceDetails.getUniqueId()); + assertEquals("Check response code after get resource", 200, resourceGetResponse.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(importResponse.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + "0.1", LifeCycleStatesEnum.CHECKIN); + assertNotNull("check response object is not null after import resource", checkInResponse); + assertEquals("Check response code after checkout resource", 200, checkInResponse.getErrorCode().intValue()); + + String newUuid = ResponseParser.getValueFromJsonResponse(checkInResponse.getResponse(), "uuid"); + assertTrue(ResourceValidationUtils.validateUuidAfterChangingStatus(oldUuid, newUuid)); + + // req4cert resource + RestResponse request4cert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertNotNull("check response object is not null after resource request for certification", request4cert); + assertEquals("Check response code after checkout resource", 200, request4cert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(request4cert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(request4cert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + String newUuid2 = ResponseParser.getValueFromJsonResponse(request4cert.getResponse(), "uuid"); + assertTrue(ResourceValidationUtils.validateUuidAfterChangingStatus(oldUuid, newUuid2)); + + // startCert + RestResponse startCert = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertNotNull("check response object is not null after resource request start certification", startCert); + assertEquals("Check response code after checkout resource", 200, startCert.getErrorCode().intValue()); + resourceFromGet = ResponseParser.convertResourceResponseToJavaObject(startCert.getResponse()); + assertNotNull(resourceFromGet); + resourceDetails = ResponseParser.parseToObject(startCert.getResponse(), ResourceReqDetails.class); + resourceDetails.setVersion(resourceFromGet.getVersion()); + + String newUuid3 = ResponseParser.getValueFromJsonResponse(startCert.getResponse(), "uuid"); + assertTrue(ResourceValidationUtils.validateUuidAfterChangingStatus(oldUuid, newUuid3)); + + RestResponse certify = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, "0.1", + LifeCycleStatesEnum.CERTIFY); + assertNotNull("check response object is not null after import resource", certify); + assertEquals("Check response code after checkout resource", 200, certify.getErrorCode().intValue()); + + String newUuid4 = ResponseParser.getValueFromJsonResponse(certify.getResponse(), "uuid"); + assertTrue(ResourceValidationUtils.validateUuidAfterChangingStatus(oldUuid, newUuid4)); + + RestResponse checkoutResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + "1.0", LifeCycleStatesEnum.CHECKOUT); + assertNotNull("check response object is not null after import resource", checkInResponse); + assertEquals("Check response code after checkout resource", 200, checkInResponse.getErrorCode().intValue()); + + String newUuid5 = ResponseParser.getValueFromJsonResponse(checkoutResponse.getResponse(), "uuid"); + assertFalse(ResourceValidationUtils.validateUuidAfterChangingStatus(oldUuid, newUuid5)); + } + + @Test + public void importNewResource_propertiesMapInternalUrlCredential() throws Exception { + String folderName = "validateProporties_typeMap_valueUrlCredential"; + RestResponse importResponse = ImportRestUtils.importNewResourceByName(folderName, UserRoleEnum.DESIGNER); + + Resource resource = ResponseParser.parseToObjectUsingMapper(importResponse.getResponse(), Resource.class); + + List properties = resource.getProperties(); + assertEquals("check properties size", 3, properties.size()); + + PropertyDefinition propertyDefinition = properties.stream().filter(p -> p.getName().equals("validation_test")) + .findFirst().get(); + String defaultValue = propertyDefinition.getDefaultValue(); + + Map mapValue = gson.fromJson(defaultValue, Map.class); + assertEquals("check Map value size", 2, mapValue.size()); + checkMapValues(mapValue, "key", 1, null); + checkMapValues(mapValue, "key", 2, null); + + System.err.println("import Resource " + "<" + folderName + ">" + "response: " + importResponse.getErrorCode()); + + } + + @Test + public void importNewResource_propertiesListInternalUrlCredential() throws Exception { + String folderName = "validateProporties_typeList_valueUrlCredential"; + RestResponse importResponse = ImportRestUtils.importNewResourceByName(folderName, UserRoleEnum.DESIGNER); + + Resource resource = ResponseParser.parseToObjectUsingMapper(importResponse.getResponse(), Resource.class); + + List properties = resource.getProperties(); + assertEquals("check properties size", 3, properties.size()); + + PropertyDefinition propertyDefinition = properties.stream().filter(p -> p.getName().equals("validation_test")) + .findFirst().get(); + String defaultValue = propertyDefinition.getDefaultValue(); + + List listValue = gson.fromJson(defaultValue, List.class); + assertEquals("check List value size", 2, listValue.size()); + checkListValues(listValue.get(0), 1, SPECIAL_CHARACTERS); + checkListValues(listValue.get(1), 2, SPECIAL_CHARACTERS); + + // Verify attributes + List attributes = resource.getAttributes(); + + assertEquals("check properties size", 2, attributes.size()); + + // Verify attribute from type map + PropertyDefinition attributeMapDefinition = attributes.stream() + .filter(p -> p.getName().equals("validation_test_map")).findFirst().get(); + String defaultMapValue = attributeMapDefinition.getDefaultValue(); + Map attributeMapValue = gson.fromJson(defaultMapValue, Map.class); + assertEquals("check Map value size", 2, attributeMapValue.size()); + checkMapValues(attributeMapValue, "key", 1, SPECIAL_CHARACTERS); + checkMapValues(attributeMapValue, "key", 2, SPECIAL_CHARACTERS); + + // Verify attribute from type list + PropertyDefinition attributeListDefinition = attributes.stream() + .filter(p -> p.getName().equals("validation_test_list")).findFirst().get(); + String defaultListValue = attributeListDefinition.getDefaultValue(); + + List attributeListValue = gson.fromJson(defaultListValue, List.class); + assertEquals("check List value size", 2, attributeListValue.size()); + checkListValues(attributeListValue.get(0), 1, SPECIAL_CHARACTERS); + checkListValues(attributeListValue.get(1), 2, SPECIAL_CHARACTERS); + + System.err.println("import Resource " + "<" + folderName + ">" + "response: " + importResponse.getErrorCode()); + + } + + private void checkListValues(Object object, int index, String suffix) { + + Map map = (Map) object; + assertEquals("check Map protocol value", "protocol" + index + (suffix == null ? "" : suffix), + map.get("protocol")); + assertEquals("check Map token value", "token" + index, map.get("token")); + } + + // @Test + public void importNewResource_validateProporties_typeTestDataType() throws Exception { + String folderName = "validateProporties_typeTestDataType"; + RestResponse importResponse = ImportRestUtils.importNewResourceByName(folderName, UserRoleEnum.DESIGNER); + + Resource resource = ResponseParser.parseToObjectUsingMapper(importResponse.getResponse(), Resource.class); + + } + + private void checkMapValues(Map mapValue, String key, int index, String suffix) { + + Map map1 = (Map) mapValue.get(key + index); + assertEquals("check Map protocol value", "protocol" + index + (suffix == null ? "" : suffix), + map1.get("protocol")); + assertEquals("check Map token value", "token" + index, map1.get("token")); + + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaCapabilitiesWithProperties.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaCapabilitiesWithProperties.java new file mode 100644 index 0000000000..3d7c81abae --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaCapabilitiesWithProperties.java @@ -0,0 +1,416 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.imports; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +/** + * US US730518 Story [BE] - TOSCA capabilities with properties - import "As a + * resource designer, I would like to add my VFC capabilities with properties." + * + * @author ns019t + * + */ +public class ImportToscaCapabilitiesWithProperties extends ComponentBaseTest { + @Rule + public static TestName name = new TestName(); + + Gson gson = new Gson(); + + /** + * public Constructor ImportToscaCapabilitiesWithProperties + */ + public ImportToscaCapabilitiesWithProperties() { + super(name, ImportToscaCapabilitiesWithProperties.class.getName()); + } + + /** + * String constants + */ + public static String propertyForTestName = "propertyfortest"; + public static String rootPath = System.getProperty("user.dir"); + public static String scalable = "tosca.capabilities.Scalable"; + public static String container = "tosca.capabilities.Container"; + public static String minInstances = "min_instances"; + public static String userDefinedNodeYaml = "mycompute.yml"; + + /** + * Capability Type - capability type on the graph should already have + * properties modeled on it. please verify. The import of the capability + * types should support adding those properties. when importing, validate + * name uniqueness between the capability's properties see capability + * tosca.capabilities.Container + * + * Acceptance Criteria: validate capability type properties (for example, + * compute have capability Container -> the properties of this capability + * should be in the Json response) + * + * @throws IOException + */ + @Test + public void validateCapabilityTypePropertiesSucceed() throws IOException { + User user = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse createResourceRes = ResourceRestUtils.getResourceByNameAndVersion(user.getUserId(), "Compute", + "1.0"); + BaseRestUtils.checkSuccess(createResourceRes); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(createResourceRes.getResponse()); + Map> capabilities = resource.getCapabilities(); + assertEquals(capabilities.size(), 6); + + CapabilityDefinition capability = capabilities.get(scalable).get(0); + List properties = capability.getProperties(); + assertEquals(properties.size(), 3); + assertTrue(!properties.stream().filter(p -> p.getName().equalsIgnoreCase(propertyForTestName)).findAny() + .isPresent()); + + ComponentInstanceProperty originalProperty = properties.stream() + .filter(p -> p.getName().equalsIgnoreCase(minInstances)).findAny().get(); + assertEquals(originalProperty.getType(), "integer"); + assertEquals(originalProperty.getDefaultValue(), "1"); + + capability = capabilities.get(container).get(0); + properties = capability.getProperties(); + assertEquals(properties.size(), 4); + } + + /** + * Capability Definition on VFC / CP / VL - properties can also be defined + * on the capability when the capability is declared. (property definition + * with default value) If the property name (case insensitive) already + * defined on the capability type, it overrides the capability from the + * capability type Import of VFC / CP /VL should support adding properties + * to the capability. when importing, validate name uniqueness between the + * capability's properties + * + * Acceptance Criteria: import node type with capability definition on it. + * use the attached "myCompute" + * + * @throws Exception + */ + @Test + public void importNodeTypeWithCapabilityWithPropertiesFromYmlSucceed() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + RestResponse createResource = importUserDefinedNodeType(userDefinedNodeYaml, sdncModifierDetails, + resourceDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + Map> capabilities = resource.getCapabilities(); + assertEquals(capabilities.size(), 6); + + CapabilityDefinition capability = capabilities.get(scalable).get(0); + List properties = capability.getProperties(); + assertEquals(properties.size(), 4); + + ComponentInstanceProperty newProperty = properties.stream() + .filter(p -> p.getName().equalsIgnoreCase(propertyForTestName)).findAny().get(); + assertEquals(newProperty.getType(), "string"); + assertEquals(newProperty.getDescription(), "test"); + assertEquals(newProperty.getDefaultValue(), "success"); + + ComponentInstanceProperty overriddenProperty = properties.stream() + .filter(p -> p.getName().equalsIgnoreCase(minInstances)).collect(Collectors.toList()).get(0); + assertEquals(overriddenProperty.getType(), "integer"); + assertEquals(overriddenProperty.getDefaultValue(), "3"); + + } + + /** + * importNodeTypeWithCapabilityWithPropertiesFromYmlFailed + * + * @throws Exception + */ + @Test + public void importNodeTypeWithCapabilityWithPropertiesFromYmlFailed() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + RestResponse createResource = importUserDefinedNodeType("mycompute_failed.yml", sdncModifierDetails, + resourceDetails); + BaseRestUtils.checkErrorMessageResponse(createResource, ActionStatus.PROPERTY_NAME_ALREADY_EXISTS); + } + + /** + * Capability Assignment (on node_template / resource instance) - should + * support assignment of the property (property value). On the resource + * instance level, value can be assigned to either properties that are + * defined on the capability type or on the capability definition. When + * importing a VF - the node_template can have capability's property value. + * It should be imported and saved on the graph Acceptance Criteria: import + * a VF that assign values to property of capability that was defined on the + * capability type + * + * @throws Exception + */ + @Test + public void importResourceWithCapabilityWithPropertiesOverridingCapTypePropertiesSucceed() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String payloadName = "vf_with_cap_prop_override_cap_type_prop.csar"; + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + Path path = Paths.get(rootPath + "/src/test/resources/CI/csars/vf_with_cap_prop_override_cap_type_prop.csar"); + byte[] data = Files.readAllBytes(path); + String payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + + List> propertyNamesValues = new ArrayList<>(); + propertyNamesValues.add(new ImmutablePair("num_cpus", "2")); + propertyNamesValues.add(new ImmutablePair("mem_size", "2000 MB")); + checkResource(createResource, 8, container, "DBMS", propertyNamesValues); + + ResourceReqDetails resourceDetails2 = ElementFactory.getDefaultResource(); + resourceDetails2.setCsarUUID("vf_with_cap_prop_override_cap_type_prop.csar"); + resourceDetails2.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + + checkResource(createResource, 8, container, "DBMS", propertyNamesValues); + } + + /** + * importResourceWithCapabilityWithPropertiesOverridingCapTypePropertiesFailed + * + * @throws Exception + */ + @Test + public void importResourceWithCapabilityWithPropertiesOverridingCapTypePropertiesFailed() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String payloadName = "vf_with_cap_prop_override_cap_type_prop_failed.csar"; + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + Path path = Paths + .get(rootPath + "/src/test/resources/CI/csars/vf_with_cap_prop_override_cap_type_prop_failed.csar"); + byte[] data = Files.readAllBytes(path); + String payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkErrorMessageResponse(createResource, ActionStatus.INVALID_PROPERTY); + + ResourceReqDetails resourceDetails2 = ElementFactory.getDefaultResource(); + resourceDetails2.setCsarUUID("vf_with_cap_prop_override_cap_type_prop_failed.csar"); + resourceDetails2.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + BaseRestUtils.checkErrorMessageResponse(createResource, ActionStatus.INVALID_PROPERTY); + + } + + /** + * Capability Assignment (on node_template / resource instance) - should + * support assignment of the property (property value). On the resource + * instance level, value can be assigned to either properties that are + * defined on the capability type or on the capability definition. When + * importing a VF - the node_template can have capability's property value. + * It should be imported and saved on the graph Acceptance Criteria: import + * a VF that assign values to property of capability that was defined on the + * capability definition (on the node type) + * + * @throws Exception + */ + @Test + public void importResourceWithCapabilityWithPropertiesOverridingNodeTypeCapPropertiesSucceed() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + RestResponse createResource = importUserDefinedNodeType(userDefinedNodeYaml, sdncModifierDetails, + resourceDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource userDefinedNodeType = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), + Resource.class); + + String payloadName = "vf_with_cap_prop_override_cap_type_prop1.csar"; + resourceDetails = ElementFactory.getDefaultImportResource(); + Path path = Paths.get(rootPath + "/src/test/resources/CI/csars/vf_with_cap_prop_override_cap_type_prop1.csar"); + byte[] data = Files.readAllBytes(path); + String payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + + List> propertyNamesValues = new ArrayList<>(); + propertyNamesValues.add(new ImmutablePair("num_cpus", "2")); + propertyNamesValues.add(new ImmutablePair("mem_size", "2000 MB")); + checkResource(createResource, 8, container, "DBMS", propertyNamesValues); + + List> propertyNamesValues1 = new ArrayList<>(); + propertyNamesValues1.add(new ImmutablePair(propertyForTestName, "success_again")); + propertyNamesValues1.add(new ImmutablePair(minInstances, "4")); + checkResource(createResource, 8, scalable, userDefinedNodeType.getName(), propertyNamesValues1); + + ResourceReqDetails resourceDetails2 = ElementFactory.getDefaultResource(); + resourceDetails2.setCsarUUID("vf_with_cap_prop_override_cap_type_prop1.csar"); + resourceDetails2.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + + checkResource(createResource, 8, container, "DBMS", propertyNamesValues); + checkResource(createResource, 8, scalable, userDefinedNodeType.getName(), propertyNamesValues1); + + } + + /** + * importResourceWithCapabilityWithPropertiesOverridingNodeTypeCapPropertiesFailed + * + * @throws Exception + */ + @Test + public void importResourceWithCapabilityWithPropertiesOverridingNodeTypeCapPropertiesFailed() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + RestResponse createResource = importUserDefinedNodeType(userDefinedNodeYaml, sdncModifierDetails, + resourceDetails); + BaseRestUtils.checkCreateResponse(createResource); + + String payloadName = "vf_with_cap_prop_override_cap_type_prop1_failed.csar"; + resourceDetails = ElementFactory.getDefaultImportResource(); + Path path = Paths + .get(rootPath + "/src/test/resources/CI/csars/vf_with_cap_prop_override_cap_type_prop1_failed.csar"); + byte[] data = Files.readAllBytes(path); + String payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkErrorResponse(createResource, ActionStatus.PROPERTY_NAME_ALREADY_EXISTS, + propertyForTestName); + + ResourceReqDetails resourceDetails2 = ElementFactory.getDefaultResource(); + resourceDetails2.setCsarUUID("vf_with_cap_prop_override_cap_type_prop1_failed.csar"); + resourceDetails2.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + BaseRestUtils.checkErrorResponse(createResource, ActionStatus.PROPERTY_NAME_ALREADY_EXISTS, + propertyForTestName); + } + + private RestResponse importUserDefinedNodeType(String payloadName, User sdncModifierDetails, + ImportReqDetails resourceDetails) throws Exception { + + Path path = Paths.get(rootPath + "/src/test/resources/CI/csars/" + payloadName); + byte[] data = Files.readAllBytes(path); + String payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VFC.name()); + return ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + } + + // TODO Tal: Since Cashing change partial resource returned that causes null + // pointer exception + // commented out till fixing + private void checkResource(RestResponse createResource, int capNum, String capType, String riName, + List> propertyNamesValues) { + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + Map> capabilities = resource.getCapabilities(); + // TODO Tal: Since Cashing change partial resource returned that causes + // null pointer exception + /* assertEquals(capabilities.size(), capNum); */ + /* + * List capabilitesContainer = + * capabilities.get(capType); + */ + + ComponentInstance resourceRI = resource.getComponentInstances().stream() + .filter(ri -> ri.getComponentName().equals(riName)).collect(Collectors.toList()).get(0); + // TODO Tal: Since Cashing change partial resource returned that causes + // null pointer exception + /* + * CapabilityDefinition capabilityFromContainer = + * capabilitesContainer.stream() + * .filter(cap->cap.getOwnerId().equals(resourceRI.getUniqueId())). + * collect(Collectors.toList()).get(0); + */ + + CapabilityDefinition capabilityFromRI = resourceRI.getCapabilities().get(capType).get(0); + for (ImmutablePair propValuePair : propertyNamesValues) { + // TODO Tal: Since Cashing change partial resource returned that + // causes null pointer exception + /* + * Map propertiesFromContainer = + * capabilityFromContainer.getProperties() + * .stream().filter(p->p.getName().equalsIgnoreCase(propValuePair. + * getLeft())) .collect(Collectors.toMap(p->p.getName(), p->p)); + */ + + List propertiesFromRI = capabilityFromRI.getProperties().stream() + .filter(p -> p.getName().equalsIgnoreCase(propValuePair.getLeft())).collect(Collectors.toList()); + // TODO Tal: Since Cashing change partial resource returned that + // causes null pointer exception + /* + * for(ComponentInstanceProperty riProp : propertiesFromRI){ + * assertTrue(propertiesFromContainer.containsKey(riProp.getName())) + * ; ComponentInstanceProperty containerProp = + * propertiesFromContainer.get(riProp.getName()); + * assertEquals(riProp.getValue(), containerProp.getValue()); + * if(riProp.getName().equals(propValuePair.getLeft())) + * assertEquals(riProp.getValue(), propValuePair.getRight()); + * + * } + */ + } + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaResourceTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaResourceTest.java new file mode 100644 index 0000000000..8ce8dc5433 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportToscaResourceTest.java @@ -0,0 +1,2896 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.imports; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_CREATED; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_INVALID_CONTENT; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.http.client.ClientProtocolException; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.RelationshipImpl; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Decoder; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.general.ImportUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.api.ToscaNodeTypeInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import aj.org.objectweb.asm.Attribute; + +/** + * + * @author Andrey + Pavel + Shay + * + */ + +public class ImportToscaResourceTest extends ComponentBaseTest { + private static Logger logger = LoggerFactory.getLogger(ImportToscaResourceTest.class.getName()); + protected Utils utils = new Utils(); + + public ImportToscaResourceTest() { + super(name, ImportToscaResourceTest.class.getName()); + } + + public ImportReqDetails importReqDetails; + protected static User sdncUserDetails; + protected static User testerUser; + protected String testResourcesPath; + protected ResourceReqDetails resourceDetails; + private HashSet capabilitySources; + private int actualNumOfReqOrCap; + + @Rule + public static TestName name = new TestName(); + + @BeforeMethod + public void before() throws Exception { + importReqDetails = ElementFactory.getDefaultImportResource(); + sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + testerUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + resourceDetails = ElementFactory.getDefaultResource(); + String sourceDir = config.getResourceConfigDir(); + final String workDir = "importToscaResourceByCreateUrl"; + testResourcesPath = sourceDir + File.separator + workDir; + capabilitySources = new HashSet(); + actualNumOfReqOrCap = 0; + } + + @DataProvider + private static final Object[][] getYmlWithInValidListProperties() throws IOException, Exception { + return new Object[][] { { "ListPropertyFalure02.yml", "[false,\"truee\"]", "boolean" }, + { "ListPropertyFalure03.yml", "[false,3]", "boolean" }, + { "ListPropertyFalure04.yml", "[false,3.56]", "boolean" }, + { "ListPropertyFalure05.yml", "[10000,3.56]", "integer" }, + { "ListPropertyFalure06.yml", "[10000,\"aaaa\"]", "integer" }, + { "ListPropertyFalure07.yml", "[10000,true]", "integer" }, + { "ListPropertyFalure08.yml", "[10.5,true]", "float" }, + { "ListPropertyFalure09.yml", "[10.5,\"asdc\"]", "float" }, // type + // float + { "ListPropertyFalure11.yml", "[10.5,\"500.0@\"]", "float" }, // property + // list + // float + // type + // contain + // @ + // in + // default + // value + { "ListPropertyFalure12.yml", "[10000,\"3#\"]", "integer" }, // property + // list + // integer + // type + // contain + // # + // in + // default + // value + { "ListPropertyFalure13.yml", "[false,\"true%\"]", "boolean" }, // property + // list + // boolean + // type + // contain + // % + // in + // default + // value + { "ListPropertyFalure14.yml", "[false,\"falsee\",true]", "boolean" }, + { "ListPropertyFalure15.yml", "[10.5,\"10.6x\",20.5,30.5]", "float" } // float + // with + // value + // 10.6x + // instead + // 10.6f + + }; + } + + @DataProvider + private static final Object[][] getYmlWithInValidMapProperties() throws IOException, Exception { + return new Object[][] { { "MapPropertyFalure02.yml", "[false,\"truee\"]", "boolean" }, + { "MapPropertyFalure03.yml", "[false,3]", "boolean" }, + { "MapPropertyFalure04.yml", "[false,3.56]", "boolean" }, + { "MapPropertyFalure05.yml", "[10000,3.56]", "integer" }, + { "MapPropertyFalure06.yml", "[10000,\"aaaa\"]", "integer" }, + { "MapPropertyFalure07.yml", "[10000,true]", "integer" }, + { "MapPropertyFalure08.yml", "[10.5,true]", "float" }, + { "MapPropertyFalure09.yml", "[10.5,\"asdc\"]", "float" }, // type + // float + { "MapPropertyFalure11.yml", "[10.5,\"500.0@\"]", "float" }, // property + // list + // float + // type + // contain + // @ + // in + // default + // value + { "MapPropertyFalure12.yml", "[10000,\"3#\"]", "integer" }, // property + // list + // integer + // type + // contain + // # + // in + // default + // value + { "MapPropertyFalure13.yml", "[false,\"true%\"]", "boolean" }, // property + // list + // boolean + // type + // contain + // % + // in + // default + // value + { "MapPropertyFalure14.yml", "[false,\"falsee\",true]", "boolean" }, + { "MapPropertyFalure15.yml", "[10.5,\"10.6x\",20.5,30.5]", "float" } // float + // with + // value + // 10.6x + // instead + // 10.6f + + }; + } + + @DataProvider + private static final Object[][] getYmlWithInValidOccurrences() throws IOException, Exception { + return new Object[][] { { "occurencyFalure01.yml" }, // requirements [2 + // , 0] + { "occurencyFalure02.yml" }, // requirements [-1, 2] + { "occurencyFalure03.yml" }, // requirements [1 ,-2] + { "occurencyFalure05.yml" }, // requirements MAX occurrences not + // exist [ 1 , ] + { "occurencyFalure06.yml" }, // requirements [ 0 , 0 ] + { "occurencyFalure08.yml" }, // requirements [ 1.0 , 2.0 ] + { "occurencyFalure09.yml" }, // requirements [ "1" , "2" ] + { "occurencyFalure10.yml" }, // requirements [ ] + { "occurencyFalure11.yml" }, // requirements [ UNBOUNDED , + // UNBOUNDED ] + { "occurencyFalure31.yml" }, // capability [ 2, 1] + { "occurencyFalure32.yml" }, // capability [-1, 2] + { "occurencyFalure33.yml" }, // capability [1, -2] + { "occurencyFalure35.yml" }, // capability MAX occurrences not + // exist [ 1 , ] + { "occurencyFalure36.yml" }, // capability [ 0 , 0 ] + { "occurencyFalure38.yml" }, // capability [ 1.0 , 2.0 ] + { "occurencyFalure39.yml" }, // capability [ "1" , "2" ] + { "occurencyFalure40.yml" }, // capability [ ] + { "occurencyFalure41.yml" } // capability [ UNBOUNDED , + // UNBOUNDED ] + }; + } + + @DataProvider + private static final Object[][] getInvalidYmlWithOccurrences() throws IOException, Exception { + return new Object[][] { { "occurencyFalure04.yml" }, // requirements MIN + // occurrences + // not exist [ , + // 1] + { "occurencyFalure07.yml" }, // requirements [ @ , 1 ] + { "occurencyFalure34.yml" }, // capability MIN occurrences not + // exist [ , 1] + { "occurencyFalure37.yml" } // capability [ 0 , # ] + + }; + } + + // US656928 + protected final String importMapPropertySuccess = "importMapPropertySuccessFlow.yml"; + protected final String importAttributeSuccess = "importAttributeSuccessFlow.yml"; + protected final String importSuccessFile = "myCompute.yml"; + protected final String derivedFromMyCompute = "derivedFromMyCompute.yml"; + protected final String importSuccessVFFile = "myComputeVF.yml"; + protected final String importNoDerivedFromFile = "myComputeDerivedFromNotExists.yml"; + protected final String importInvalidDefinitionVersionFile = "myComputeIncorrectDefenitionVersionValue.yml"; + protected final String importIncorrectNameSpaceFormatFile = "myComputeIncorrectNameSpaceFormat.yml"; + protected final String importNoDefenitionVersionFile = "myComputeNoDefenitionVersion.yml"; + protected final String importNodeTypesTwiceFile = "myComputeWithNodeTypesTwice.yml"; + protected final String importTopologyTemplateFile = "myComputeWithTopologyTemplate.yml"; + protected final String importNoContentFile = "noContent.yml"; + protected final String importWithOccurrences = "myComputeOccurencySuccess.yml"; + protected final String importListPropertyBadDefault = "importListPropertyBadDefault.yml"; + protected final String importListPropertyGoodDefault = "importListPropertyGoodDefault.yml"; + protected final String importListPropertySuccess = "importListPropertySuccessFlow.yml"; + // US631462 + protected final String importDuplicateRequirements = "importDuplicateRequirements.yml"; + protected final String importDuplicateCapability = "importDuplicateCapability.yml"; + protected final String importCapabilityNameExistsOnParent = "importCapabilityNameExistsOnParent.yml"; + protected final String importRequirementNameExistsOnParent = "importRequirementNameExistsOnParent.yml"; + protected final String importToscaResourceReqCapDerivedFromParent = "derivedFromWebAppDerivedReqCap.yml"; + protected final String missingCapInReqDef = "missingCapInReqDefinition.yml"; + protected final String missingCapInCapDef = "missingCapInCapDefinition.yml"; + + // US558432 - Support for Capability/Requirement "occurences" Import + @Test(dataProvider = "getYmlWithInValidOccurrences") + public void importToscaResourceWithOccurrencesFailuresFlow01(String ymlFileWithInvalidCapReqOccurrences) + throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + ymlFileWithInvalidCapReqOccurrences); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_OCCURRENCES.name(), new ArrayList(), + importResourceResponse.getResponse()); + } + + @Test(dataProvider = "getInvalidYmlWithOccurrences") + public void importToscaResourceWithOccurrencesFailuresFlow02(String ymlFileWithInvalidCapReqOccurrences) + throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + ymlFileWithInvalidCapReqOccurrences); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_YAML_FILE.name(), new ArrayList(), + importResourceResponse.getResponse()); + } + + @Test + public void importToscaResource() throws Exception { + + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importSuccessFile); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + AssertJUnit.assertTrue("response code is not 201, returned :" + importResourceResponse.getErrorCode(), + importResourceResponse.getErrorCode() == 201); + ToscaNodeTypeInfo parseToscaNodeYaml = utils + .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + Resource resourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + AssertJUnit.assertTrue("validate toscaResourceName field", + resourceJavaObject.getToscaResourceName().equals(parseToscaNodeYaml.getNodeName())); + AssertJUnit.assertTrue("validate resourceType field", + resourceJavaObject.getResourceType().equals(ResourceTypeEnum.VFC)); + // find derived from resource details + // Validate resource details after import-create resource including + // capabilities, interfaces from derived_from resource + + // Validate audit message + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType(parseToscaNodeYaml.getNodeName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceWithOccurrencesSuccessFlow() throws Exception { + + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importWithOccurrences); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + AssertJUnit.assertTrue("response code is not 201, returned :" + importResourceResponse.getErrorCode(), + importResourceResponse.getErrorCode() == 201); + ToscaNodeTypeInfo parseToscaNodeYaml = utils + .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + Resource resourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + AssertJUnit.assertTrue("validate toscaResourceName field", + resourceJavaObject.getToscaResourceName().equals(parseToscaNodeYaml.getNodeName())); + AssertJUnit.assertTrue("validate resourceType field", + resourceJavaObject.getResourceType().equals(ResourceTypeEnum.VFC)); + String requirementsType = "tosca.capabilities.Attachment"; + String capabilitType = "tosca.capabilities.Endpoint.Admin"; + // Verify Occurrences of requirements and capabilities in resource + verifyRequirementsOccurrences(resourceJavaObject, requirementsType); + verifyCapabilitiesOccurrences(resourceJavaObject, capabilitType); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType(parseToscaNodeYaml.getNodeName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + // ------------------------------Success--------------------------------- + + @Test(enabled = false) + public void importToscaResourceVFResType() throws Exception { + + String resourceType = ResourceTypeEnum.VF.toString(); + + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importSuccessVFFile); + // importReqDetails.setResourceType(resourceType); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + assertTrue("response code is not 201, returned :" + importResourceResponse.getErrorCode(), + importResourceResponse.getErrorCode() == 201); + ToscaNodeTypeInfo parseToscaNodeYaml = utils + .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + Resource resourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + assertTrue("validate toscaResourceName field", + resourceJavaObject.getToscaResourceName().equals(parseToscaNodeYaml.getNodeName())); + assertTrue( + "validate resourceType field, expected - " + resourceType + ", actual - " + + resourceJavaObject.getResourceType(), + resourceJavaObject.getResourceType().toString().equals(resourceType)); + + // Validate audit message + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType(parseToscaNodeYaml.getNodeName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + // ------------------------------Failure--------------------------------- + + @Test + public void importToscaResourceDerivedFromNotExist() throws Exception { + + String fileName = importNoDerivedFromFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + // List derivedFrom = new ArrayList() ; + // derivedFrom.add("hh"); + // importReqDetails.setDerivedFrom(derivedFrom); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.PARENT_RESOURCE_NOT_FOUND.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.PARENT_RESOURCE_NOT_FOUND.name(), variables, + importResourceResponse.getResponse()); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); + ToscaNodeTypeInfo parseToscaNodeYaml = utils + .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceIncorrectDefinitionVersion() throws Exception { + + String fileName = importInvalidDefinitionVersionFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_TOSCA_TEMPLATE.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_TOSCA_TEMPLATE.name(), variables, + importResourceResponse.getResponse()); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceIncorrectSpaceNameFormat() throws Exception { + + String fileName = importIncorrectNameSpaceFormatFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_RESOURCE_NAMESPACE.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_RESOURCE_NAMESPACE.name(), variables, + importResourceResponse.getResponse()); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceNoDefinitionVersion() throws Exception { + + String fileName = importNoDefenitionVersionFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_TOSCA_TEMPLATE.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_TOSCA_TEMPLATE.name(), variables, + importResourceResponse.getResponse()); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceNoContent() throws Exception { + + String fileName = importNoContentFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_RESOURCE_PAYLOAD.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_RESOURCE_PAYLOAD.name(), variables, + importResourceResponse.getResponse()); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceWithTopologyTemplate() throws Exception { + + String fileName = importTopologyTemplateFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.NOT_RESOURCE_TOSCA_TEMPLATE.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_RESOURCE_TOSCA_TEMPLATE.name(), variables, + importResourceResponse.getResponse()); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceWithNodeTypesTwice() throws Exception { + + String fileName = importNodeTypesTwiceFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.NOT_SINGLE_RESOURCE.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_SINGLE_RESOURCE.name(), variables, + importResourceResponse.getResponse()); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + // failed case - uniqueness of toscaResourceName - RESOURCE_ALREADY_EXISTS + @Test + public void importToscaResourceTwice() throws Exception { + String fileName = importSuccessFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + assertTrue("response code is not 201, returned :" + importResourceResponse.getErrorCode(), + importResourceResponse.getErrorCode() == 201); + Resource resourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + RestResponse checkInresponse = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CHECKIN); + assertTrue("checkIn resource request returned status:" + checkInresponse.getErrorCode(), + checkInresponse.getErrorCode() == 200); + + // Validate audit message + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + ToscaNodeTypeInfo parseToscaNodeYaml = utils + .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + expectedResourceAuditJavaObject.setToscaNodeType(parseToscaNodeYaml.getNodeName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + + // import the same tosca resource with different resourceName + DbUtils.cleanAllAudits(); + + importReqDetails.setName("kuku"); + List tags = new ArrayList(); + tags.add(importReqDetails.getName()); + importReqDetails.setTags(tags); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESOURCE_ALREADY_EXISTS.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_ALREADY_EXISTS.name(), variables, + importResourceResponse.getResponse()); + + expectedResourceAuditJavaObject = ElementFactory.getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType(importReqDetails.getToscaResourceName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + + } + + @Test + public void importToscaResourceWithTheSameNameAsCreatedResourceBefore() throws Exception { + + // create resource + String fileName = importSuccessFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + + resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName(importReqDetails.getName()); + + RestResponse response = ResourceRestUtils.createResource(resourceDetails, sdncUserDetails); + int status = response.getErrorCode(); + assertEquals("create request returned status:" + status, 201, status); + assertNotNull("resource uniqueId is null:", resourceDetails.getUniqueId()); + Resource resourceJavaObject = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + // assertNull("validate toscaResourceName field", + // resourceJavaObject.getToscaResourceName()); + + // import the same tosca resource + DbUtils.cleanAllAudits(); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESOURCE_ALREADY_EXISTS.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_ALREADY_EXISTS.name(), variables, + importResourceResponse.getResponse()); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + + } + + @Test + public void importToscaResourceInvalidChecksum() throws Exception { + String fileName = importSuccessFile; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.Content_MD5.getValue(), "invalidMd5Sum"); + + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + headersMap); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + assertNotNull("check response object is not null after import tosca resource", importResourceResponse); + assertNotNull("check error code exists in response after import tosca resource", + importResourceResponse.getErrorCode()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_RESOURCE_CHECKSUM.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_RESOURCE_CHECKSUM.name(), variables, + importResourceResponse.getResponse()); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceInvalidResType() throws Exception { + + String resourceType = "invalidResourceType"; + + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importSuccessFile); + importReqDetails.setResourceType(resourceType); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_CONTENT.name()); + assertNotNull("check response object is not null after import resouce", importResourceResponse); + assertNotNull("check error code exists in response after import resource", + importResourceResponse.getErrorCode()); + assertEquals("Check response code after import resource", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + + List variables = new ArrayList<>(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), variables, + importResourceResponse.getResponse()); + + // Validate audit message + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void derivedTemplateImportedSecondResourceAsFirstImportedNodeType() throws Exception { + + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importSuccessFile); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + assertTrue("response code is not 201, returned :" + importResourceResponse.getErrorCode(), + importResourceResponse.getErrorCode() == 201); + ToscaNodeTypeInfo parseToscaNodeYaml = utils + .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + Resource resourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + assertTrue("validate toscaResourceName field", + resourceJavaObject.getToscaResourceName().equals(parseToscaNodeYaml.getNodeName())); + assertTrue( + "validate resourceType field, expected - " + importReqDetails.getResourceType() + ", actual - " + + resourceJavaObject.getResourceType(), + resourceJavaObject.getResourceType().toString().equals(importReqDetails.getResourceType())); + + // Validate audit message + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType(parseToscaNodeYaml.getNodeName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + + RestResponse certifyResource = LifecycleRestUtils.certifyResource(importReqDetails); + assertTrue("certify resource request returned status:" + certifyResource.getErrorCode(), + certifyResource.getErrorCode() == 200); + + // import second resource template derived from first resource + DbUtils.cleanAllAudits(); + importReqDetails.setName("kuku"); + List tags = new ArrayList(); + tags.add(importReqDetails.getName()); + importReqDetails.setTags(tags); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + derivedFromMyCompute); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + assertTrue("response code is not 201, returned :" + importResourceResponse.getErrorCode(), + importResourceResponse.getErrorCode() == 201); + parseToscaNodeYaml = utils.parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + Resource resourceJavaObject2 = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + assertTrue("validate toscaResourceName field", + resourceJavaObject2.getToscaResourceName().equals(parseToscaNodeYaml.getNodeName())); + assertTrue( + "validate resourceType field, expected - " + importReqDetails.getResourceType() + ", actual - " + + resourceJavaObject2.getResourceType(), + resourceJavaObject2.getResourceType().toString().equals(importReqDetails.getResourceType())); + + // Validate audit message + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject2 = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject2.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject2.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject2.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject2.setToscaNodeType(parseToscaNodeYaml.getNodeName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject2, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + + } + + @Test + public void importToscaResourceListPropertyGoodDefault() throws Exception { + + String fileName = importListPropertyGoodDefault; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + assertTrue("response code is not 201, returned :" + importResourceResponse.getErrorCode(), + importResourceResponse.getErrorCode() == 201); + + Resource resourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + assertTrue("Properties size : " + resourceJavaObject.getProperties().size(), + resourceJavaObject.getProperties().size() == 1); + assertTrue("Property type : " + resourceJavaObject.getProperties().get(0).getType(), + resourceJavaObject.getProperties().get(0).getType().equals(ToscaPropertyType.LIST.getType())); + assertTrue( + "actual Default values : " + resourceJavaObject.getProperties().get(0).getDefaultValue() + + " , expected : " + "[false, true]", + resourceJavaObject.getProperties().get(0).getDefaultValue().equals("[\"false\",\"true\"]")); + + } + + @Test + public void importToscaResourceListPropertyBadDefault() throws Exception { + + String fileName = importListPropertyBadDefault; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE.name()); + assertEquals("Check response code after tosca resource import", errorInfo.getCode(), + importResourceResponse.getErrorCode()); + ArrayList variables = new ArrayList<>(); + variables.add("my_prop"); + variables.add("list"); + variables.add("boolean"); + variables.add("[12,true]"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE.name(), variables, + importResourceResponse.getResponse()); + + } + + // Benny US580744 - Add support for TOSCA "list" type - import + + @Test + public void importToscaResourceListPropertySuccessFlow() throws Exception { + String fileName = importListPropertySuccess; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + ResourceRestUtils.checkCreateResponse(importResourceResponse); + Resource resourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + ToscaNodeTypeInfo parseToscaNodeYaml = utils + .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + // Verify Properties List in resource + verifyResourcePropertiesList(resourceJavaObject); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType(parseToscaNodeYaml.getNodeName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + // DE198534 + @Test(dataProvider = "getYmlWithInValidListProperties") // invalid default + // values + public void importToscaResourceListPropertyFailureFlows(String ymlFileWithInvalidPropertyDefualtValues, + String defualtValues, String enterySchemaType) throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + ymlFileWithInvalidPropertyDefualtValues); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add("my_property"); + variables.add("list"); + variables.add(enterySchemaType); + variables.add(defualtValues); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE.name(), variables, + importResourceResponse.getResponse()); + } + + // BUG DE198650 + @Test + public void importToscaResourceListPropertyNonSupportEntrySchemaType() throws Exception { + String ymlFile = "ListPropertyFalure01.yml"; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + ymlFile); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add("booolean"); // property entry_schema data type + variables.add("my_boolean"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROPERTY_INNER_TYPE.name(), variables, + importResourceResponse.getResponse()); + } + + // BUG DE198676 + @Test // (enabled=false) + public void importToscaResourceListPropertyNonSupportedPropertyType() throws Exception { // Not + // "list" + // type + String ymlFile = "ListPropertyFalure16.yml"; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + ymlFile); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add("koko"); // property data type (koko instead list) + variables.add("my_boolean"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROPERTY_TYPE.name(), variables, + importResourceResponse.getResponse()); + } + + /// US656928 - [BE] - Add support for TOSCA "map" type - Phase 1 import + @Test + public void importToscaResourceMapPropertySuccessFlow() throws Exception { + String fileName = importMapPropertySuccess; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + ResourceRestUtils.checkCreateResponse(importResourceResponse); + Resource resourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + ToscaNodeTypeInfo parseToscaNodeYaml = utils + .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + // Verify Properties MAP in resource + verifyResourcePropertiesMap(resourceJavaObject); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType(parseToscaNodeYaml.getNodeName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test(dataProvider = "getYmlWithInValidMapProperties") // invalid default + // values + public void importToscaResourceMapPropertyFailureFlows(String ymlFileWithInvalidPropertyDefualtValues, + String defualtValues, String enterySchemaType) throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + ymlFileWithInvalidPropertyDefualtValues); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add("my_property"); + variables.add("map"); + variables.add(enterySchemaType); + variables.add(defualtValues); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE.name(), variables, + importResourceResponse.getResponse()); + } + + @Test + public void importToscaResourceMaptPropertyNonSupportedPropertyType() throws Exception { // Not + // "Map" + // type + String ymlFile = "MapPropertyFalure16.yml"; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + ymlFile); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add("koko"); // property data type (koko instead list) + variables.add("my_boolean"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROPERTY_TYPE.name(), variables, + importResourceResponse.getResponse()); + } + + @Test + public void importToscaResourceMissingCapabilityInReqDefinition() throws Exception { + + String fileName = missingCapInReqDef; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_CAPABILITY_TYPE.name()); + String missingCapName = "org.openecomp.capabilities.networkInterfaceNotFound"; + BaseRestUtils.checkErrorResponse(importResourceResponse, ActionStatus.MISSING_CAPABILITY_TYPE, missingCapName); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, Arrays.asList(missingCapName)); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType("org.openecomp.resource.vSCP-03-16"); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceMissingCapabilityInCapDefinition() throws Exception { + + String fileName = missingCapInCapDef; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + logger.debug("import tosca resource response: {}", importResourceResponse.getResponseMessage()); + + // Validate audit message + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_CAPABILITY_TYPE.name()); + String missingCapName = "org.openecomp.capabilities.networkInterfaceNotFound"; + BaseRestUtils.checkErrorResponse(importResourceResponse, ActionStatus.MISSING_CAPABILITY_TYPE, missingCapName); + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, Arrays.asList(missingCapName)); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType("org.openecomp.resource.vSCP-03-16"); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceDuplicateRequirements() throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importDuplicateRequirements); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add("requirement"); + variables.add("local_storage"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME.name(), variables, + importResourceResponse.getResponse()); + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceDuplicateCapabilities() throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importDuplicateCapability); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add("capability"); + variables.add("scalable"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME.name(), variables, + importResourceResponse.getResponse()); + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.IMPORT_DUPLICATE_REQ_CAP_NAME.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceRequirementNameExistsOnParent() throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importRequirementNameExistsOnParent); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add("requirement"); + variables.add("local_storage"); + variables.add("Compute"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED.name(), + variables, importResourceResponse.getResponse()); + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceCapabilityNameExistsOnParent() throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importCapabilityNameExistsOnParent); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertTrue(importResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add("capability"); + variables.add("binding"); + variables.add("Compute"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED.name(), + variables, importResourceResponse.getResponse()); + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgFailure(errorInfo, variables); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + @Test + public void importToscaResourceReqCapDerivedFromParent() throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + importToscaResourceReqCapDerivedFromParent); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + BaseRestUtils.checkCreateResponse(importResourceResponse); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType("org.openecomp.resource.MyWebApp"); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + /************************ Shay ************************/ + + @Test + public void caseRequirementInsensitiveTest() throws Exception { + String fileName = "CaseInsensitiveReqTest_1.yml"; + int expectedNumOfRequirements = 2; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + importReqDetails.setRequirements(testResourcesPath, fileName, sdncUserDetails, null); + Map requirements = importReqDetails.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String fileName2 = "CaseInsensitiveReqTest_2.yml"; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName2); + importReqDetails.setName("secondImportedResource"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + importReqDetails.setRequirements(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, null); + requirements = importReqDetails.getRequirements(); + requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + + checkImportedAssetAssociated(importReqDetails); + + } + + private void checkImportedAssetAssociated(ImportReqDetails importDetails) throws IOException, Exception { + RestResponse importResourceResponse; + ImportReqDetails importReqDetails2 = ElementFactory.getDefaultImportResource(); + importReqDetails2 = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails2, testResourcesPath, + "BindingAsset.yml"); + importReqDetails2.setName("bindingAsset"); + importReqDetails2.setTags(Arrays.asList(importReqDetails2.getName())); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails2, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + ResourceReqDetails vf = ElementFactory.getDefaultResourceByType("VF100", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncUserDetails.getUserId(), + ResourceTypeEnum.VF.toString()); + RestResponse createResourceResponse = ResourceRestUtils.createResource(vf, sdncUserDetails); + ResourceRestUtils.checkCreateResponse(createResourceResponse); + + LifecycleRestUtils.changeResourceState(importDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + LifecycleRestUtils.changeResourceState(importReqDetails2, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + + RestResponse response = ResourceRestUtils.createResourceInstance(importDetails, sdncUserDetails, + vf.getUniqueId()); + ResourceRestUtils.checkCreateResponse(response); + ComponentInstance riCap = ResponseParser.parseToObject(response.getResponse(), ComponentInstance.class); + + response = ResourceRestUtils.createResourceInstance(importReqDetails2, sdncUserDetails, vf.getUniqueId()); + ResourceRestUtils.checkCreateResponse(response); + ComponentInstance riReq = ResponseParser.parseToObject(response.getResponse(), ComponentInstance.class); + + RestResponse getResourceBeforeAssociate = ComponentRestUtils + .getComponentRequirmentsCapabilities(sdncUserDetails, vf); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceBeforeAssociate.getResponse(), CapReqDef.class); + + String capbilityUid = capReqDef.getCapabilities().get("tosca.capabilities.network.Bindable").get(0) + .getUniqueId(); + String requirementUid = capReqDef.getRequirements().get("tosca.capabilities.network.Bindable").get(0) + .getUniqueId(); + + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + requirementDef.setFromNode(riReq.getUniqueId()); + requirementDef.setToNode(riCap.getUniqueId()); + + RequirementAndRelationshipPair pair = new RequirementAndRelationshipPair(); + pair.setRequirementOwnerId(riReq.getUniqueId()); + pair.setCapabilityOwnerId(riCap.getUniqueId()); + pair.setRequirement("VirtualBinding"); + RelationshipImpl relationship = new RelationshipImpl(); + relationship.setType("tosca.capabilities.network.Bindable"); + pair.setRelationships(relationship); + pair.setCapabilityUid(capbilityUid); + pair.setRequirementUid(requirementUid); + List relationships = new ArrayList<>(); + relationships.add(pair); + requirementDef.setRelationships(relationships); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, sdncUserDetails, + vf.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + } + + @Test + public void caseCapabilitiesInsensitiveTest() throws Exception { + String fileName = "CaseInsensitiveCapTest_1.yml"; + int expectedNumOfCapabilities = 6; + + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setCapabilities(testResourcesPath, fileName, sdncUserDetails, null); + Map capabilities = importReqDetails.getCapabilities(); + Map capabilitiesFromResponse = parseReqOrCapFromResponse("capabilities", importReqDetails, + expectedNumOfCapabilities); + assertEquals(capabilities.keySet().size(), capabilitiesFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(capabilities, capabilitiesFromResponse); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String fileName2 = "CaseInsensitiveCapTest_2.yml"; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName2); + importReqDetails.setName("secondImportedResource"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setCapabilities(testResourcesPath, fileName2, sdncUserDetails, null); + capabilities = importReqDetails.getCapabilities(); + capabilitiesFromResponse = parseReqOrCapFromResponse("capabilities", importReqDetails, + expectedNumOfCapabilities); + assertEquals(capabilities.keySet().size(), capabilitiesFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(capabilities, capabilitiesFromResponse); + + } + + @Test + public void fatherAndChildHaveDifferentRequirementsTest() throws Exception { + String fileName = "DifferentReqFromCompute.yml"; + int expectedNumOfRequirements = 3; + + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setRequirements(testResourcesPath, fileName, sdncUserDetails, "Compute"); + Map requirements = importReqDetails.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + + checkImportedAssetAssociated(importReqDetails); + } + + @Test + public void fatherHasNoRequirementsTest() throws Exception { + String fatherFileName = "CPHasNoReqCap.yml"; + String childFileName = "DerivedFromCPWithOwnReq.yml"; + int expectedNumOfRequirements = 3; + + importReqDetails.setName("father"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fatherFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String derivedFromResourceName = importReqDetails.getName(); + importReqDetails = ElementFactory.getDefaultImportResource(); + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setRequirements(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + derivedFromResourceName); + Map requirements = importReqDetails.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + + } + + @Test + public void childHasSameReqNameAndTypeLikeFatherTest() throws Exception { + String childFileName = "SameReqAsCompute.yml"; + int expectedNumOfRequirements = 2; + + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setRequirements(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, null); + Map requirements = importReqDetails.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + } + + @Test + public void childHasSameCapNameAndTypeLikeFatherTest() throws Exception { + String childFileName = "SameCapAsCompute.yml"; + int expectedNumOfCapabilities = 6; + + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setCapabilities(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + "Compute"); + Map capabilities = importReqDetails.getCapabilities(); + Map capabilitiesFromResponse = parseReqOrCapFromResponse("capabilities", importReqDetails, + expectedNumOfCapabilities); + assertEquals(capabilities.keySet().size(), capabilitiesFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(capabilities, capabilitiesFromResponse); + } + + @Test + public void childGetsAllRequirementsOfFatherAndGrandfatherTest() throws Exception { + int expectedNumOfRequirements = 4; + + String fatherFileName = "DifferentReqFromCompute.yml"; + importReqDetails.setName("father"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fatherFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String derivedFromName = importReqDetails.getName(); + String childFileName = "DifferentReqCapFromCompute1.yml"; + importReqDetails = ElementFactory.getDefaultImportResource(); + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setRequirements(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + derivedFromName); + Map requirements = importReqDetails.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + + } + + @Test + public void childOverridesGrandfatherRequirementsTest() throws Exception { + int expectedNumOfRequirements = 3; + + String fatherFileName = "DifferentReqFromCompute.yml"; + importReqDetails.setName("father"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fatherFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String derivedFromName = importReqDetails.getName(); + String childFileName = "SameReqAsCompute_DerivedFromMyCompute1.yml"; + importReqDetails = ElementFactory.getDefaultImportResource(); + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setRequirements(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + derivedFromName); + Map requirements = importReqDetails.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + } + + @Test + public void childAndGrandfatherHaveDifferenetReqiurementTypeTest() throws Exception { + int expectedNumOfRequirements = 3; + int expectedNumOfCapabilities = 6; + + String fatherName = "father"; + String fatherFileName = "DifferentReqFromCompute.yml"; + importReqDetails.setName(fatherName); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fatherFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String fatherUniqueId = importReqDetails.getUniqueId(); + ImportReqDetails importReqDetailsFather = importReqDetails; + + String childFileName = "importRequirementNameExistsOnParent_DerivedFromMyCompute1.yml"; + importReqDetails = ElementFactory.getDefaultImportResource(); + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_INVALID_CONTENT, importResourceResponse.getErrorCode().intValue()); + ArrayList variables = new ArrayList<>(); + variables.add("requirement"); + variables.add("local_storage"); + variables.add(fatherName); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED.name(), + variables, importResourceResponse.getResponse()); + + importReqDetails.setUniqueId(fatherUniqueId); + + importReqDetailsFather.setRequirements(testResourcesPath, fatherFileName, sdncUserDetails, "Compute"); + Map requirements = importReqDetailsFather.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetailsFather, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetailsFather.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + + importReqDetailsFather.setCapabilities(testResourcesPath, fatherFileName, sdncUserDetails, "Compute"); + Map capabilities = importReqDetailsFather.getCapabilities(); + Map capabilitiesFromResponse = parseReqOrCapFromResponse("capabilities", importReqDetailsFather, + expectedNumOfCapabilities); + assertEquals(capabilities.keySet().size(), capabilitiesFromResponse.keySet().size()); + importReqDetailsFather.compareRequirementsOrCapabilities(capabilities, capabilitiesFromResponse); + } + + @Test + public void childHasNoReqCapTest() throws Exception { + int expectedNumOfRequirements = 3; + int expectedNumOfCapabilities = 6; + + String fatherFileName = "DifferentReqFromCompute.yml"; + importReqDetails.setName("father"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fatherFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String derivedFromName = importReqDetails.getName(); + String childFileName = "CPHasNoReqCap_DerivedFromMyCompute1.yml"; + importReqDetails = ElementFactory.getDefaultImportResource(); + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setRequirements(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + derivedFromName); + Map requirements = importReqDetails.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + + importReqDetails.setCapabilities(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + derivedFromName); + Map capabilities = importReqDetails.getCapabilities(); + Map capabilitiesFromResponse = parseReqOrCapFromResponse("capabilities", importReqDetails, + expectedNumOfCapabilities); + assertEquals(capabilities.keySet().size(), capabilitiesFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(capabilities, capabilitiesFromResponse); + } + + @Test + public void fatherAndChildGetReqCapFromGrandfatherTest() throws Exception { + int expectedNumOfRequirements = 2; + int expectedNumOfCapabilities = 6; + + String fatherFileName = "MyFatherCompute_NoReqCap.yml"; + importReqDetails.setName("father"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fatherFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String derivedFromName = importReqDetails.getName(); + String childFileName = "myChildCompute_NoReqCap.yml"; + importReqDetails = ElementFactory.getDefaultImportResource(); + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setRequirements(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + derivedFromName); + Map requirements = importReqDetails.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + + importReqDetails.setCapabilities(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + derivedFromName); + Map capabilities = importReqDetails.getCapabilities(); + Map capabilitiesFromResponse = parseReqOrCapFromResponse("capabilities", importReqDetails, + expectedNumOfCapabilities); + assertEquals(capabilities.keySet().size(), capabilitiesFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(capabilities, capabilitiesFromResponse); + } + + @Test + public void reverseInheritanceTest() throws Exception { + int expectedNumOfRequirements = 2; + int expectedNumOfCapabilities = 2; + + String fatherName = "father"; + String fatherFileName = "myFatherWebApp_derviedFromDocker.yml"; + importReqDetails.setName(fatherName); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fatherFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String fatherUniqueId = importReqDetails.getUniqueId(); + ImportReqDetails importReqDetailsFather = importReqDetails; + String childFileName = "myChildWebApp_DerivedFromContainer.yml"; + importReqDetails = ElementFactory.getDefaultImportResource(); + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_INVALID_CONTENT, importResourceResponse.getErrorCode().intValue()); + ArrayList variables = new ArrayList<>(); + variables.add("requirement"); + variables.add("host"); + variables.add(fatherName); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED.name(), + variables, importResourceResponse.getResponse()); + + importReqDetails.setUniqueId(fatherUniqueId); + importReqDetailsFather.setRequirements(testResourcesPath, fatherFileName, sdncUserDetails, "Root"); + Map requirements = importReqDetailsFather.getRequirements(); + Map requirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetailsFather, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), requirementsFromResponse.keySet().size()); + importReqDetailsFather.compareRequirementsOrCapabilities(requirements, requirementsFromResponse); + + importReqDetailsFather.setCapabilities(testResourcesPath, fatherFileName, sdncUserDetails, "Root"); + Map capabilities = importReqDetailsFather.getCapabilities(); + Map capabilitiesFromResponse = parseReqOrCapFromResponse("capabilities", importReqDetailsFather, + expectedNumOfCapabilities); + assertEquals(capabilities.keySet().size(), capabilitiesFromResponse.keySet().size()); + importReqDetailsFather.compareRequirementsOrCapabilities(capabilities, capabilitiesFromResponse); + } + + // DE202329 + @Test(enabled = false) + public void requirementWithMissingTypeTest() throws Exception { + String fatherName = "father"; + String fatherFileName = "DerivedFromWebApplication_HasNoReqType.yml"; + importReqDetails.setName(fatherName); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fatherFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_INVALID_CONTENT, importResourceResponse.getErrorCode().intValue()); + ArrayList variables = new ArrayList<>(); + variables.add("diff"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_CAPABILITY_TYPE.name(), variables, + importResourceResponse.getResponse()); + + } + + @Test + public void TwinBrothersHaveSameReqCapTest() throws Exception { + int expectedNumOfRequirements = 4; + int expectedNumOfCapabilities = 7; + + String derivedFromName = "father"; + String fatherFileName = "DifferentReqFromCompute.yml"; + importReqDetails.setName(derivedFromName); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fatherFileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + RestResponse changeResourceState1 = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState1.getErrorCode().intValue()); + RestResponse changeResourceState2 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState2.getErrorCode().intValue()); + RestResponse changeResourceState3 = LifecycleRestUtils.changeResourceState(importReqDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState3.getErrorCode().intValue()); + + String childFileName = "DifferentReqCapFromCompute1.yml"; + importReqDetails = ElementFactory.getDefaultImportResource(); + importReqDetails.setName("child"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + childFileName); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + Map childRequirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + Map childCapabilitiesFromResponse = parseReqOrCapFromResponse("capabilities", importReqDetails, + expectedNumOfCapabilities - 1); + + String twinFileName = "DifferentReqCapFromCompute2.yml"; + importReqDetails = ElementFactory.getDefaultImportResource(); + importReqDetails.setName("twin"); + importReqDetails.setTags(Arrays.asList(importReqDetails.getName())); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + twinFileName); + importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + + importReqDetails.setRequirements(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + derivedFromName); + Map requirements = importReqDetails.getRequirements(); + Map twinRequirementsFromResponse = parseReqOrCapFromResponse("requirements", importReqDetails, + expectedNumOfRequirements); + assertEquals(requirements.keySet().size(), twinRequirementsFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(requirements, twinRequirementsFromResponse); + + importReqDetails.setCapabilities(testResourcesPath, importReqDetails.getPayloadName(), sdncUserDetails, + derivedFromName); + Map capabilities = importReqDetails.getCapabilities(); + Map twinCapabilitiesFromResponse = parseReqOrCapFromResponse("capabilities", importReqDetails, + expectedNumOfCapabilities); + assertEquals(capabilities.keySet().size(), twinCapabilitiesFromResponse.keySet().size()); + importReqDetails.compareRequirementsOrCapabilities(capabilities, twinCapabilitiesFromResponse); + + assertEquals(childRequirementsFromResponse.keySet().size(), twinRequirementsFromResponse.keySet().size()); + assertEquals(childCapabilitiesFromResponse.keySet().size(), twinCapabilitiesFromResponse.keySet().size()); + } + + /* + * invariantUUID - US672129 + */ + + private void checkInvariantUuidIsImmutableInDifferentAction(ImportReqDetails importReqDetails) throws Exception { + // create resource + importReqDetails.setName("import"); + String invariantUuidDefinedByUser = "abcd1234"; + RestResponse importResourceResponse = importResourceWithRequestedInvariantUuid(importReqDetails, + invariantUuidDefinedByUser); + String invariantUUIDcreation = ResponseParser.getInvariantUuid(importResourceResponse); + assertFalse(checkInvariantUuidEqual(invariantUuidDefinedByUser, importResourceResponse)); + + // get resource + RestResponse getResource = ResourceRestUtils.getResource(importReqDetails.getUniqueId()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, getResource)); + + // checkin resource + RestResponse changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CHECKIN); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // checkout resource + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CHECKOUT); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // checkin resource + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CHECKIN); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // checkout resource + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CHECKOUT); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // checkin resource + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CHECKIN); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // certification request + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // start certification + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, testerUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // certify + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, testerUser, + LifeCycleStatesEnum.CERTIFY); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + String certifiedUniqueId = importReqDetails.getUniqueId(); + + // update resource + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CHECKOUT); + ResourceReqDetails updatedResourceReqDetails = new ResourceReqDetails(importReqDetails, + importReqDetails.getVersion()); + updatedResourceReqDetails.setDescription("updatedDescription"); + updatedResourceReqDetails.setVendorRelease("1.2.3.4"); + RestResponse updateResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceReqDetails, + sdncUserDetails, importReqDetails.getUniqueId()); + assertEquals(STATUS_CODE_SUCCESS, updateResponse.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, updateResponse)); + + // certification request + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // checkout resource + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CHECKOUT); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // certification request + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // start certification + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, testerUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // cancel certification + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, testerUser, + LifeCycleStatesEnum.CANCELCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // start certification + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, testerUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // failure + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, testerUser, + LifeCycleStatesEnum.FAILCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // upload artifact + changeResourceState = LifecycleRestUtils.changeResourceState(importReqDetails, sdncUserDetails, + LifeCycleStatesEnum.CHECKOUT); + ArtifactReqDetails artifactDetails = ElementFactory.getDefaultArtifact(); + ArtifactRestUtils.addInformationalArtifactToResource(artifactDetails, sdncUserDetails, + importReqDetails.getUniqueId()); + assertEquals(STATUS_CODE_SUCCESS, changeResourceState.getErrorCode().intValue()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, changeResourceState)); + + // create instance + resourceDetails.setResourceType(ResourceTypeEnum.VF.toString()); + ResourceRestUtils.createResource(resourceDetails, sdncUserDetails); + importReqDetails.setUniqueId(certifiedUniqueId); + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(importReqDetails); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncUserDetails, resourceDetails.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals(STATUS_CODE_CREATED, createResourceInstanceResponse.getErrorCode().intValue()); + getResource = ResourceRestUtils.getResource(importReqDetails.getUniqueId()); + assertTrue(checkInvariantUuidEqual(invariantUUIDcreation, getResource)); + } + + private boolean checkInvariantUuidEqual(String expectedInvariantUuid, RestResponse response) { + String invariantUUIDFromResponse = ResponseParser.getInvariantUuid(response); + return expectedInvariantUuid.equals(invariantUUIDFromResponse); + } + + @Test + public void checkCPHasImmutableInvariantUuidTest() throws Exception { + String filename = "FatherHasNoReqCap.yml"; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + filename); + checkResourceHasImmutableInvariantUuidTest(importReqDetails); + } + + @Test + public void checkVFCHasImmutableInvariantUuidTest() throws Exception { + String filename = "computeCap11.yml"; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + filename); + checkResourceHasImmutableInvariantUuidTest(importReqDetails); + } + + public void checkResourceHasImmutableInvariantUuidTest(ImportReqDetails importReqDetails) throws Exception { + // invariantUuid is null + importReqDetails.setName("first"); + RestResponse importResourceResponse = importResourceWithRequestedInvariantUuid(importReqDetails, null); + String invariantUUIDcreation = ResponseParser.getInvariantUuid(importResourceResponse); + assertNotNull(invariantUUIDcreation); + + ResourceRestUtils.deleteResource(importReqDetails.getUniqueId(), sdncUserDetails.getUserId()); + + // invariantUuid is empty + importReqDetails.setName("second"); + String invariantUuidDefinedByUser = ""; + importResourceResponse = importResourceWithRequestedInvariantUuid(importReqDetails, invariantUuidDefinedByUser); + invariantUUIDcreation = ResponseParser.getInvariantUuid(importResourceResponse); + assertNotNull(invariantUUIDcreation); + + ResourceRestUtils.deleteResource(importReqDetails.getUniqueId(), sdncUserDetails.getUserId()); + + checkInvariantUuidIsImmutableInDifferentAction(importReqDetails); + } + + private static RestResponse importResourceWithRequestedInvariantUuid(ImportReqDetails importDetails, + String invariantUuid) throws Exception { + importDetails.setInvariantUUID(invariantUuid); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importDetails, sdncUserDetails, + null); + assertEquals(STATUS_CODE_CREATED, importResourceResponse.getErrorCode().intValue()); + return importResourceResponse; + } + + private Map parseReqOrCapFromResponse(String parsedFieldName, ImportReqDetails importReqDetails, + int expectedNumOfReqCap) throws ClientProtocolException, IOException { + RestResponse getResource = ResourceRestUtils.getResource(importReqDetails.getUniqueId()); + assertTrue(getResource.getErrorCode().equals(STATUS_CODE_SUCCESS)); + Map parsedFieldFromResponseToMap = ResponseParser.getJsonValueAsMap(getResource, + parsedFieldName); + Iterator iterator = parsedFieldFromResponseToMap.keySet().iterator(); + actualNumOfReqOrCap = 0; + while (iterator.hasNext()) { + String next = iterator.next(); + List object = (List) parsedFieldFromResponseToMap.get(next); + actualNumOfReqOrCap += object.size(); + } + assertEquals(expectedNumOfReqCap, actualNumOfReqOrCap); + return parsedFieldFromResponseToMap; + } + + // --------------------------------- + + private void verifyResourcePropertiesList(Resource resourceJavaObject) { // use + // importListPropertySuccessFlow.yml + boolean isPropertyAppear = false; + List propertiesList = resourceJavaObject.getProperties(); + for (PropertyDefinition pro : propertiesList) { + switch (pro.getName()) { + case "my_boolean": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[false,true]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "my_boolean_array": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[true,false]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "duplicate_boolean_values": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[true,false,true]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "boolean_values_Insensitive": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[true,false,true]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "my_integers": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[0,1000,-1000,50]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "my_integers_array": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[10,-1000,0]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "duplicate_integers_values": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[10,10,-1000,0]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "my_string": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("[\"asdc\",\"$?^@ecomp$!#%()_-~@+*^...;;/w#\",\"uc\"]")); + // assertTrue("Check Property default values ", + // pro.getDefaultValue().equals("[\"asdc\",\"@=~!@#$%^&*()_+=?><:-w\",\"uc\"]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "my_string_array": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("[\"AAA\",\"~$~#bbb%^*_-\",\"qwe\",\"1.3\",\"500\",\"true\"]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "duplicate_string_values": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("[\"asdc\",\"asdc\",\"uc\"]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_null_value": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[\"asdc\",\"uc\"]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_space_value": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[\"asdc\",\"uc\"]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_array_null_value": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("[\"aaa\",\"bbb\",\"500\"]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "my_float": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[6,1000.000001,-3.0]")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "my_float_array": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[0.01,-5.0,2.1]")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "duplicate_float_values": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[0.0,0.0,4.555555]")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_no_default_values": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertEquals("Check Property default values ", pro.getDefaultValue(), null); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "integer_no_default_values": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertEquals("Check Property default values ", pro.getDefaultValue(), null); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "string_no_default_values": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertEquals("Check Property default values ", pro.getDefaultValue(), null); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "boolean_no_default_values": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertEquals("Check Property default values ", pro.getDefaultValue(), null); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "integer_null_value": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[1000,2000]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "boolean_null_value": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[true,false]")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "float_null_value": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[6,-3.0]")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_space_value": + assertTrue("Check Property Type ", pro.getType().equals("list")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("[6,-3.0]")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + + } + assertTrue(isPropertyAppear); + isPropertyAppear = false; + } + + } + + private void verifyRequirementsOccurrences(Resource resourceJavaObject, String requirementsType) { + boolean isRequirementAppear = false; + // List requerments = + // resourceJavaObject.getRequirements().get("tosca.capabilities.Attachment"); + List requerments = resourceJavaObject.getRequirements().get(requirementsType); + + for (RequirementDefinition req : requerments) { + switch (req.getName()) { + case "local_storage100": + assertTrue("Check Min Requirement Occurrences ", req.getMinOccurrences().equals("1")); + assertTrue("Check Max Requirement Occurrences ", req.getMaxOccurrences().equals("UNBOUNDED")); + isRequirementAppear = true; + break; + case "local_storage200": + assertTrue("Check Min Requirement Occurrences ", req.getMinOccurrences().equals("1")); + assertTrue("Check Max Requirement Occurrences ", req.getMaxOccurrences().equals("1")); + isRequirementAppear = true; + break; + case "local_storage300": + assertTrue("Check Min Requirement Occurrences ", req.getMinOccurrences().equals("1")); + assertTrue("Check Max Requirement Occurrences ", req.getMaxOccurrences().equals("10")); + isRequirementAppear = true; + break; + case "local_storage400": + assertTrue("Check Min Requirement Occurrences ", req.getMinOccurrences().equals("1")); + assertTrue("Check Max Requirement Occurrences ", req.getMaxOccurrences().equals("10000000")); + isRequirementAppear = true; + break; + case "local_storage500": + assertTrue("Check Min Requirement Occurrences ", req.getMinOccurrences().equals("2")); + assertTrue("Check Max Requirement Occurrences ", req.getMaxOccurrences().equals("3")); + isRequirementAppear = true; + break; + case "local_storageNoOccurrences600": + assertTrue("Check Min Requirement Occurrences ", req.getMinOccurrences().equals("1")); + assertTrue("Check Max Requirement Occurrences ", req.getMaxOccurrences().equals("1")); + isRequirementAppear = true; + break; + } + assertTrue(isRequirementAppear); + isRequirementAppear = false; + } + + } + + private void verifyCapabilitiesOccurrences(Resource resourceJavaObject, String capabilitType) { + boolean isCapabilityAppear = false; + // List capabilities = + // resourceJavaObject.getCapabilities().get("tosca.capabilities.Endpoint.Admin"); + List capabilities = resourceJavaObject.getCapabilities().get(capabilitType); + + for (CapabilityDefinition cap : capabilities) { + switch (cap.getName()) { + case "endpointNoOccurrence": + assertTrue("Check Min capability Occurrences ", cap.getMinOccurrences().equals("1")); + assertTrue("Check Max capability Occurrences ", cap.getMaxOccurrences().equals("UNBOUNDED")); + isCapabilityAppear = true; + break; + case "endpoint200": + assertTrue("Check Min capability Occurrences ", cap.getMinOccurrences().equals("1")); + assertTrue("Check Max capability Occurrences ", cap.getMaxOccurrences().equals("2")); + isCapabilityAppear = true; + break; + case "endpoint300": + assertTrue("Check Min capability Occurrences ", cap.getMinOccurrences().equals("1")); + assertTrue("Check Max capability Occurrences ", cap.getMaxOccurrences().equals("1")); + isCapabilityAppear = true; + break; + case "endpoint400": + assertTrue("Check Min capability Occurrences ", cap.getMinOccurrences().equals("1")); + assertTrue("Check Max capability Occurrences ", cap.getMaxOccurrences().equals("10")); + isCapabilityAppear = true; + break; + case "endpoint500": + assertTrue("Check Min capability Occurrences ", cap.getMinOccurrences().equals("1")); + assertTrue("Check Max capability Occurrences ", cap.getMaxOccurrences().equals("10000000")); + isCapabilityAppear = true; + break; + case "endpoint600": + assertTrue("Check Min capability Occurrences ", cap.getMinOccurrences().equals("1")); + assertTrue("Check Max capability Occurrences ", cap.getMaxOccurrences().equals("UNBOUNDED")); + isCapabilityAppear = true; + break; + case "endpoint700": + assertTrue("Check Min capability Occurrences ", cap.getMinOccurrences().equals("2")); + assertTrue("Check Max capability Occurrences ", cap.getMaxOccurrences().equals("4")); + isCapabilityAppear = true; + break; + + } + assertTrue(isCapabilityAppear); + isCapabilityAppear = false; + } + + } + + private void verifyResourcePropertiesMap(Resource resourceJavaObject) { // use + // importMapPropertySuccessFlow.yml + boolean isPropertyAppear = false; + List propertiesList = resourceJavaObject.getProperties(); + for (PropertyDefinition pro : propertiesList) { + switch (pro.getName()) { + case "string_prop01": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\"val1\",\"keyB\":\"val2\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop02": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\"val1\",\"keyB\":\"val2\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop03": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\"val1\",\"keyB\":\"val2\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop04": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\"10\",\"keyB\":\"true\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop05": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":\"Big\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop06": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\"aaaA\",\"keyB\":null}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop07": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":null}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop08": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\"\",\"keyB\":\"abcd\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop09": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\" \",\"keyB\":\"abcd\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop10": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\" aaaa\",\"keyB\":\" bbbb\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop11": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\"aaaa \",\"keyB\":\"bbbb \"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop12": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":\" aaaa \",\"keyB\":\" bbbb ccccc \"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop13": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("{\"keyA\":\"aaaa\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop14": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("{\"keyA\":\" aaaa \"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop15": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("{\"keyA\":\"AbcD\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop16": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("{\"keyA\":\"AbcD\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop17": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("{\"keyA\":\"AbcD\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop18": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("{\"keyA\":\"AbcD\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop19": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("{\"keyA\":\"AbcD\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop20": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue() + .equals("{\"keyA\":\"aaaa\",\"keya\":\"aaaa\",\"Keya\":\"Aaaa\",\"KEYA\":\"nnnn\"}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop21": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":null,\"keyC\":null}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "string_prop22": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertEquals("Check Property default values ", pro.getDefaultValue(), null); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("string")); + isPropertyAppear = true; + break; + case "integer_prop01": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":1,\"keyB\":1000}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop02": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":null,\"keyC\":null}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop03": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":800,\"keyB\":-600}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop04": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":-600}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop05": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":100,\"keyB\":0}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop06": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":100,\"keyB\":0}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop07": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":100,\"keyB\":100}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop08": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":100,\"keyB\":200}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop09": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":100,\"keyB\":200}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop10": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":2222}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop11": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":null,\"keyC\":null,\"keyD\":null}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop12": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertEquals("Check Property default values ", pro.getDefaultValue(), null); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "integer_prop13": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("{\"keyA\":200}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("integer")); + isPropertyAppear = true; + break; + case "boolean_prop01": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":true,\"keyB\":false,\"keyC\":false}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "boolean_prop02": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":true,\"keyB\":false,\"keyC\":false}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "boolean_prop03": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":null,\"keyC\":null,\"keyD\":null}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "boolean_prop04": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":null,\"keyC\":null,\"keyD\":null}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "boolean_prop05": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":true,\"keyB\":false,\"keyC\":false}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "boolean_prop06": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":true,\"keyB\":true,\"keyC\":false}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "boolean_prop07": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertEquals("Check Property default values ", pro.getDefaultValue(), null); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "boolean_prop08": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":true,\"keyB\":false}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "boolean_prop09": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":false,\"keyB\":true}")); + assertTrue("Check entrySchema Property Type ", + pro.getSchema().getProperty().getType().equals("boolean")); + isPropertyAppear = true; + break; + case "float_prop01": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":1.2,\"keyB\":3.56,\"keyC\":33}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop02": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":0.0,\"keyB\":0.0,\"keyC\":0}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop03": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":null,\"keyC\":null,\"keyD\":null}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop04": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":1.2,\"keyB\":3.56,\"keyC\":33}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop05": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":33,\"keyB\":1.2,\"keyC\":3.607,\"keyD\":0}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop06": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":33,\"keyB\":1.2,\"keyC\":3.607}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop07": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":null,\"keyB\":null,\"keyC\":null,\"keyD\":null}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop08": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertEquals("Check Property default values ", pro.getDefaultValue(), null); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop09": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":0.01,\"keyB\":null}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop10": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", pro.getDefaultValue().equals("{\"keyA\":0.00020}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + case "float_prop11": + assertTrue("Check Property Type ", pro.getType().equals("map")); + assertTrue("Check Property default values ", + pro.getDefaultValue().equals("{\"keyA\":3.56,\"keyB\":33}")); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType().equals("float")); + isPropertyAppear = true; + break; + } + assertTrue(isPropertyAppear); + isPropertyAppear = false; + } + + } + + @Test + public void importToscaResourceAttributeSuccessFlow() throws Exception { + + String fileName = importAttributeSuccess; + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, sdncUserDetails, + null); + ResourceRestUtils.checkCreateResponse(importResourceResponse); + Resource resourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + ToscaNodeTypeInfo parseToscaNodeYaml = utils + .parseToscaNodeYaml(Decoder.decode(importReqDetails.getPayloadData())); + + HashMap attr = new HashMap<>(); + + PropertyDefinition newAttr2 = new PropertyDefinition(); + newAttr2.setName("networks"); + newAttr2.setType("map"); + newAttr2.setDefaultValue("{\"keyA\" : val1 , \"keyB\" : val2}"); + SchemaDefinition schema = new SchemaDefinition(); + PropertyDataDefinition prop = new PropertyDataDefinition(); + prop.setType("string"); + schema.setProperty(prop); + newAttr2.setSchema(schema); + attr.put("networks", newAttr2); + + PropertyDefinition newAttr1 = new PropertyDefinition(); + newAttr1.setName("public_address"); + newAttr1.setType("string"); + attr.put("public_address", newAttr1); + + PropertyDefinition newAttr3 = new PropertyDefinition(); + newAttr3.setName("ports"); + newAttr3.setDescription("this is my description"); + attr.put("ports", newAttr3); + + PropertyDefinition newAttr = new PropertyDefinition(); + newAttr.setDefaultValue("myDefault"); + newAttr.setName("private_address"); + newAttr.setStatus("supported"); + newAttr.setType("string"); + attr.put("private_address", newAttr); + + // verify Resource Attributes + validateResourceAttribute(resourceJavaObject, attr); + + // TO DO + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory + .getDefaultImportResourceAuditMsgSuccess(); + expectedResourceAuditJavaObject.setResourceName(importReqDetails.getName()); + expectedResourceAuditJavaObject.setModifierName(sdncUserDetails.getFullName()); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + expectedResourceAuditJavaObject.setToscaNodeType(parseToscaNodeYaml.getNodeName()); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + AuditingActionEnum.IMPORT_RESOURCE.getName(), null, false); + } + + private void validateResourceAttribute(Resource resource, Map attr) { + List resList = resource.getAttributes(); + int size = resList.size(); + String attributeName; + for (int i = 0; i < size; i++) { + attributeName = resList.get(i).getName(); + assertEquals(attr.get(attributeName).getDefaultValue(), resList.get(i).getDefaultValue()); + assertEquals(attr.get(attributeName).getName(), resList.get(i).getName()); + assertEquals(attr.get(attributeName).getDescription(), resList.get(i).getDescription()); + assertEquals(attr.get(attributeName).getStatus(), resList.get(i).getStatus()); + } + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportUpdateResourseCsarTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportUpdateResourseCsarTest.java new file mode 100644 index 0000000000..464ebe12ed --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/imports/ImportUpdateResourseCsarTest.java @@ -0,0 +1,283 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.imports; + +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.assertEquals; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.regex.Pattern; + +import org.apache.commons.codec.binary.Base64; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.common.api.Constants; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class ImportUpdateResourseCsarTest extends ComponentBaseTest { + @Rule + public static TestName name = new TestName(); + + Gson gson = new Gson(); + public static String userDefinedNodeYaml = "mycompute2.yml"; + public static String rootPath = System.getProperty("user.dir"); + public static String csarFolderPath = "/src/test/resources/CI/csars/"; + + public ImportUpdateResourseCsarTest() { + super(name, ImportUpdateResourseCsarTest.class.getName()); + } + + @Test + public void createUpdateImportResourceFromCsarTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + RestResponse updateResource = null; + RestResponse createResource = null; + Resource resource = null; + String payloadName = "orig2G.csar"; + String rootPath = System.getProperty("user.dir"); + Path path = Paths.get(rootPath + csarFolderPath + "orig2G.csar"); + byte[] data = Files.readAllBytes(path); + String payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setName("TEST01"); + resourceDetails.setCsarUUID("orig2G.csar"); + resourceDetails.setCsarVersion("1"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + // create new resource from Csar + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + // update scar with new artifacts + path = Paths.get(rootPath + csarFolderPath + "orig2G_update.csar"); + data = Files.readAllBytes(path); + payloadData = Base64.encodeBase64String(data); + resourceDetails.setDescription("update"); + resourceDetails.setCsarVersion("2"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + } + + @Test + public void createUpdateImportResourceFromCsarWithArtifactsGroupNamingTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes; + ResourceReqDetails resourceDetails; + RestResponse updateResource; + RestResponse createResource; + Resource resource; + + // back original scar + copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "VF_RI2_G4_withArtifacts_group_naming_a.csar", "VF_RI2_G4_withArtifacts_group_naming.csar"); + BaseRestUtils.checkSuccess(copyRes); + + resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("TEST01"); + resourceDetails.setCsarUUID("VF_RI2_G4_withArtifacts_group_naming.csar"); + resourceDetails.setCsarVersion("1"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + // create new resource from Csar + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + List groups = resource.getGroups(); + assertTrue(groups != null && groups.size() == 6); + assertTrue(groups.stream() + .filter(g -> g.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE) + && !Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(g.getName()).matches()) + .count() == 0); + // update scar + copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "VF_RI2_G4_withArtifacts_group_naming_delete_update.csar", "VF_RI2_G4_withArtifacts_group_naming.csar"); + BaseRestUtils.checkSuccess(copyRes); + resourceDetails.setDescription("BLA BLA BLA"); + resourceDetails.setCsarVersion("2"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + groups = resource.getGroups(); + assertTrue(groups != null && groups.size() == 5); + // back original scar + copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "VF_RI2_G4_withArtifacts_group_naming_a.csar", "VF_RI2_G4_withArtifacts_group_naming.csar"); + BaseRestUtils.checkSuccess(copyRes); + resourceDetails.setDescription("BLA BLA BLA"); + resourceDetails.setCsarVersion("3"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + groups = resource.getGroups(); + assertTrue(groups != null && groups.size() == 6); + assertTrue(groups.stream() + .filter(g -> g.getType().equals(Constants.DEFAULT_GROUP_VF_MODULE) + && !Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(g.getName()).matches()) + .count() == 0); + } + + @Test + public void createUpdateDeleteAllRequiredArtifactsTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes; + ResourceReqDetails resourceDetails; + RestResponse updateResource; + RestResponse createResource; + Resource resource; + String artifactName = "heatnested7"; + + ImportReqDetails resourceDetails0 = ElementFactory.getDefaultImportResource(); + createResource = importUserDefinedNodeType(userDefinedNodeYaml, sdncModifierDetails, resourceDetails0); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + + // back original scar + copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, "orig2GV001_a.csar", "orig2GV001.csar"); + BaseRestUtils.checkSuccess(copyRes); + + resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("TEST01"); + resourceDetails.setCsarUUID("orig2GV001.csar"); + resourceDetails.setCsarVersion("1"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + // create new resource from Csar + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertTrue(resource.getDeploymentArtifacts().get(artifactName).getRequiredArtifacts().size() == 2); + List groups = resource.getGroups(); + // update scar + copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "orig2GV006-remove-all-nested-artifacts.csar", "orig2GV001.csar"); + BaseRestUtils.checkSuccess(copyRes); + resourceDetails.setDescription("BLA BLA BLA"); + resourceDetails.setCsarVersion("2"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + assertTrue(resource.getDeploymentArtifacts().get(artifactName).getRequiredArtifacts().size() == 0); + groups = resource.getGroups(); + // back original scar + copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, "orig2GV001_a.csar", "orig2GV001.csar"); + BaseRestUtils.checkSuccess(copyRes); + } + + // First create from orig2GV006-remove-all-nested-artifacts.csar (without + // requiredArtifact) + // Submit for testing + // Login as tester -> Certification + // Login as designer + // then update to orig2GV008-change-nested-oam-fileContent.csar (with + // requiredArtifact) + // Expected: requiredArtifact: ["hot-nimbus-psm_v1.0.yaml", + // "hot-nimbus-swift-container_v1.0.yaml"] + // Actual: no requiredArtifact + @Test + public void createUpdateAddRequiredArtifactsTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse copyRes; + ResourceReqDetails resourceDetails; + RestResponse updateResource; + RestResponse createResource; + Resource resource; + String artifactName = "heatnested7"; + + ImportReqDetails resourceDetails0 = ElementFactory.getDefaultImportResource(); + createResource = importUserDefinedNodeType(userDefinedNodeYaml, sdncModifierDetails, resourceDetails0); + BaseRestUtils.checkCreateResponse(createResource); + createResource = LifecycleRestUtils.certifyResource(resourceDetails0); + BaseRestUtils.checkSuccess(createResource); + + // back original scar + copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "orig2GV006-remove-all-nested-artifacts.csar", "orig2GV001.csar"); + BaseRestUtils.checkSuccess(copyRes); + + resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("TEST01"); + resourceDetails.setCsarUUID("orig2GV001.csar"); + resourceDetails.setCsarVersion("1"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + // create new resource from Csar + createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + createResource = LifecycleRestUtils.certifyResource(resourceDetails); + BaseRestUtils.checkSuccess(createResource); + + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + assertTrue(resource.getDeploymentArtifacts().get(artifactName).getRequiredArtifacts().size() == 0); + List groups = resource.getGroups(); + // update scar + copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, + "orig2GV008-change-nested-oam-fileContent.csar", "orig2GV001.csar"); + BaseRestUtils.checkSuccess(copyRes); + resourceDetails.setDescription("BLA BLA BLA"); + resourceDetails.setCsarVersion("2"); + updateResource = ResourceRestUtils.updateResource(resourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(updateResource); + resource = ResponseParser.parseToObjectUsingMapper(updateResource.getResponse(), Resource.class); + assertTrue(resource.getDeploymentArtifacts().get(artifactName).getRequiredArtifacts().size() == 2); + groups = resource.getGroups(); + // back original scar + copyRes = ImportCsarResourceTest.copyCsarRest(sdncModifierDetails, "orig2GV001_a.csar", "orig2GV001.csar"); + BaseRestUtils.checkSuccess(copyRes); + } + + private RestResponse importUserDefinedNodeType(String payloadName, User sdncModifierDetails, + ImportReqDetails resourceDetails) throws Exception { + + Path path = Paths.get(rootPath + csarFolderPath + payloadName); + byte[] data = Files.readAllBytes(path); + String payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(ResourceTypeEnum.VFC.name()); + return ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/inputs/InputsApiTests.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/inputs/InputsApiTests.java new file mode 100644 index 0000000000..345b81eb3e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/inputs/InputsApiTests.java @@ -0,0 +1,225 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.inputs; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.Pair; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstInputsMap; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.InputsRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.BaseValidationUtils; +import org.testng.annotations.Test; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import fj.data.Either; + +/** + * CI-Tests for inputs + * @author il0695 + * + */ +public class InputsApiTests extends ComponentBaseTest { + + private static String inputCsar1 = "FCGI_with_inputs.csar"; + private static String inputCsar2 = "LDSA1_with_inputs.csar"; + private static User sdncDesignerDetails = null; + + @Rule + public static TestName name = new TestName(); + + /** + * Constructor + */ + public InputsApiTests() { + super(name, InputsApiTests.class.getName()); + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + } + + /** + * Create VF with inputs from CSAR file + * + * @throws Exception + */ + @Test + public void testCreateResourceInstanceWithInputsFromCsar() throws Exception { + Resource vf = AtomicOperationUtils.importResourceFromCSAR(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, inputCsar1); + assertTrue("Success creating VF from CSAR", !vf.getInputs().isEmpty()); + } + + /** + * Create service and add to it VF instance with inputs + * + * @throws Exception + */ + @Test + public void testAddVfInstanceWithInputsToService() throws Exception { + createServiceWithVFInstanceWithInputs(); + } + + /** + * General test to check most functionality of inputs + *
    + *
  • Create service with VF instance that has inputs)
  • + *
  • Get all inputs of VF instance
  • + *
  • Add inputs to service
  • + *
  • Get service inputs
  • + *
  • Delete service inputs
  • + *
+ * + * @throws Exception + */ + @Test + public void testInputsMainFunctionality() throws Exception { + Service service = createServiceWithVFInstanceWithInputs(); + int totalInputsBeforeAdd = service.getInputs().size(); + + // Get component instances + RestResponse getInstancesResponse = ComponentInstanceRestUtils.getComponentInstances(ComponentTypeEnum.SERVICE, service.getUniqueId(), sdncDesignerDetails); + BaseValidationUtils.checkSuccess(getInstancesResponse); + List serviceInstances = new Gson().fromJson(getInstancesResponse.getResponse(), new TypeToken>(){}.getType()); + + // Get all inputs of first instance + ComponentInstance vfInstance = serviceInstances.get(0); + RestResponse getComponentInstanceInputsResponse = InputsRestUtils.getComponentInstanceInputs(service, vfInstance); + BaseValidationUtils.checkSuccess(getComponentInstanceInputsResponse); + List instanceInputs = new Gson().fromJson(getComponentInstanceInputsResponse.getResponse(), new TypeToken>(){}.getType()); + + // Take only the 2 first inputs + List inputsToAdd = instanceInputs.stream().limit(2).collect(Collectors.toList()); + + // Build component instances input map to add to server + ComponentInstInputsMap buildComponentInstInputsMap = buildComponentInstInputsMap(vfInstance.getUniqueId(), inputsToAdd); + RestResponse addInputResponse = InputsRestUtils.addInput(service, buildComponentInstInputsMap, UserRoleEnum.DESIGNER); + BaseValidationUtils.checkSuccess(addInputResponse); + + // Get service inputs count + RestResponse getComponentInputsResponse = InputsRestUtils.getComponentInputs(service); + BaseValidationUtils.checkSuccess(getComponentInputsResponse); + List serviceInputsAfterAdd = new Gson().fromJson(getComponentInputsResponse.getResponse(), new TypeToken>(){}.getType()); + if (serviceInputsAfterAdd.size()-totalInputsBeforeAdd!=2) { + assertTrue("Error adding inputs to service (service should have 2 inputs)", false); + } + + // Delete 1 input from service + RestResponse deleteInputFromComponentResponse = InputsRestUtils.deleteInputFromComponent(service, serviceInputsAfterAdd.get(0).getUniqueId()); + BaseValidationUtils.checkSuccess(deleteInputFromComponentResponse); + + // Get service inputs count after delete + RestResponse getComponentInputsResponseAfterDelete = InputsRestUtils.getComponentInputs(service); + BaseValidationUtils.checkSuccess(getComponentInputsResponseAfterDelete); + List serviceInputsAfterDelete = new Gson().fromJson(getComponentInputsResponseAfterDelete.getResponse(), new TypeToken>(){}.getType()); + if (serviceInputsAfterDelete.size()-totalInputsBeforeAdd!=1) { + assertTrue("Error deleting inputs from service (service should have 1 input)", false); + } + + assertTrue("Success testing inputs main functionality", true); + } + + /** + * Private method to create service with VF instance that has inputs + * This is private method to be used by multiple tests + * + * @return {@link org.openecomp.sdc.be.model} + * @throws Exception + * @throws IOException + */ + private Service createServiceWithVFInstanceWithInputs() throws Exception, IOException { + // Create default service + Either createDefaultServiceEither = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + if (createDefaultServiceEither.isRight()){ + assertTrue("Error creating default service", false); + } + Service service = createDefaultServiceEither.left().value(); + + // Create VF from CSAR file + Resource vfWithInputs = AtomicOperationUtils.importResourceFromCSAR(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, inputCsar2); + + // Certify VF + Pair changeComponentState = AtomicOperationUtils.changeComponentState(vfWithInputs, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + assertTrue("response code is BaseRestUtils.STATUS_CODE_SUCCESS, returned :" + changeComponentState.getRight().getErrorCode(), changeComponentState.getRight().getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + // Add VF instance to service + Either addComponentInstanceToComponentContainerEither = AtomicOperationUtils.addComponentInstanceToComponentContainer(vfWithInputs, service, UserRoleEnum.DESIGNER, true); + if (addComponentInstanceToComponentContainerEither.isRight()){ + assertTrue("Error adding VF to service", false); + } + + // Get service response + ServiceReqDetails serviceDetails = new ServiceReqDetails(service); + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + + // Get VF instance from service + ComponentInstance vfInstance = service.getComponentInstances().get(0); + if (vfInstance!=null){ + assertTrue("Success creating service with VF instance", true); + } else { + assertTrue("Error creating service with VF instance", false); + } + return service; + } + + /** + * Return default ComponentInstInputsMap + * + * @param addToInput + * @param inputs + * @return {@link org.openecomp.sdc.be.model.ComponentInstInputsMap} + */ + private ComponentInstInputsMap buildComponentInstInputsMap (String addToInput, List inputs) { + Map> map = new HashMap<>(); + map.put(addToInput, inputs); + ComponentInstInputsMap componentInstInputsMap = new ComponentInstInputsMap(); + componentInstInputsMap.setComponentInstanceInputsMap(map); + return componentInstInputsMap; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/lifecycle/LCSbaseTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/lifecycle/LCSbaseTest.java new file mode 100644 index 0000000000..e15652dddf --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/lifecycle/LCSbaseTest.java @@ -0,0 +1,274 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.lifecycle; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; + +import org.apache.log4j.lf5.util.ResourceUtils; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.ArtifactUtils; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.annotations.BeforeMethod; + +/** + * + * @author al714h + * + * resourceDetails - create, Add Heat, certify resourceDetails1 - create + * resource, LCS - CheckOut serviceDetails - create, add RI from + * resourceDetails serviceDetails2 - create, add RI from resourceDetails + * serviceDetailsEmpty - create, LCS - CheckOut serviceDetailsEmpty2 - + * create, LCS - CheckOut + * + */ +public abstract class LCSbaseTest extends ComponentBaseTest { + + protected ResourceReqDetails resourceDetails; + protected ResourceReqDetails resourceDetails1; + protected ServiceReqDetails serviceDetails; + protected ServiceReqDetails serviceDetails2; + protected ServiceReqDetails serviceDetailsEmpty; + protected ServiceReqDetails serviceDetailsEmpty2; + protected ComponentInstanceReqDetails componentInstanceReqDetails; + protected ComponentInstanceReqDetails resourceInstanceReqDetails2; + protected User sdncDesignerDetails1; + protected User sdncDesignerDetails2; + protected static User sdncTesterDeatails1; + protected User sdncAdminDetails1; + protected ArtifactReqDetails heatArtifactDetails; + protected ArtifactReqDetails heatVolArtifactDetails; + protected ArtifactReqDetails heatNetArtifactDetails; + + protected ArtifactReqDetails defaultArtifactDetails; + protected ResourceUtils resourceUtils; + protected ArtifactUtils artifactUtils; + + // protected static ServiceUtils serviceUtils = new ServiceUtils(); + public LCSbaseTest(TestName testName, String className) { + super(testName, className); + } + + @BeforeMethod + public void before() throws Exception { + + initializeMembers(); + + createComponents(); + + } + + public void initializeMembers() throws IOException, Exception { + resourceDetails = ElementFactory.getDefaultResource(); + // resourceDetails = + // ElementFactory.getDefaultResource("myNewResource1234567890", + // NormativeTypesEnum.ROOT, ResourceServiceCategoriesEnum.ROUTERS, + // UserRoleEnum.DESIGNER.getUserId()); + resourceDetails1 = ElementFactory.getDefaultResource("secondResource", NormativeTypesEnum.ROOT); + serviceDetails = ElementFactory.getDefaultService(); + serviceDetails2 = ElementFactory.getDefaultService("newTestService2", ServiceCategoriesEnum.MOBILITY, "al1976"); + serviceDetailsEmpty = ElementFactory.getDefaultService("newEmptyService", ServiceCategoriesEnum.MOBILITY, + "al1976"); + serviceDetailsEmpty2 = ElementFactory.getDefaultService("newEmptyService2", ServiceCategoriesEnum.MOBILITY, + "al1976"); + sdncDesignerDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncDesignerDetails2 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2); + sdncTesterDeatails1 = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + sdncAdminDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + heatNetArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT_NET.getType()); + heatVolArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT_VOL.getType()); + componentInstanceReqDetails = ElementFactory.getDefaultComponentInstance(); + resourceInstanceReqDetails2 = ElementFactory.getDefaultComponentInstance(); + + } + + protected void createComponents() throws Exception { + + RestResponse response = ResourceRestUtils.createResource(resourceDetails1, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("resource uniqueId is null:", resourceDetails1.getUniqueId()); + + response = ResourceRestUtils.createResource(resourceDetails, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("resource uniqueId is null:", resourceDetails.getUniqueId()); + + response = ServiceRestUtils.createService(serviceDetails, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("service uniqueId is null:", serviceDetails.getUniqueId()); + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, + resourceDetails.getUniqueId()); + assertTrue("add HEAT artifact to resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + // certified resource + response = LCSbaseTest.certifyResource(resourceDetails, sdncDesignerDetails1); + assertTrue("certify resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + // add resource instance with HEAT deployment artifact to the service + componentInstanceReqDetails.setComponentUid(resourceDetails.getUniqueId()); + response = ComponentInstanceRestUtils.createComponentInstance(componentInstanceReqDetails, sdncDesignerDetails1, + serviceDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + assertTrue("response code is not 201, returned: " + response.getErrorCode(), response.getErrorCode() == 201); + + response = ServiceRestUtils.createService(serviceDetails2, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("service uniqueId is null:", serviceDetails2.getUniqueId()); + + componentInstanceReqDetails.setComponentUid(resourceDetails.getUniqueId()); + response = ComponentInstanceRestUtils.createComponentInstance(componentInstanceReqDetails, sdncDesignerDetails1, + serviceDetails2.getUniqueId(), ComponentTypeEnum.SERVICE); + assertTrue("response code is not 201, returned: " + response.getErrorCode(), response.getErrorCode() == 201); + + response = ServiceRestUtils.createService(serviceDetailsEmpty, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("service uniqueId is null:", serviceDetailsEmpty.getUniqueId()); + + response = ServiceRestUtils.createService(serviceDetailsEmpty2, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("service uniqueId is null:", serviceDetailsEmpty2.getUniqueId()); + + DbUtils.cleanAllAudits(); + + } + + public static RestResponse certifyResource(ResourceReqDetails resourceDetails, User user) throws Exception { + RestResponse restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, user.getUserId(), + LifeCycleStatesEnum.CHECKIN); + // if (restResponseResource.getErrorCode() == 200){ + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, user.getUserId(), + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + // }else + // return restResponseResource; + sdncTesterDeatails1 = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + if (restResponseResource.getErrorCode() == 200) { + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, + sdncTesterDeatails1.getUserId(), LifeCycleStatesEnum.STARTCERTIFICATION); + } else + return restResponseResource; + if (restResponseResource.getErrorCode() == 200) { + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, + sdncTesterDeatails1.getUserId(), LifeCycleStatesEnum.CERTIFY); + } + return restResponseResource; + } + + public static RestResponse certifyService(ServiceReqDetails serviceDetails, User user) throws Exception { + RestResponse restResponseService = LifecycleRestUtils.changeServiceState(serviceDetails, user, + LifeCycleStatesEnum.CHECKIN); + // if (restResponseService.getErrorCode() == 200){ + restResponseService = LifecycleRestUtils.changeServiceState(serviceDetails, user, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + // }else + // return restResponseService; + + sdncTesterDeatails1 = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + if (restResponseService.getErrorCode() == 200) { + restResponseService = LifecycleRestUtils.changeServiceState(serviceDetails, sdncTesterDeatails1, + LifeCycleStatesEnum.STARTCERTIFICATION); + } else + return restResponseService; + if (restResponseService.getErrorCode() == 200) { + restResponseService = LifecycleRestUtils.changeServiceState(serviceDetails, sdncTesterDeatails1, + LifeCycleStatesEnum.CERTIFY); + } + return restResponseService; + } + + protected static RestResponse raiseResourceToTargetVersion(ResourceReqDetails resourceDetails, String targetVersion, + User user) throws Exception { + return raiseResourceToTargetVersion(resourceDetails, targetVersion, null, user); + } + + protected static RestResponse raiseResourceToTargetVersion(ResourceReqDetails resourceDetails, String targetVersion, + RestResponse prevResponse, User user) throws Exception { + + String[] splitParts = targetVersion.split("\\."); + + int version = Integer.parseInt(splitParts[1]); + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + + if (prevResponse != null) { + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(prevResponse.getResponse()); + if (resourceRespJavaObject.getLifecycleState().equals(LifecycleStateEnum.CERTIFIED)) { + RestResponse restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, + user.getUserId(), LifeCycleStatesEnum.CHECKOUT); + } + } + + RestResponse restResponseResource = null; + for (int i = 0; i < (version - 1); i++) { + + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, user, null, + LifeCycleStatesEnum.CHECKIN, checkinComentJson); + if (restResponseResource.getErrorCode() == 200) { + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, user.getUserId(), + LifeCycleStatesEnum.CHECKOUT); + if (restResponseResource.getErrorCode() == 200) { + + } else + break; + + } else + break; + + } + + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, user, null, + LifeCycleStatesEnum.CHECKIN, checkinComentJson); + assertEquals("Check response code ", 200, restResponseResource.getErrorCode().intValue()); + return restResponseResource; + } + +} diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ChangeServiceInstanceVersionTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ChangeServiceInstanceVersionTest.java similarity index 100% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ChangeServiceInstanceVersionTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ChangeServiceInstanceVersionTest.java diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductBaseTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductBaseTest.java similarity index 100% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductBaseTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductBaseTest.java diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckinTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckinTest.java similarity index 100% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckinTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckinTest.java diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckoutTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckoutTest.java similarity index 100% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckoutTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCheckoutTest.java diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductComponentInstanceCRUDTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductComponentInstanceCRUDTest.java similarity index 97% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductComponentInstanceCRUDTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductComponentInstanceCRUDTest.java index fe5a6e34f9..596825875d 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductComponentInstanceCRUDTest.java +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductComponentInstanceCRUDTest.java @@ -266,9 +266,9 @@ public class ProductComponentInstanceCRUDTest extends ComponentInstanceBaseTest // pass @Test public void createServiceInstanceNameIsNull() throws Exception { - String expectedServiceInstanceName = serviceDetails_01.getName() + " 1"; - String expectedServiceInstancenormalizedName = serviceDetails_01.getName() + "1"; serviceDetails_01.setName(null); + String expectedServiceInstanceName = (serviceDetails_01.getName() != null ? serviceDetails_01.getName() : "resourceInstanceName") + " 1"; + String expectedServiceInstancenormalizedName = (serviceDetails_01.getName() != null ? serviceDetails_01.getName() : "resourceInstanceName") + "1"; RestResponse createServiceInstanceResp = createServiceInstance(productDetails_01, serviceDetails_01, sdncPmDetails1); ResourceRestUtils.checkCreateResponse(createServiceInstanceResp); String instanceNormalizedName = ResponseParser.getValueFromJsonResponse(createServiceInstanceResp.getResponse(), "normalizedName"); @@ -435,8 +435,8 @@ public class ProductComponentInstanceCRUDTest extends ComponentInstanceBaseTest ComponentInstanceReqDetails serviceInstanceReqDetails = ElementFactory.getComponentResourceInstance(serviceDetails_01); RestResponse createServiceInstanceResp = ComponentInstanceRestUtils.createComponentInstance(serviceInstanceReqDetails, sdncPmDetails1, productDetails_01.getUniqueId(), ComponentTypeEnum.PRODUCT); ResourceRestUtils.checkCreateResponse(createServiceInstanceResp); - String newName = "qwer-TYUIOP_asd_0987654321.Abcd"; - String ExpectedNormalizName = "qwertyuiopasd0987654321abcd"; + String newName = "cier-TYUIOP_asd_0987654321.Abcd"; + String ExpectedNormalizName = "ciertyuiop_asd_0987654321abcd"; serviceInstanceReqDetails.setName(newName); RestResponse updateServiceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance(serviceInstanceReqDetails, sdncPmDetails1, productDetails_01.getUniqueId(), ComponentTypeEnum.PRODUCT); ResourceRestUtils.checkSuccess(updateServiceInstanceResponse); @@ -501,13 +501,13 @@ public class ProductComponentInstanceCRUDTest extends ComponentInstanceBaseTest ResourceRestUtils.checkCreateResponse(createServiceInstanceResp); String expectedName = ResponseParser.getValueFromJsonResponse(createServiceInstanceResp.getResponse(), "name"); String expectedNormalizedName = ResponseParser.getValueFromJsonResponse(createServiceInstanceResp.getResponse(), "normalizedName"); - String newName = "Qwertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456"; + String newName = "Ciertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ciertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ciertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ciertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ciertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ciertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ciertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ciertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ciertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456Ahjklzxcvbnmasdfghjkl123456"; serviceInstanceReqDetails.setName(newName); RestResponse updateServiceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance(serviceInstanceReqDetails, sdncPmDetails1, productDetails_01.getUniqueId(), ComponentTypeEnum.PRODUCT); assertEquals("Check response code ", STATUS_CODE_COMPONENT_NAME_EXCEEDS_LIMIT, updateServiceInstanceResponse.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add("Service Instance"); - varibales.add("50"); + varibales.add("1024"); ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_NAME_EXCEEDS_LIMIT.name(), varibales, updateServiceInstanceResponse.getResponse()); // get product and verify that service instanceName is correct RestResponse getActualProductResponse = ProductRestUtils.getProduct(productDetails_01.getUniqueId(), sdncPmDetails1.getUserId()); @@ -556,8 +556,8 @@ public class ProductComponentInstanceCRUDTest extends ComponentInstanceBaseTest ResourceRestUtils.checkSuccess(updateServiceInstanceResponse); String instanceNormalizedName = ResponseParser.getValueFromJsonResponse(updateServiceInstanceResponse.getResponse(), "normalizedName"); String instanceName = ResponseParser.getValueFromJsonResponse(updateServiceInstanceResponse.getResponse(), "name"); - assertEquals("check Resource Instance normalizedName ", (serviceDetails_01.getName() + "2").toLowerCase(), instanceNormalizedName); - assertEquals("check Resource Instance normalizedName ", (serviceDetails_01.getName() + " 2"), instanceName); + assertEquals("check Resource Instance normalizedName ", (serviceDetails_01.getName() + "1").toLowerCase(), instanceNormalizedName); + assertEquals("check Resource Instance normalizedName ", (serviceDetails_01.getName() + " 1"), instanceName); // get product and verify that service instanceName is correct RestResponse getActualProductResponse = ProductRestUtils.getProduct(productDetails_01.getUniqueId(), sdncPmDetails1.getUserId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getActualProductResponse.getResponse(), Product.class); @@ -683,7 +683,7 @@ public class ProductComponentInstanceCRUDTest extends ComponentInstanceBaseTest assertEquals(nameFromResponse, actualComponentInstance.getName()); } - @Test + @Test (enabled = false) public void updateServiceInstanceLocationNameIsEmpty() throws Exception { String expectedServiceInstanceName = serviceDetails_01.getName() + " 2"; String expectedServiceInstancenormalizedName = serviceDetails_01.getName() + "2"; diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCreateWithValidationsTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCreateWithValidationsTest.java similarity index 95% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCreateWithValidationsTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCreateWithValidationsTest.java index 7ac24bdd69..45d3b23983 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCreateWithValidationsTest.java +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCreateWithValidationsTest.java @@ -61,10 +61,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { super(name, ProductCreateWithValidationsTest.class.getName()); } - @Test + @Test // (enabled = false) public void createProductSuccessValidation() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); @@ -88,7 +88,7 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { @Test public void createProductNotByPmUser() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); normalizedName = productReqDetails.getName().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productStrategistUser1); assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, @@ -110,7 +110,7 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { nonAsdcUser.setFirstName(null); nonAsdcUser.setLastName(null); ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); normalizedName = productReqDetails.getName().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, nonAsdcUser); assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, @@ -132,7 +132,7 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { nonAsdcUser.setFirstName(null); nonAsdcUser.setLastName(null); ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); normalizedName = productReqDetails.getName().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, nonAsdcUser); assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_MISSING_INFORMATION, @@ -164,11 +164,11 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductNameValidationMaxLength() throws Exception { // Max length = 25 ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Qwertyuiop1234567890asdfA"); +// productReqDetails.setName("Qwertyuiop1234567890asdfA"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); @@ -228,17 +228,17 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductNameAlreadyExist() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); - // productReqDetails.setName("ProDuct1"); + // // productReqDetails.setName("CIProduct1"); DbUtils.deleteFromEsDbByPattern("_all"); createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_ALREADY_EXISTS, @@ -274,18 +274,18 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { } // DE193857 - @Test(enabled = false) + @Test (enabled = false) public void createProductNameValidationAllowedCharacters() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Ac_2@3:4& m=n+b-u.j-u'g#b"); // Bug @:&=+'# - normalizedName = "ac234mnbujugb"; - String expectedProductName = "Ac_2@3:4& M=n+b-u.j-u'g#b"; + productReqDetails.setName("Ci_2@3:4& m=n+b-u.j-u'g#b"); // Bug @:&=+'# + normalizedName = "ci234mnbujugb"; + String expectedProductName = "Ci_2@3:4& M=n+b-u.j-u'g#b"; productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); String productUuid = ResponseParser.getUuidFromResponse(createProduct); productReqDetails.setName(expectedProductName); - productReqDetails.setName("Ac_2@3:4& M=n+b-u.j-u'g#b"); + productReqDetails.setName("Ci_2@3:4& M=n+b-u.j-u'g#b"); compareExpectedAndActualProducts(productReqDetails, createProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setNormalizedName(normalizedName); @@ -303,15 +303,15 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { } // DE193857 - @Test(enabled = false) + @Test public void createProductNameValidationREmoveExtraNonAlphanumericChars() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Ac____222----333......asd"); - productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); + productReqDetails.setName("Ci____222----333......asd"); +// productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); - productReqDetails.setName("Ac_222-333.asd"); - normalizedName = "ac222333asd"; + productReqDetails.setName("Ci_222-333.asd"); + normalizedName = "ci222333asd"; String productUuid = ResponseParser.getUuidFromResponse(createProduct); compareExpectedAndActualProducts(productReqDetails, createProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); @@ -370,15 +370,17 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { } } - @Test(enabled = false) + // Already enabled = false + @Test public void createProductNameValidationRemoveSpaceFromBeginning() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName(" Qwertyuiop1234567890asdfA"); - productReqDetails.setTags(Arrays.asList(productReqDetails.getName().trim())); + productReqDetails.setName(" Ciertyuiop1234567890asdfA"); +// productReqDetails.setTags(Arrays.asList(productReqDetails.getName().trim())); normalizedName = productReqDetails.getName().trim().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); String productUuid = ResponseParser.getUuidFromResponse(createProduct); + productReqDetails.setName(" Ciertyuiop1234567890asdfA".trim()); compareExpectedAndActualProducts(productReqDetails, createProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), @@ -394,15 +396,17 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test(enabled = false) + // Already enabled = false + @Test public void createProductNameValidationRemoveSpaceFromTheEnd() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Qwertyuiop1234567890asdfA "); - productReqDetails.setTags(Arrays.asList(productReqDetails.getName().trim())); + productReqDetails.setName("Ciertyuiop1234567890asdfA "); +// productReqDetails.setTags(Arrays.asList(productReqDetails.getName().trim())); normalizedName = productReqDetails.getName().trim().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); String productUuid = ResponseParser.getUuidFromResponse(createProduct); + productReqDetails.setName("Ciertyuiop1234567890asdfA ".trim()); compareExpectedAndActualProducts(productReqDetails, createProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), @@ -422,7 +426,7 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { public void createProductNameValidationStartWithNumber() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); productReqDetails.setName("1Qwert"); - productReqDetails.setTags(Arrays.asList(productReqDetails.getName().trim())); +// productReqDetails.setTags(Arrays.asList(productReqDetails.getName().trim())); normalizedName = productReqDetails.getName().trim().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); @@ -440,6 +444,9 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { expectedProduct, CREATE_AUDIT_ACTION, productManager1, ActionStatus.CREATED, Constants.EMPTY_STRING, "0.1", null, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, productUuid); AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); + productReqDetails.setName("Ci1Qwert"); + RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); + } @Test @@ -461,15 +468,15 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductNameValidationFirstLetterOfKeyWordsCapitalized() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); // productReqDetails.setTags(Arrays.asList("abba")); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); - // productReqDetails.setName("Abba"); + // // productReqDetails.setName("Abba"); /* * String actualNormalizedNameFromResponse = * ResponseParser.getValueFromJsonResponse(createProduct.getResponse(), @@ -542,10 +549,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductFullNameHasMinLength() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setFullName("abcd"); @@ -567,10 +574,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductFullNameHasMaxLength() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setFullName( @@ -593,10 +600,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductFullNameExceedMaxLength() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setFullName( @@ -614,10 +621,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductFullNameRemoveExtraSpaces() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setFullName("Abbaaa a1"); @@ -672,10 +679,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test (enabled = false) public void createProductDescriptionValidCharacters01() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setDescription("qwertyuiopasdfghjklzxcvbnm1234567890Bold<"); @@ -698,10 +705,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test (enabled = false) public void createProductDescriptionValidCharacters02() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setDescription("~!@#$%^&*()_+<>?qwertyuiopasdfghjklzxcvbnm1234567890#"); @@ -724,10 +731,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductDescriptionInValidCharacters() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setDescription("מה"); @@ -743,10 +750,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test (enabled = false) public void createProductDescriptionRemoveSpacesFromBeginning() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setDescription(" abcd12345"); @@ -769,10 +776,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test (enabled = false) public void createProductDescriptionRemoveSpacesFromTheEnd() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setDescription("abcd 12345 xcvb "); @@ -795,10 +802,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductDescriptionMaxLength() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setDescription( @@ -821,10 +828,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductDescriptionExceedMaxLength() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba"); + // productReqDetails.setName("Abba"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setDescription( @@ -860,10 +867,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { } // DE192351 - @Test + @Test // (enabled = false) public void createProductTagValidationAllowedCharacters() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); // Bug @:&=+'# + // productReqDetails.setName("CIProduct1"); // Bug @:&=+'# productReqDetails.setTags(Arrays.asList(productReqDetails.getName(), "Acde2@3:4& m=n+b-u.j-u'g#b")); normalizedName = productReqDetails.getName().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); @@ -884,10 +891,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductTagsNameValidationProductNameIsNotInTag() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Qwertyuiop1234567890asdfA"); +// productReqDetails.setName("Qwertyuiop1234567890asdfA"); productReqDetails.setTags(Arrays.asList("Abc")); normalizedName = productReqDetails.getName().trim().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); @@ -902,11 +909,11 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductSingleTagMaxLength() throws Exception { // SingleTagMaxLength = 50 ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags( Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345678")); normalizedName = productReqDetails.getName().toLowerCase(); @@ -928,10 +935,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test (enabled = false) public void createProductSingleTagExceedMaxLength() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); // Bug @:&=+'# + // productReqDetails.setName("CIProduct1"); // Bug @:&=+'# productReqDetails.setTags( Arrays.asList(productReqDetails.getName(), "Axbba1234567890asdfghjkl123zxcvbnm432asdfgh12345678")); normalizedName = productReqDetails.getName().toLowerCase(); @@ -947,11 +954,11 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test (enabled = false) public void createProductAllTagsMaxLength() throws Exception { // AllTagsMaxLength = 1024 ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags( Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345601", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345602", @@ -996,7 +1003,7 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { public void createProductAllTagsExceedMaxLength() throws Exception { // AllTagsMaxLength = 1024 ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags( Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345601", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345602", @@ -1031,10 +1038,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductDuplicateTagRemoved() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); // Bug @:&=+'# + // productReqDetails.setName("CIProduct1"); // Bug @:&=+'# productReqDetails.setTags(Arrays.asList(productReqDetails.getName(), productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); @@ -1056,10 +1063,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductContactsIsEmpty() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); // Bug @:&=+'# + // productReqDetails.setName("CIProduct1"); // Bug @:&=+'# productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); productReqDetails.setContacts(Arrays.asList("")); @@ -1075,10 +1082,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductContactsInvalidFormat() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); // Bug @:&=+'# + // productReqDetails.setName("CIProduct1"); // Bug @:&=+'# productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); productReqDetails.setContacts(Arrays.asList("bt750345")); @@ -1094,10 +1101,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductConvertContactsToLowerCase() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); // Bug @:&=+'# + // productReqDetails.setName("CIProduct1"); // Bug @:&=+'# productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); productReqDetails.setContacts(Arrays.asList(productManager1.getUserId().toUpperCase())); @@ -1120,10 +1127,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductContactsDoexNotContainTheProductCreator() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); // Bug @:&=+'# + // productReqDetails.setName("CIProduct1"); // Bug @:&=+'# productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); productReqDetails.setContacts(Arrays.asList(productManager2.getUserId())); @@ -1145,10 +1152,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductContactsNotAllowedAsdcUsers() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); // Bug @:&=+'# + // productReqDetails.setName("CIProduct1"); // Bug @:&=+'# productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); productReqDetails.setContacts(Arrays.asList(designerUser.getUserId())); @@ -1165,10 +1172,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductContactsNotAsdcUser() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); // Bug @:&=+'# + // productReqDetails.setName("CIProduct1"); // Bug @:&=+'# productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase(); String nonAsdcUser = "bh1234"; @@ -1185,10 +1192,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductProjectCodeIsEmpty() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setProjectCode(""); @@ -1204,10 +1211,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductProjectCodeIsNull() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setProjectCode(null); @@ -1223,10 +1230,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductProjectCodeIsNotNumeric() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setProjectCode("asdfgh"); @@ -1242,11 +1249,11 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductProjectCodeHasnMinCharacters() throws Exception { // Min =5 ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setProjectCode("12345"); @@ -1267,11 +1274,11 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductProjectCodeHasnMaxCharacters() throws Exception { // Max =10 ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setProjectCode("1234567890"); @@ -1292,11 +1299,11 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductProjectCodeExceedMaxCharacters() throws Exception { // Max =10 ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setProjectCode("12345678901"); @@ -1312,11 +1319,11 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductProjectCodeLessThanMinCharacters() throws Exception { // Max =10 ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setProjectCode("1234"); @@ -1332,10 +1339,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductIconIsEmpty() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setIcon(""); @@ -1351,10 +1358,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductIconIsNull() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setIcon(null); @@ -1370,10 +1377,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductIconMaxLength() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setIcon("asdfghjklqwertyuiozxcvbfv"); @@ -1394,10 +1401,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductIconExceedMaxLength() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setIcon("asdfghjklqwertyuiozxcvbf12"); @@ -1413,10 +1420,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductIconAllowedCharacters() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setIcon("a--s-fghjk_q__r1234567890"); @@ -1437,10 +1444,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test (enabled = false) public void createProductIconInValidCharacters() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); String icon = "asdfg"; @@ -1463,10 +1470,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { } } - @Test + @Test // (enabled = false) public void createProductIsActiveisEmpty() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setActive(""); @@ -1488,10 +1495,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductIsActiveisNull() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setActive(""); @@ -1514,10 +1521,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductIsActiveisFalse() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setActive("false"); @@ -1541,7 +1548,7 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { @Test public void createProductIsActiveisHasInvalidValue() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setActive("xfalse"); @@ -1558,10 +1565,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } - @Test + @Test // (enabled = false) public void createProductIsActiveisTrue() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Product1"); + // productReqDetails.setName("CIProduct1"); productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); productReqDetails.setActive("true"); @@ -1584,10 +1591,10 @@ public class ProductCreateWithValidationsTest extends ProductBaseTest { ////////////////////////////////////////////// // DE192424 - @Test + @Test // (enabled = false) public void createProductNameValidationNormalizationNameWithSpaces() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); - productReqDetails.setName("Abba Emma"); +// productReqDetails.setName("Abba Emma"); // productReqDetails.setName("abba emma"); // productReqDetails.setTags(Arrays.asList("abba emma")); normalizedName = productReqDetails.getName().toLowerCase().replaceAll("\\s+", ""); diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCrudTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCrudTest.java similarity index 80% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCrudTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCrudTest.java index d91391d967..2044d213e6 100644 --- a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCrudTest.java +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductCrudTest.java @@ -95,10 +95,12 @@ public class ProductCrudTest extends ProductBaseTest { private void createProductAndGet(UserRoleEnum user) throws Exception, IOException { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, createProduct.getErrorCode().intValue()); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, + createProduct.getErrorCode().intValue()); RestResponse catalog = CatalogRestUtils.getCatalog(user.getUserId()); - assertEquals("Check response code after get catalog", BaseRestUtils.STATUS_CODE_SUCCESS, catalog.getErrorCode().intValue()); + assertEquals("Check response code after get catalog", BaseRestUtils.STATUS_CODE_SUCCESS, + catalog.getErrorCode().intValue()); try { JsonElement jElement = new JsonParser().parse(catalog.getResponse()); @@ -124,7 +126,8 @@ public class ProductCrudTest extends ProductBaseTest { public void getAllNoProcduts() throws Exception { RestResponse catalog = CatalogRestUtils.getCatalog(); - assertEquals("Check response code after get catalog", BaseRestUtils.STATUS_CODE_SUCCESS, catalog.getErrorCode().intValue()); + assertEquals("Check response code after get catalog", BaseRestUtils.STATUS_CODE_SUCCESS, + catalog.getErrorCode().intValue()); try { JsonElement jElement = new JsonParser().parse(catalog.getResponse()); @@ -145,17 +148,21 @@ public class ProductCrudTest extends ProductBaseTest { headersToRemove.add(HttpHeaderEnum.USER_ID.getValue()); RestResponse catalog = CatalogRestUtils.sendGetAndRemoveHeaders(url, null, headersToRemove); - assertEquals("Check response code after get catalog", BaseRestUtils.STATUS_CODE_MISSING_INFORMATION, catalog.getErrorCode().intValue()); + assertEquals("Check response code after get catalog", BaseRestUtils.STATUS_CODE_MISSING_INFORMATION, + catalog.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_INFORMATION.name(), new ArrayList(), catalog.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_INFORMATION.name(), new ArrayList(), + catalog.getResponse()); } @Test public void getAllWrongUser() throws Exception { RestResponse catalog = CatalogRestUtils.getCatalog("kj8976"); - assertEquals("Check response code after get catalog", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, catalog.getErrorCode().intValue()); + assertEquals("Check response code after get catalog", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + catalog.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), catalog.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + catalog.getResponse()); } @Test // (enabled=false) @@ -211,10 +218,13 @@ public class ProductCrudTest extends ProductBaseTest { User emptyUser = new User(); emptyUser.setUserId(""); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, emptyUser); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_MISSING_INFORMATION, createProduct.getErrorCode().intValue()); - Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, emptyUser); - ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation(expectedProduct, CREATE_AUDIT_ACTION, emptyUser, ActionStatus.MISSING_INFORMATION, Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, - null, Constants.EMPTY_STRING); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_MISSING_INFORMATION, + createProduct.getErrorCode().intValue()); + Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, + emptyUser); + ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation( + expectedProduct, CREATE_AUDIT_ACTION, emptyUser, ActionStatus.MISSING_INFORMATION, + Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, null, Constants.EMPTY_STRING); constructFieldsForAuditValidation.setCURR_STATE(""); AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } @@ -225,10 +235,13 @@ public class ProductCrudTest extends ProductBaseTest { User notExistingUser = new User(); notExistingUser.setUserId("jj6444"); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, notExistingUser); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, createProduct.getErrorCode().intValue()); - Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, notExistingUser); - ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation(expectedProduct, CREATE_AUDIT_ACTION, notExistingUser, ActionStatus.RESTRICTED_OPERATION, Constants.EMPTY_STRING, Constants.EMPTY_STRING, - null, null, Constants.EMPTY_STRING); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + createProduct.getErrorCode().intValue()); + Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, + notExistingUser); + ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation( + expectedProduct, CREATE_AUDIT_ACTION, notExistingUser, ActionStatus.RESTRICTED_OPERATION, + Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, null, Constants.EMPTY_STRING); constructFieldsForAuditValidation.setCURR_STATE(""); AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } @@ -237,10 +250,13 @@ public class ProductCrudTest extends ProductBaseTest { public void createProductInvalidJson() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); RestResponse createProduct = ProductRestUtils.createProduct_Invalid_Json(productManager1.getUserId()); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, createProduct.getErrorCode().intValue()); - Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, productManager1); - ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation(expectedProduct, CREATE_AUDIT_ACTION, productManager1, ActionStatus.INVALID_CONTENT, Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, - null, Constants.EMPTY_STRING); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + createProduct.getErrorCode().intValue()); + Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, + productManager1); + ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation( + expectedProduct, CREATE_AUDIT_ACTION, productManager1, ActionStatus.INVALID_CONTENT, + Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, null, Constants.EMPTY_STRING); constructFieldsForAuditValidation.setRESOURCE_NAME(""); constructFieldsForAuditValidation.setCURR_STATE(""); AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); @@ -251,10 +267,13 @@ public class ProductCrudTest extends ProductBaseTest { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); User wrongRole = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, wrongRole); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, createProduct.getErrorCode().intValue()); - Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, wrongRole); - ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation(expectedProduct, CREATE_AUDIT_ACTION, wrongRole, ActionStatus.RESTRICTED_OPERATION, Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, - null, Constants.EMPTY_STRING); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + createProduct.getErrorCode().intValue()); + Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, + wrongRole); + ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation( + expectedProduct, CREATE_AUDIT_ACTION, wrongRole, ActionStatus.RESTRICTED_OPERATION, + Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, null, Constants.EMPTY_STRING); constructFieldsForAuditValidation.setCURR_STATE(""); AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } @@ -264,10 +283,13 @@ public class ProductCrudTest extends ProductBaseTest { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); User wrongRole = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST3); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, wrongRole); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, createProduct.getErrorCode().intValue()); - Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, wrongRole); - ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation(expectedProduct, CREATE_AUDIT_ACTION, wrongRole, ActionStatus.RESTRICTED_OPERATION, Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, - null, Constants.EMPTY_STRING); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + createProduct.getErrorCode().intValue()); + Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, + wrongRole); + ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation( + expectedProduct, CREATE_AUDIT_ACTION, wrongRole, ActionStatus.RESTRICTED_OPERATION, + Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, null, Constants.EMPTY_STRING); constructFieldsForAuditValidation.setCURR_VERSION(""); constructFieldsForAuditValidation.setCURR_STATE(""); AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); @@ -277,14 +299,18 @@ public class ProductCrudTest extends ProductBaseTest { public void getProductSuccessFlow() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, createProduct.getErrorCode().intValue()); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, + createProduct.getErrorCode().intValue()); - RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); - assertEquals("Check response code after getting created Product", BaseRestUtils.STATUS_CODE_SUCCESS, getProductRes.getErrorCode().intValue()); + RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); + assertEquals("Check response code after getting created Product", BaseRestUtils.STATUS_CODE_SUCCESS, + getProductRes.getErrorCode().intValue()); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProductRes.getResponse(), Product.class); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.GET_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.GET_COMPONENT); } @Test // (enabled=false) @@ -292,19 +318,26 @@ public class ProductCrudTest extends ProductBaseTest { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, createProduct.getErrorCode().intValue()); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, + createProduct.getErrorCode().intValue()); - RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); - assertEquals("Check response code after getting created Product", BaseRestUtils.STATUS_CODE_SUCCESS, getProductRes.getErrorCode().intValue()); + RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); + assertEquals("Check response code after getting created Product", BaseRestUtils.STATUS_CODE_SUCCESS, + getProductRes.getErrorCode().intValue()); Product product = ResponseParser.parseToObjectUsingMapper(getProductRes.getResponse(), Product.class); - assertEquals("Assert on product icon", "Product1", product.getName()); + assertEquals("Assert on product icon", productReqDetails.getName(), product.getName()); - RestResponse deleteProductRes = ProductRestUtils.deleteProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); - assertEquals("Check response code for deletign Product", BaseRestUtils.STATUS_CODE_SUCCESS, deleteProductRes.getErrorCode().intValue()); + RestResponse deleteProductRes = ProductRestUtils.deleteProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); + assertEquals("Check response code for deletign Product", BaseRestUtils.STATUS_CODE_SUCCESS, + deleteProductRes.getErrorCode().intValue()); - RestResponse getProductAfterDeleteRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); - assertEquals("Check response code after getting deleted Product", BaseRestUtils.STATUS_CODE_NOT_FOUND, getProductAfterDeleteRes.getErrorCode().intValue()); + RestResponse getProductAfterDeleteRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); + assertEquals("Check response code after getting deleted Product", BaseRestUtils.STATUS_CODE_NOT_FOUND, + getProductAfterDeleteRes.getErrorCode().intValue()); } @Test // (enabled=false) @@ -312,11 +345,14 @@ public class ProductCrudTest extends ProductBaseTest { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, createProduct.getErrorCode().intValue()); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, + createProduct.getErrorCode().intValue()); productManager1.setUserId(null); - RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); - assertEquals("Check response code after getting created Producuct with UserId extracted from header", BaseRestUtils.STATUS_CODE_MISSING_INFORMATION, getProductRes.getErrorCode().intValue()); + RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); + assertEquals("Check response code after getting created Producuct with userId extracted from header", + BaseRestUtils.STATUS_CODE_MISSING_INFORMATION, getProductRes.getErrorCode().intValue()); } @@ -324,21 +360,27 @@ public class ProductCrudTest extends ProductBaseTest { public void getProductNonExistingUser() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, createProduct.getErrorCode().intValue()); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, + createProduct.getErrorCode().intValue()); productManager1.setUserId("bt1111"); - RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); - assertEquals("Check response code after getting created Producuct with non exsisting user", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, getProductRes.getErrorCode().intValue()); + RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); + assertEquals("Check response code after getting created Producuct with non exsisting user", + BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, getProductRes.getErrorCode().intValue()); } @Test // (enabled=false) public void createProductAndGetProductWithDifferentUser() throws Exception { ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, createProduct.getErrorCode().intValue()); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, + createProduct.getErrorCode().intValue()); User sdncProductStrategistUserAdminDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); - RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), sdncProductStrategistUserAdminDetails.getUserId()); - assertEquals("Check response code after getting created Product different user role", BaseRestUtils.STATUS_CODE_SUCCESS, getProductRes.getErrorCode().intValue()); + RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + sdncProductStrategistUserAdminDetails.getUserId()); + assertEquals("Check response code after getting created Product different user role", + BaseRestUtils.STATUS_CODE_SUCCESS, getProductRes.getErrorCode().intValue()); } // US594753 - Update Product metadata @@ -348,7 +390,8 @@ public class ProductCrudTest extends ProductBaseTest { @Test(enabled = false) public void updateProductAllFieldsByPM() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); // Update product productReqDetails.setUniqueId(product.getUniqueId()); @@ -357,7 +400,8 @@ public class ProductCrudTest extends ProductBaseTest { List addSecondGroupingToDefaultCategory = addSecondGroupingToDefaultCategory(); productReqDetails.setFullName("New Full name"); productReqDetails.setActive("false"); - productReqDetails.setContacts(Arrays.asList(productManager2.getUserId().toLowerCase(), productManager1.getUserId().toLowerCase())); + productReqDetails.setContacts( + Arrays.asList(productManager2.getUserId().toLowerCase(), productManager1.getUserId().toLowerCase())); productReqDetails.setDescription("New Product Description"); productReqDetails.setIcon("asdfghjklqwertyuiozxcvbfv"); productReqDetails.setProjectCode("98765"); @@ -374,53 +418,64 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setUUID(product.getUUID()); expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setNormalizedName(productReqDetails.getName().toLowerCase()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductByPS() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setDescription("New discription"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productStrategistUser1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updateProduct.getResponse()); } @Test // (enabled=false) public void updateProductByAdmin() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setDescription("New discription"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, designerUser); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updateProduct.getResponse()); } @Test // (enabled=false) public void updateProductByNonPmUser() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); // Update product name productReqDetails.setDescription("New discription"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, designerUser); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updateProduct.getResponse()); } @Test // (enabled=false) public void updateProductByNonAsdcUser() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -429,14 +484,17 @@ public class ProductCrudTest extends ProductBaseTest { User nonAsdcUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); nonAsdcUser.setUserId("bt789k"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, nonAsdcUser); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updateProduct.getResponse()); } @Test // (enabled=false) public void updateProductUserIdIsEmpty() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -445,8 +503,10 @@ public class ProductCrudTest extends ProductBaseTest { User nonAsdcUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); nonAsdcUser.setUserId(""); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, nonAsdcUser); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_MISSING_INFORMATION, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_INFORMATION.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_MISSING_INFORMATION, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_INFORMATION.name(), new ArrayList(), + updateProduct.getResponse()); } @Test // (enabled=false) @@ -459,14 +519,18 @@ public class ProductCrudTest extends ProductBaseTest { productReqDetails.setUUID(product.getUUID()); productReqDetails.setDescription("New discription"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager2); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.GET_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.GET_COMPONENT); } @Test // (enabled=false) @@ -475,53 +539,65 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); Product product = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKIN); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKIN); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); // Update product name RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); - String valueFromJsonResponse = ResponseParser.getValueFromJsonResponse(changeProductLifeCycle.getResponse(), "lastUpdateDate"); + String valueFromJsonResponse = ResponseParser.getValueFromJsonResponse(changeProductLifeCycle.getResponse(), + "lastUpdateDate"); expectedProduct.setLastUpdateDate(Long.parseLong(valueFromJsonResponse)); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductNameIsEmpty() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setName(""); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add("abbreviated"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductNameIsNull() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager2, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager2, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); // List tags = productReqDetails.getTags(); // tags.removeAll(tags); @@ -537,31 +613,37 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setNormalizedName(product.getName().toLowerCase()); expectedProduct.setName(product.getName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductNameLessThanMinLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setName("ABC"); // no update will be performed RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add("abbreviated"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH.name(), + varibales, updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } // If user update "product name" we need to remove the old product name from @@ -569,7 +651,8 @@ public class ProductCrudTest extends ProductBaseTest { @Test(enabled = false) public void updateProductNameHasMinLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager2, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager2, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -584,7 +667,8 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setUUID(product.getUUID()); expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setNormalizedName(productReqDetails.getName().toLowerCase()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } // If user update "product name" we need to remove the old product name from @@ -593,7 +677,8 @@ public class ProductCrudTest extends ProductBaseTest { @Test(enabled = false) public void updateProductNameMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); // Update product name productReqDetails.setUniqueId(product.getUniqueId()); @@ -612,31 +697,37 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setNormalizedName(newNormalizedName); expectedProduct.setName(newName); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductNameExceedMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setName("Ac_2B3U4k mSKnob-u.j-uGgPx"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add("abbreviated"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH.name(), + varibales, updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) @@ -645,34 +736,41 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager2); ProductRestUtils.checkCreateResponse(createProduct); Product product1 = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product1, productManager2, LifeCycleStatesEnum.CHECKIN); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product1, productManager2, + LifeCycleStatesEnum.CHECKIN); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setName("Product2000"); // productReqDetails.setTags(Arrays.asList(productReqDetails.getName())); createProduct = ProductRestUtils.createProduct(productReqDetails, productManager2); ProductRestUtils.checkCreateResponse(createProduct); Product product2 = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); - changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product2, productManager2, LifeCycleStatesEnum.CHECKIN); + changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product2, productManager2, + LifeCycleStatesEnum.CHECKIN); ProductRestUtils.checkSuccess(changeProductLifeCycle); - changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product2, productManager2, LifeCycleStatesEnum.CHECKOUT); + changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product2, productManager2, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product2.getUniqueId()); productReqDetails.setUUID(product2.getUUID()); productReqDetails.setName(product1.getName()); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager2); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_ALREADY_EXISTS, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_ALREADY_EXISTS, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add(product1.getName()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_NAME_ALREADY_EXIST.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_NAME_ALREADY_EXIST.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager2.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager2.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product2.getUniqueId()); expectedProduct.setVersion(product2.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } // DE193857 - Normalized Name is not removing special characters @@ -681,7 +779,8 @@ public class ProductCrudTest extends ProductBaseTest { @Test(enabled = false) public void updateProductNameAllowedCharacters() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); // Update product name productReqDetails.setUniqueId(product.getUniqueId()); @@ -717,7 +816,8 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setNormalizedName(newNormalizedName); expectedProduct.setName(newName); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } // If user update "product name" we need to remove the old product name from @@ -725,7 +825,8 @@ public class ProductCrudTest extends ProductBaseTest { @Test(enabled = false) public void updateProductNameRemoveSpaceFromBeginning() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -744,7 +845,8 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setNormalizedName(newNormalizedName); expectedProduct.setName(newName); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } // If user update "product name" we need to remove the old product name from @@ -752,7 +854,8 @@ public class ProductCrudTest extends ProductBaseTest { @Test(enabled = false) public void updateProductNameRemoveSpaceFromEnd() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -771,7 +874,8 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setNormalizedName(newNormalizedName); expectedProduct.setName(newName); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } //// DE193857 - Normalized Name is not removing special characters @@ -780,7 +884,8 @@ public class ProductCrudTest extends ProductBaseTest { @Test(enabled = false) public void updateProductNameRemoveExtraNonAlphanumericChars() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -799,7 +904,8 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setNormalizedName(newNormalizedName); expectedProduct.setName(newName); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } // If user update "product name" we need to remove the old product name from @@ -807,7 +913,8 @@ public class ProductCrudTest extends ProductBaseTest { @Test(enabled = false) public void updateProductNameValidationStartWithNumber() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -826,61 +933,73 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setNormalizedName(newNormalizedName); expectedProduct.setName(productReqDetails.getName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductNameValidationStartWithNonAlphaNumeric() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setName("_1000Ab"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add("abbreviated"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_FORMAT.name(), + varibales, updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductFullNameIsEmpty() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setFullName(""); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add("full"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_ONE_OF_COMPONENT_NAMES.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductFullNameIsNull() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -895,13 +1014,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setNormalizedName(product.getNormalizedName()); expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setFullName(product.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductFullNameHasMinLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -916,17 +1037,20 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setNormalizedName(product.getNormalizedName()); expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setFullName(productReqDetails.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductFullNameHasMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); - productReqDetails.setFullName("1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk"); + productReqDetails.setFullName( + "1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); productReqDetails.setLastUpdaterUserId(productManager1.getUserId()); @@ -937,78 +1061,94 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setNormalizedName(product.getNormalizedName()); expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setFullName(productReqDetails.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductFullNamelessThanMinLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setFullName("123"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add("full"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH.name(), + varibales, updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductFullNameExceedMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); - productReqDetails.setFullName("1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjkx"); + productReqDetails.setFullName( + "1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjkx"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add("full"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ELEMENT_INVALID_NAME_LENGTH.name(), + varibales, updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } // DE193947 @Test public void updateProductFullNameWithSpecialCharacters() throws Exception { - char invalidChars[] = { '~', '!', '%', '^', '*', '(', ')', '"', '{', '}', '[', ']', '?', '>', '<', '/', '|', '\\', ',', '$', '#', '@', '+' }; + char invalidChars[] = { '~', '!', '%', '^', '*', '(', ')', '"', '{', '}', '[', ']', '?', '>', '<', '/', '|', + '\\', ',', '$', '#', '@', '+' }; String fullName = "avbng"; createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); for (int i = 0; i < invalidChars.length; i++) { productReqDetails.setFullName(fullName + invalidChars[i]); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, + updateProduct.getErrorCode().intValue()); } } @Test // (enabled=false) public void updateProductFullNameValidCharactersCharacters01() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1023,13 +1163,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setNormalizedName(product.getNormalizedName()); expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setFullName("qwertyuiopasdfghjklzxcvbnm1234567890Bold<"); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductFullNameRemoveExtraSpaces() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1044,36 +1186,43 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setNormalizedName(product.getNormalizedName()); expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setFullName("Abbaaa a1"); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductDescriptionIsEmpty() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setDescription(""); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductDescriptionIsNull() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1081,7 +1230,8 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1089,13 +1239,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test(enabled = false) public void updateProductDescriptionValidCharacters01() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1103,7 +1255,8 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1112,13 +1265,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductDescriptionValidCharacters02() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1126,45 +1281,53 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); - expectedProduct.setDescription("qwertyuiopasdfghjklzxcvbnm1234567890Bold<"); + expectedProduct.setDescription("qwertyuiopasdfghjklzxcvbnm1234567890Bold<"); expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductDescriptionInValidCharacters() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setDescription("מה"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_DESCRIPTION.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_DESCRIPTION.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductDescriptionRemoveSpacesFromBeginning() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1172,22 +1335,25 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); - expectedProduct.setDescription("abcd12345 g"); + expectedProduct.setDescription(" abcd12345 g"); expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductDescriptionRemoveSpacesFromTheEnd() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1195,22 +1361,25 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); - expectedProduct.setDescription("abcd12345 gdf"); + expectedProduct.setDescription("abcd12345 gdf "); expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductDescriptionMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1219,7 +1388,8 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1228,62 +1398,74 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductDescriptionExceedMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); String description = "01234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk aa1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk aa1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk aa1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk aa1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk aa1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk aa1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk aa1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk aa1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjk aa1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfg"; productReqDetails.setDescription(description); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add("1024"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_DESCRIPTION_EXCEEDS_LIMIT.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_DESCRIPTION_EXCEEDS_LIMIT.name(), + varibales, updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductTagIsEmpty() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setTags(Arrays.asList("")); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); varibales.add("tag"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FIELD_FORMAT.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FIELD_FORMAT.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductTagIsNull() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1291,7 +1473,8 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1300,34 +1483,41 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductTagsNameValidationProductNameIsNotInTag() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setTags(Arrays.asList("Abc")); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_TAGS_NO_COMP_NAME.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_TAGS_NO_COMP_NAME.name(), + new ArrayList(), updateProduct.getResponse()); } @Test // (enabled=false) public void createProductSingleTagMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); - productReqDetails.setTags(Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345678")); + productReqDetails.setTags( + Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345678")); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1336,24 +1526,30 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductSingleTagExceedMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); - productReqDetails.setTags(Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh123456788")); + productReqDetails.setTags(Arrays.asList(productReqDetails.getName(), + "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890")); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); - varibales.add("50"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_SINGLE_TAG_EXCEED_LIMIT.name(), varibales, updateProduct.getResponse()); + varibales.add("1024"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_SINGLE_TAG_EXCEED_LIMIT.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1361,26 +1557,31 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductAllTagsMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); - productReqDetails.setTags(Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345601", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345602", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345603", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345604", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345605", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345606", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345607", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345608", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh1234569", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345610", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345611", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345612", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345613", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345614", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345615", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345616", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345617", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345618", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345619", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345")); + productReqDetails.setTags( + Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345601", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345602", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345603", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345604", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345605", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345606", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345607")); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1389,41 +1590,63 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductAllTagsExceedMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); - ProductRestUtils.checkSuccess(changeProductLifeCycle); - productReqDetails.setUniqueId(product.getUniqueId()); - productReqDetails.setUUID(product.getUUID()); - productReqDetails.setTags(Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345601", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345602", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345603", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345604", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345605", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345606", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345607", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345608", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh1234569", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345610", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345611", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345612", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345613", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345614", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345615", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345616", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345617", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345618", "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345619", - "Abba1234567890asdfghjkl123zxcvbnm432asdfgh123456")); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); + ProductRestUtils.checkSuccess(changeProductLifeCycle); + productReqDetails.setUniqueId(product.getUniqueId()); + productReqDetails.setUUID(product.getUUID()); + productReqDetails.setTags( + Arrays.asList(productReqDetails.getName(), "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345601", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345602", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345603", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345604", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345605", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345606", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345607", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345608", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh1234569", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345610", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345611", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345612", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345613", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345614", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345615", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345616", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345617", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345618", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh12345619", + "Abba1234567890asdfghjkl123zxcvbnm432asdfgh123456")); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add("1024"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_TAGS_EXCEED_LIMIT.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_TAGS_EXCEED_LIMIT.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductTagsDuplicateTagRemoved() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1431,7 +1654,8 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata updated - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1440,43 +1664,51 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductContactsIsEmpty() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setContacts(Arrays.asList("")); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductContactsIsNull() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setContacts(null); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1484,43 +1716,51 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductContactsInvalidFormat() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setContacts(Arrays.asList("bt750345")); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(COMPONENT_TYPE); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(getProduct.getResponse(), Product.class); expectedProduct.setVersion(product.getVersion()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductConvertContactsToLowerCase() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setContacts(Arrays.asList(productManager2.getUserId().toUpperCase())); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1528,25 +1768,31 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - expectedProduct.setContacts(Arrays.asList(productManager2.getUserId().toLowerCase(), productManager1.getUserId())); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + expectedProduct + .setContacts(Arrays.asList(productManager2.getUserId().toLowerCase(), productManager1.getUserId())); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductContactsNotAllowedAsdcUsers() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setContacts(Arrays.asList(productStrategistUser1.getUserId())); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(productStrategistUser1.getUserId()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PRODUCT_CONTACT.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PRODUCT_CONTACT.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1554,25 +1800,30 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductContactsNotAsdcUser() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); String nonAsdcUserUserId = "bt567h"; productReqDetails.setContacts(Arrays.asList(nonAsdcUserUserId)); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList varibales = new ArrayList(); varibales.add(nonAsdcUserUserId); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PRODUCT_CONTACT.name(), varibales, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PRODUCT_CONTACT.name(), varibales, + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1580,22 +1831,27 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductProjectCodeIsEmpty() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setProjectCode(""); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_PROJECT_CODE.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_PROJECT_CODE.name(), new ArrayList(), + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1603,20 +1859,23 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductProjectCodeIsNull() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setProjectCode(null); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1625,22 +1884,27 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setProjectCode(product.getProjectCode()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductProjectCodeLessThanMinCharacters() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setProjectCode("9870"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROJECT_CODE.name(), new ArrayList(), updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROJECT_CODE.name(), new ArrayList(), + updateProduct.getResponse()); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1648,14 +1912,16 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductProjectCodeHasnMinCharacters() throws Exception { // min - // =5 + // =5 createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1663,7 +1929,8 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1672,13 +1939,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setProjectCode(productReqDetails.getProjectCode()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductProjectCodeHasnMaxCharacters() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1686,7 +1955,8 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1695,22 +1965,27 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setProjectCode(productReqDetails.getProjectCode()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductProjectCodeExceedMaxCharacters() throws Exception {// Max - // =10 + // =10 createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setProjectCode("12345678901"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROJECT_CODE.name(), new ArrayList(), updateProduct.getResponse()); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROJECT_CODE.name(), new ArrayList(), + updateProduct.getResponse()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1719,22 +1994,27 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setProjectCode(product.getProjectCode()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductProjectCodeIsNotNumeric() throws Exception { // Max =10 createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setProjectCode("1234a"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROJECT_CODE.name(), new ArrayList(), updateProduct.getResponse()); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROJECT_CODE.name(), new ArrayList(), + updateProduct.getResponse()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1743,23 +2023,28 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setProjectCode(product.getProjectCode()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductIconIsEmpty() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setIcon(""); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList variables = new ArrayList(); variables.add(COMPONENT_TYPE); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_ICON.name(), variables, updateProduct.getResponse()); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_ICON.name(), variables, + updateProduct.getResponse()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1768,13 +2053,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setIcon(product.getIcon()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductIconIsNull() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1782,7 +2069,8 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); // Get Product and verify that metadata didn't change - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1791,13 +2079,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setIcon(product.getIcon()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductIconMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -1805,7 +2095,8 @@ public class ProductCrudTest extends ProductBaseTest { // 25 RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1814,24 +2105,29 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setIcon(productReqDetails.getIcon()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductIconExceedMaxLength() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setIcon("A_a-1-2--b__BB1234567890A_"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList variables = new ArrayList(); variables.add(COMPONENT_TYPE); variables.add("25"); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ICON_EXCEEDS_LIMIT.name(), variables, updateProduct.getResponse()); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ICON_EXCEEDS_LIMIT.name(), variables, + updateProduct.getResponse()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1840,29 +2136,35 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setIcon(product.getIcon()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductIconInValidCharacters() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); String icon = "asdfg"; // Allowed characters [a-zA-Z0-9], dash (‘-‘), // underscore (‘_’). - char invalidChars[] = { '~', '!', '$', '%', '^', '*', '(', ')', '"', '{', '}', '[', ']', '?', '>', '<', '/', '|', '\\', ',' }; + char invalidChars[] = { '~', '!', '$', '%', '^', '*', '(', ')', '"', '{', '}', '[', ']', '?', '>', '<', '/', + '|', '\\', ',' }; RestResponse updateProduct; for (int i = 0; i < invalidChars.length; i++) { productReqDetails.setIcon(icon + invalidChars[i]); updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); ArrayList variables = new ArrayList(); variables.add(COMPONENT_TYPE); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_ICON.name(), variables, updateProduct.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_ICON.name(), variables, + updateProduct.getResponse()); } - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1871,20 +2173,23 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setIcon(product.getIcon()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductIsActiveIsEmpty() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setActive(""); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1893,20 +2198,23 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setIsActive(false); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductIsActiveIsTrue() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setActive("true"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1915,7 +2223,8 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setIsActive(true); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) @@ -1925,16 +2234,19 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); Product product = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKIN); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKIN); ProductRestUtils.checkSuccess(changeProductLifeCycle); - changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setActive(null); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1943,20 +2255,23 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setIsActive(true); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductIsActiveIsFalse() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setActive("false"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); ProductRestUtils.checkSuccess(updateProduct); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1965,22 +2280,28 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); expectedProduct.setIsActive(false); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductIsActiveHasInvalidValue() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); productReqDetails.setActive("eeeee"); RestResponse updateProduct = ProductRestUtils.updateProduct(productReqDetails, productManager1); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); - ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), new ArrayList(), updateProduct.getResponse()); - assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, updateProduct.getErrorCode().intValue()); - RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), new ArrayList(), + updateProduct.getResponse()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_INVALID_CONTENT, + updateProduct.getErrorCode().intValue()); + RestResponse getProduct = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); ProductRestUtils.checkSuccess(getProduct); Product expectedProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); expectedProduct.setUniqueId(product.getUniqueId()); @@ -1988,13 +2309,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setVersion(product.getVersion()); expectedProduct.setLastUpdaterUserId(productManager1.getUserId()); expectedProduct.setLastUpdaterFullName(productManager1.getFullName()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductAssociations() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -2010,7 +2333,8 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setCategories(productReqDetails.getCategories()); expectedProduct.setNormalizedName(productReqDetails.getName().toLowerCase()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) @@ -2021,9 +2345,11 @@ public class ProductCrudTest extends ProductBaseTest { RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); Product product = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKIN); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKIN); ProductRestUtils.checkSuccess(changeProductLifeCycle); - changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -2040,13 +2366,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setCategories(productReqDetails.getCategories()); expectedProduct.setNormalizedName(productReqDetails.getName().toLowerCase()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductRemoveAllAssociations() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -2062,13 +2390,15 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setCategories(productReqDetails.getCategories()); expectedProduct.setNormalizedName(productReqDetails.getName().toLowerCase()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } @Test // (enabled=false) public void updateProductAssociationsCategotyIsNull() throws Exception { createProducrByPSAndCheckIn(); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKOUT); ProductRestUtils.checkSuccess(changeProductLifeCycle); productReqDetails.setUniqueId(product.getUniqueId()); productReqDetails.setUUID(product.getUUID()); @@ -2084,23 +2414,30 @@ public class ProductCrudTest extends ProductBaseTest { expectedProduct.setInvariantUUID(product.getInvariantUUID()); expectedProduct.setCategories(product.getCategories()); expectedProduct.setNormalizedName(productReqDetails.getName().toLowerCase()); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.UPDATE_COMPONENT); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.UPDATE_COMPONENT); } //////////////////////////////////////////////////////////////////////// private void createProductWithCategories(List categoryDefinitions) throws Exception { - ProductReqDetails productReqDetails = (categoryDefinitions != null ? ElementFactory.getDefaultProduct(categoryDefinitions) : ElementFactory.getDefaultProduct()); + ProductReqDetails productReqDetails = (categoryDefinitions != null + ? ElementFactory.getDefaultProduct(categoryDefinitions) : ElementFactory.getDefaultProduct()); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, createProduct.getErrorCode().intValue()); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, + createProduct.getErrorCode().intValue()); Product actualProduct = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); String actualUuid = ResponseParser.getUuidFromResponse(createProduct); - Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, productManager1); - String normalizedNameFomJsonResponse = ResponseParser.getValueFromJsonResponse(createProduct.getResponse(), "normalizedName"); + Product expectedProduct = Convertor.constructFieldsForRespValidation(productReqDetails, INITIAL_PRODUCT_VERSION, + productManager1); + String normalizedNameFomJsonResponse = ResponseParser.getValueFromJsonResponse(createProduct.getResponse(), + "normalizedName"); expectedProduct.setNormalizedName(normalizedNameFomJsonResponse); - ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, ComponentOperationEnum.CREATE_COMPONENT); - ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation(expectedProduct, CREATE_AUDIT_ACTION, productManager1, ActionStatus.CREATED, Constants.EMPTY_STRING, "0.1", null, - LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, actualUuid); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, + ComponentOperationEnum.CREATE_COMPONENT); + ExpectedProductAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation( + expectedProduct, CREATE_AUDIT_ACTION, productManager1, ActionStatus.CREATED, Constants.EMPTY_STRING, + "0.1", null, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, actualUuid); AuditValidationUtils.validateAuditProduct(constructFieldsForAuditValidation, CREATE_AUDIT_ACTION); } @@ -2109,7 +2446,8 @@ public class ProductCrudTest extends ProductBaseTest { createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); ProductRestUtils.checkCreateResponse(createProduct); product = ResponseParser.parseToObjectUsingMapper(createProduct.getResponse(), Product.class); - RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, LifeCycleStatesEnum.CHECKIN); + RestResponse changeProductLifeCycle = ProductRestUtils.changeProductLifeCycle(product, productManager1, + LifeCycleStatesEnum.CHECKIN); ProductRestUtils.checkSuccess(changeProductLifeCycle); } @@ -2120,12 +2458,14 @@ public class ProductCrudTest extends ProductBaseTest { productReqDetails.setInvariantUUID(invariantUuidDefinedByUser); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); BaseRestUtils.checkStatusCode(createProduct, "create request failed", false, 201); - assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, createProduct.getErrorCode().intValue()); + assertEquals("Check response code after create Product", BaseRestUtils.STATUS_CODE_CREATED, + createProduct.getErrorCode().intValue()); Product ProductCreation = ResponseParser.convertProductResponseToJavaObject(createProduct.getResponse()); String invariantUUIDcreation = ProductCreation.getInvariantUUID(); // validate get response - RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), productManager1.getUserId()); + RestResponse getProductRes = ProductRestUtils.getProduct(productReqDetails.getUniqueId(), + productManager1.getUserId()); BaseRestUtils.checkSuccess(getProductRes); Product productGetting = ResponseParser.convertProductResponseToJavaObject(getProductRes.getResponse()); String invariantUUIDgetting = productGetting.getInvariantUUID(); @@ -2139,7 +2479,8 @@ public class ProductCrudTest extends ProductBaseTest { assertEquals(invariantUUIDcreation, invariantUUIDupdating); // Do checkin - RestResponse restResponseCheckin = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, LifeCycleStatesEnum.CHECKIN); + RestResponse restResponseCheckin = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, + LifeCycleStatesEnum.CHECKIN); BaseRestUtils.checkSuccess(restResponseCheckin); Product checkinProduct = ResponseParser.convertProductResponseToJavaObject(restResponseCheckin.getResponse()); String invariantUUIDcheckin = checkinProduct.getInvariantUUID(); @@ -2148,7 +2489,8 @@ public class ProductCrudTest extends ProductBaseTest { assertEquals(version, "0.1"); // Do checkout - RestResponse restResponseCheckout = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, LifeCycleStatesEnum.CHECKOUT); + RestResponse restResponseCheckout = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, + LifeCycleStatesEnum.CHECKOUT); BaseRestUtils.checkSuccess(restResponseCheckout); Product checkoutProduct = ResponseParser.convertProductResponseToJavaObject(restResponseCheckout.getResponse()); String invariantUUIDcheckout = checkoutProduct.getInvariantUUID(); @@ -2159,8 +2501,10 @@ public class ProductCrudTest extends ProductBaseTest { } // US672129 Benny - private void getProductValidateInvariantUuid(String productUniqueId, String invariantUUIDcreation) throws Exception { - RestResponse getProduct = ProductRestUtils.getProduct(productUniqueId, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + private void getProductValidateInvariantUuid(String productUniqueId, String invariantUUIDcreation) + throws Exception { + RestResponse getProduct = ProductRestUtils.getProduct(productUniqueId, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, getProduct.getErrorCode().intValue()); assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(getProduct)); } @@ -2172,7 +2516,8 @@ public class ProductCrudTest extends ProductBaseTest { String invariantUuidDefinedByUser = "12345"; productReqDetails.setInvariantUUID(invariantUuidDefinedByUser); RestResponse createProduct = ProductRestUtils.createProduct(productReqDetails, productManager1); - assertEquals("Check response code after create resource", BaseRestUtils.STATUS_CODE_CREATED, createProduct.getErrorCode().intValue()); + assertEquals("Check response code after create resource", BaseRestUtils.STATUS_CODE_CREATED, + createProduct.getErrorCode().intValue()); // invariantUUID generated when the component is created and never // changed String invariantUUIDcreation = ResponseParser.getInvariantUuid(createProduct); @@ -2182,18 +2527,21 @@ public class ProductCrudTest extends ProductBaseTest { assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); getProductValidateInvariantUuid(productReqDetails.getUniqueId(), invariantUUIDcreation); // Checkin - restResponse = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, LifeCycleStatesEnum.CHECKIN); + restResponse = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, + LifeCycleStatesEnum.CHECKIN); assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); getProductValidateInvariantUuid(productReqDetails.getUniqueId(), invariantUUIDcreation); // Checkout - restResponse = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, LifeCycleStatesEnum.CHECKOUT); + restResponse = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, + LifeCycleStatesEnum.CHECKOUT); assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); getProductValidateInvariantUuid(productReqDetails.getUniqueId(), invariantUUIDcreation); // UnDo-CheckOut - restResponse = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, LifeCycleStatesEnum.UNDOCHECKOUT); + restResponse = LifecycleRestUtils.changeProductState(productReqDetails, productManager1, + LifeCycleStatesEnum.UNDOCHECKOUT); assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); getProductValidateInvariantUuid(productReqDetails.getUniqueId(), invariantUUIDcreation); diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductGetFollowedTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductGetFollowedTest.java similarity index 100% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductGetFollowedTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductGetFollowedTest.java diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductLifecycleTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductLifecycleTest.java similarity index 100% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductLifecycleTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductLifecycleTest.java diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductTestBase.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductTestBase.java similarity index 100% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductTestBase.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductTestBase.java diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductToscaYamlGenerationTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductToscaYamlGenerationTest.java similarity index 100% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductToscaYamlGenerationTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductToscaYamlGenerationTest.java diff --git a/asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductUndoCheckoutTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductUndoCheckoutTest.java similarity index 100% rename from asdc-tests/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductUndoCheckoutTest.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/product/ProductUndoCheckoutTest.java diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/AdditionalInformationServletTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/AdditionalInformationServletTest.java new file mode 100644 index 0000000000..1cf16978e4 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/AdditionalInformationServletTest.java @@ -0,0 +1,2021 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.property; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.json.simple.parser.JSONParser; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.elements.AdditionalInfoParameterInfo; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.AdditionalInformationDefinition; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.resource.ResourceApiTest; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +public class AdditionalInformationServletTest extends ComponentBaseTest { + + protected Type constraintType = new TypeToken() { + }.getType(); + + protected Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create(); + + @Rule + public static TestName name = new TestName(); + + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json"; + + protected JSONParser jsonParser = new JSONParser(); + + public AdditionalInformationServletTest() { + super(name, AdditionalInformationServletTest.class.getName()); + } + + // @Before + // public void deleteResources() { + // //TODO Evg : will be new API added for delete by name and version + // + // ResourceReqDetails resource = getResource(); + // User user = getUser(); + // + // try { + // String resourceName = resource.getResourceName(); + // ResourceRestUtils.deleteResourceByNameAndVersion(user, resourceName, + // "0.1"); + // ResourceRestUtils.deleteResourceByNameAndVersion(user, resourceName, + // "0.2"); + // ResourceRestUtils.deleteResourceByNameAndVersion(user, resourceName, + // "1.0"); + // ResourceRestUtils.deleteResourceByNameAndVersion(user, resourceName, + // "1.1"); + // ResourceRestUtils.deleteResourceByNameAndVersion(user, resourceName + + // "aa", "0.1"); + // resourceUtils.deleteResource_allVersions(resource, user); + // + // } catch (IOException e) { + // assertTrue(false); + // } + // + // try { + // ServiceReqDetails serviceDetails = getServiceDetails(); + // + // RestResponse deleteServiceResponse = + // serviceUtils.deleteServiceByNameAndVersion(UserUtils.getAdminDetails(), + // serviceDetails.getServiceName(), "0.1"); + // + // assertNotNull("check response object is not null after delete + // service",deleteServiceResponse); + // assertNotNull("check error code exists in response after delete + // service",deleteServiceResponse.getErrorCode()); + // assertTrue("delete service failed status:" + + // deleteServiceResponse.getErrorCode(), + // deleteServiceResponse.getErrorCode() != 500); + // + // deleteServiceResponse = + // serviceUtils.deleteServiceByNameAndVersion(UserUtils.getAdminDetails(), + // serviceDetails.getServiceName(), "1.0"); + // + // assertNotNull("check response object is not null after delete + // service",deleteServiceResponse); + // assertNotNull("check error code exists in response after delete + // service",deleteServiceResponse.getErrorCode()); + // assertTrue("delete service failed status:" + + // deleteServiceResponse.getErrorCode(), + // deleteServiceResponse.getErrorCode() != 500); + // + // serviceUtils.deleteService_allVersions(serviceDetails, user); + // + // } catch (IOException e) { + // assertTrue(false); + // } + // } + + @Test + public void updateResourceAdditionalInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + AssertJUnit.assertNotNull("check response object is not null after create resource", createResourceResponse); + AssertJUnit.assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "BBBB"; + + String updatedKey = "ZZZ ZZZ"; + String updatedValue = "JJJJ"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + AssertJUnit.assertNotNull("check response object is not null after create property", createProperty); + AssertJUnit.assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + AssertJUnit.assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + AssertJUnit.assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + fromJson.setKey(updatedKey); + fromJson.setValue(updatedValue); + + RestResponse updatedProperty = updateAdditionalInformation(resourceId, fromJson, user, fromJson.getUniqueId()); + AssertJUnit.assertNotNull("check response object is not null after update additional information", updatedProperty); + AssertJUnit.assertNotNull("check error code exists in response after additional information", updatedProperty.getErrorCode()); + AssertJUnit.assertEquals("Check response code after additional information", 200, updatedProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo updatedJson = gson.fromJson(updatedProperty.getResponse(), AdditionalInfoParameterInfo.class); + AssertJUnit.assertFalse("check number of spaces", updatedJson.getKey().contains(" ")); + AssertJUnit.assertEquals("check returned key", "ZZZ ZZZ", updatedJson.getKey()); + AssertJUnit.assertEquals("check returned value", updatedValue, updatedJson.getValue()); + AssertJUnit.assertEquals("check returned id", fromJson.getUniqueId(), updatedJson.getUniqueId()); + + } + + @Test + public void deleteResourceAdditionalInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + AssertJUnit.assertNotNull("check response object is not null after create resource", createResourceResponse); + AssertJUnit.assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + AssertJUnit.assertNotNull("check response object is not null after create property", createProperty); + AssertJUnit.assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + AssertJUnit.assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + AssertJUnit.assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + RestResponse deletedProperty = deleteAdditionalInformation(resourceId, fromJson.getUniqueId(), user); + AssertJUnit.assertNotNull("check response object is not null after update additional information", deletedProperty); + AssertJUnit.assertNotNull("check error code exists in response after additional information", deletedProperty.getErrorCode()); + AssertJUnit.assertEquals("Check response code after additional information", 200, deletedProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo updatedJson = gson.fromJson(deletedProperty.getResponse(), AdditionalInfoParameterInfo.class); + AssertJUnit.assertFalse("check number of spaces", updatedJson.getKey().contains(" ")); + AssertJUnit.assertEquals("check returned key", "AAA AAA", updatedJson.getKey()); + AssertJUnit.assertEquals("check returned value", value, updatedJson.getValue()); + AssertJUnit.assertEquals("check returned id", fromJson.getUniqueId(), updatedJson.getUniqueId()); + + deletedProperty = deleteAdditionalInformation(resourceId, fromJson.getUniqueId(), user); + AssertJUnit.assertNotNull("check response object is not null after update additional information", deletedProperty); + AssertJUnit.assertNotNull("check error code exists in response after additional information", deletedProperty.getErrorCode()); + AssertJUnit.assertEquals("Check response code after additional information", 409, deletedProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceAdditionalInformationTestDuringLifecycle() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + AssertJUnit.assertNotNull("check response object is not null after create resource", createResourceResponse); + AssertJUnit.assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + AssertJUnit.assertNotNull("check response object is not null after create property", createProperty); + AssertJUnit.assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + AssertJUnit.assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + AssertJUnit.assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + resource.setUniqueId(resourceId); + + // resourceUtils.addResourceMandatoryArtifacts(user, + // createResourceResponse); + + certifyResource(user, resource, null, 1); + + } + + public RestResponse createService() { + + User user = getUser(); + ServiceReqDetails serviceDetails = getServiceDetails(); + + RestResponse createServiceResponse = null; + try { + createServiceResponse = ServiceRestUtils.createService(serviceDetails, user); + AssertJUnit.assertNotNull("check response object is not null after create user", createServiceResponse); + AssertJUnit.assertNotNull("check error code exists in response after create resource", createServiceResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after checkout resource", 201, createServiceResponse.getErrorCode().intValue()); + } catch (Exception e) { + AssertJUnit.assertTrue(false); + } + + return createServiceResponse; + + } + + protected User getUser() { + String adminFirstName = "Jimmy"; + String adminLastName = "Hendrix"; + String adminUserId = "jh0003"; + return new User(adminFirstName, adminLastName, adminUserId, null, null, null); + } + + protected ResourceReqDetails getResource() { + String resourceName = "ciResourceforproperty4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add("tosca.nodes.Root"); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "pe0123"; + String icon = "myICON"; + ResourceReqDetails resource = new ResourceReqDetails(resourceName, description, resourceTags, null, derivedFrom, vendorName, vendorRelease, contactId, icon); + resource.addCategoryChain(ResourceCategoryEnum.GENERIC_DATABASE.getCategory(), ResourceCategoryEnum.GENERIC_DATABASE.getSubCategory()); + return resource; + } + + protected RestResponse createResource(ResourceReqDetails resourceDetails, User sdncModifierDetails) throws IOException { + + ResourceApiTest rat = new ResourceApiTest(); + ResourceReqDetails resourceObj = rat.getResourceObj(); + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(resourceDetails); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.CREATE_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort()); + RestResponse createResourceResponse = http.httpSendPost(url, userBodyJson, headersMap); + + return createResourceResponse; + + } + + protected RestResponse getResource(User sdncModifierDetails, String resourceUid) throws IOException { + + ResourceApiTest rat = new ResourceApiTest(); + ResourceReqDetails resourceObj = rat.getResourceObj(); + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceUid); + RestResponse createResourceResponse = http.httpSendGet(url, headersMap); + + return createResourceResponse; + + } + + protected RestResponse deleteResource(String resourceName, String resourceVersion, User sdncModifierDetails) throws IOException { + RestResponse deleteResourceResponse = ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, resourceName, resourceVersion); + + return deleteResourceResponse; + + } + + protected RestResponse updateAdditionalInformation(String resourceId, AdditionalInfoParameterInfo additionalInfo, User sdncModifierDetails, String id) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + String body = gson.toJson(additionalInfo); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.UPDATE_ADDITIONAL_INFORMATION_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId, id); + return http.httpSendPut(url, body, headersMap); + + } + + protected RestResponse updateServiceAdditionalInformation(String resourceId, AdditionalInfoParameterInfo additionalInfo, User sdncModifierDetails, String id) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + String body = gson.toJson(additionalInfo); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.UPDATE_ADDITIONAL_INFORMATION_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId, id); + return http.httpSendPut(url, body, headersMap); + + } + + protected RestResponse deleteAdditionalInformation(String resourceId, String id, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.DELETE_ADDITIONAL_INFORMATION_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId, id); + return http.httpSendDelete(url, headersMap); + + } + + protected RestResponse deleteServiceAdditionalInformation(String resourceId, String id, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.DELETE_ADDITIONAL_INFORMATION_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId, id); + return http.httpSendDelete(url, headersMap); + + } + + protected RestResponse getAdditionalInformation(String resourceId, String id, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_ADDITIONAL_INFORMATION_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId, id); + return http.httpSendGet(url, headersMap); + + } + + protected RestResponse getServiceAdditionalInformation(String resourceId, String id, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_ADDITIONAL_INFORMATION_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId, id); + return http.httpSendGet(url, headersMap); + + } + + protected RestResponse getResourceAllAdditionalInformation(String resourceId, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_ALL_ADDITIONAL_INFORMATION_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId); + return http.httpSendGet(url, headersMap); + + } + + protected RestResponse getServiceAllAdditionalInformation(String resourceId, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_ALL_ADDITIONAL_INFORMATION_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId); + return http.httpSendGet(url, headersMap); + + } + + protected RestResponse createResourceAdditionalInformation(String resourceId, AdditionalInfoParameterInfo additionalInfo, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + String body = gson.toJson(additionalInfo); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.CREATE_ADDITIONAL_INFORMATION_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId); + return http.httpSendPost(url, body, headersMap); + + } + + protected RestResponse createServiceAdditionalInformation(String serviceId, AdditionalInfoParameterInfo additionalInfo, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + String body = gson.toJson(additionalInfo); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.CREATE_ADDITIONAL_INFORMATION_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), serviceId); + return http.httpSendPost(url, body, headersMap); + + } + + protected ServiceReqDetails getServiceDetails() { + String serviceName = "ciNewTestService21"; + String category = ServiceCategoriesEnum.MOBILITY.getValue(); + ArrayList tags = new ArrayList(); + tags.add("serviceTag"); + tags.add(serviceName); + String description = "service Description"; + String vendorName = "Oracle"; + String vendorRelease = "0.1"; + String contactId = "al1976"; + String icon = "myIcon"; + + return new ServiceReqDetails(serviceName, category, tags, description, contactId, icon); + } + + // TODO Tal: Since Cashing change partial resource returned that causes null + // pointer exception in line: + // commented out till fixing + protected Resource certifyResource(User user, ResourceReqDetails resource, String resourceVersion, int numberOfAI) throws IOException { + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CHECKIN); + + AssertJUnit.assertNotNull("check response object is not null after create user", checkInResponse); + AssertJUnit.assertNotNull("check error code exists in response after create user", checkInResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create user", 200, checkInResponse.getErrorCode().intValue()); + + Resource resourceAfterOperation = gson.fromJson(checkInResponse.getResponse(), Resource.class); + // TODO Tal: Since Cashing change partial resource returned that causes + // null pointer exception + /* + * AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().size()); + */ + /* + * AssertJUnit.assertEquals("check size of additional information", numberOfAI, resourceAfterOperation.getAdditionalInformation().get(0). getParameters().size()); + */ + + RestResponse req4certResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + + AssertJUnit.assertNotNull("check response object is not null after create user", req4certResponse); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, req4certResponse.getErrorCode().intValue()); + + resourceAfterOperation = gson.fromJson(req4certResponse.getResponse(), Resource.class); + // TODO Tal: Since Cashing change partial resource returned that causes + // null pointer exception + /* + * AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().size()); + */ + /* + * AssertJUnit.assertEquals("check size of additional information", numberOfAI, resourceAfterOperation.getAdditionalInformation().get(0). getParameters().size()); + */ + + // change modifier + user.setUserId(UserRoleEnum.TESTER.getUserId()); + // start certification + + RestResponse startCertResourceResponse3 = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + AssertJUnit.assertNotNull("check response object is not null after create user", startCertResourceResponse3); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, startCertResourceResponse3.getErrorCode().intValue()); + + resourceAfterOperation = gson.fromJson(startCertResourceResponse3.getResponse(), Resource.class); + // TODO Tal: Since Cashing change partial resource returned that causes + // null pointer exception + /* + * AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().size()); + */ + /* + * AssertJUnit.assertEquals("check size of additional information", numberOfAI, resourceAfterOperation.getAdditionalInformation().get(0). getParameters().size()); + */ + + // certify + + RestResponse certifyResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CERTIFY); + AssertJUnit.assertNotNull("check response object is not null after create user", certifyResponse); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, certifyResponse.getErrorCode().intValue()); + + resourceAfterOperation = gson.fromJson(certifyResponse.getResponse(), Resource.class); + AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().size()); + AssertJUnit.assertEquals("check size of additional information", numberOfAI, resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + + Resource certifyResource = gson.fromJson(certifyResponse.getResponse(), Resource.class); + return certifyResource; + } + + protected Resource certifyService(User user, ServiceReqDetails service, String resourceVersion) throws Exception { + RestResponse checkInResponse = LifecycleRestUtils.changeServiceState(service, user, resourceVersion, LifeCycleStatesEnum.CHECKIN); + + AssertJUnit.assertNotNull("check response object is not null after create user", checkInResponse); + AssertJUnit.assertNotNull("check error code exists in response after create user", checkInResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create user", 200, checkInResponse.getErrorCode().intValue()); + + Resource resourceAfterOperation = gson.fromJson(checkInResponse.getResponse(), Resource.class); + AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().size()); + AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + + RestResponse req4certResponse = LifecycleRestUtils.changeServiceState(service, user, resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + + AssertJUnit.assertNotNull("check response object is not null after create user", req4certResponse); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, req4certResponse.getErrorCode().intValue()); + + resourceAfterOperation = gson.fromJson(req4certResponse.getResponse(), Resource.class); + AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().size()); + AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + + // change modifier + user.setUserId(UserRoleEnum.TESTER.getUserId()); + // start certification + + RestResponse startCertResourceResponse3 = LifecycleRestUtils.changeServiceState(service, user, resourceVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + AssertJUnit.assertNotNull("check response object is not null after create user", startCertResourceResponse3); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, startCertResourceResponse3.getErrorCode().intValue()); + + resourceAfterOperation = gson.fromJson(startCertResourceResponse3.getResponse(), Resource.class); + AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().size()); + AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + + // certify + + RestResponse certifyResponse = LifecycleRestUtils.changeServiceState(service, user, resourceVersion, LifeCycleStatesEnum.CERTIFY); + AssertJUnit.assertNotNull("check response object is not null after create user", certifyResponse); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, certifyResponse.getErrorCode().intValue()); + + resourceAfterOperation = gson.fromJson(certifyResponse.getResponse(), Resource.class); + AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().size()); + AssertJUnit.assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + + Resource certifyResource = gson.fromJson(certifyResponse.getResponse(), Resource.class); + return certifyResource; + } + + @Test + public void createResourceAdditionalInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 409, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceAdditionalInfoFormatWithTags() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "Bold<"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertEquals("check returned key", "Bold&lt;", fromJson.getValue()); + + } + + @Test + public void createServiceAdditionalInfoFormatWithTags() throws Exception { + User user = getUser(); + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + assertNotNull("check response object is not null after create resource", createServiceResponse); + assertNotNull("check error code exists in response after create resource", createServiceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createServiceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "Bold<"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertEquals("check returned key", "Bold&lt;", fromJson.getValue()); + + } + + @Test + public void createResourceAdditionalInfoFormatWithWhiteSpaces() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = " "; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + key = " "; + value = "AAA AAA"; + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createServiceAdditionalInfoFormatWithWhiteSpaces() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + assertNotNull("check response object is not null after create resource", createServiceResponse); + assertNotNull("check error code exists in response after create resource", createServiceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createServiceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = " "; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + key = " "; + value = "AAA AAA"; + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceAndUpdateAdditionalInfo() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + key = "BBB BBB"; + value = "BBBB"; + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "BBB BBB", fromJson.getKey()); + + String updatedKey = "AAA AAA"; + String updatedValue = "JJJJ"; + + fromJson.setKey(updatedKey); + fromJson.setValue(updatedValue); + + RestResponse updatedProperty = updateAdditionalInformation(resourceId, fromJson, user, fromJson.getUniqueId()); + assertNotNull("check response object is not null after update additional information", updatedProperty); + assertNotNull("check error code exists in response after additional information", updatedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 409, updatedProperty.getErrorCode().intValue()); + + } + + @Test + public void createServiceAdditionalInformationTest() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 409, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceEmptyAdditionalInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = ""; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + key = "BBBB"; + value = ""; + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createServiceEmptyAdditionalInformationTest() throws Exception { + + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = ""; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceAllSpacesAdditionalInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = " "; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createServiceAllSpacesAdditionalInformationTest() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = " "; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceInvalidKeyAdditionalInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "abc?"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createServiceInvalidKeyAdditionalInformationTest() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = "abc?"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceAdditionalInformationNullKeyTest() throws Exception { + + User user = getUser(); + ResourceReqDetails resource = getResource(); + + RestResponse createResourceResponse = createResource(resource, user); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + String key = null; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createServiceAdditionalInformationNullKeyTest() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = null; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceMaximumInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "BBBB"; + + for (int i = 0; i < 50; i++) { + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + i, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + } + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 409, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceLifeCycleAndMaximumInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + resource.setUniqueId(resourceId); + + String key = "AAA AAA"; + String value = "BBBB"; + + for (int i = 0; i < 49; i++) { + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + i, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + } + + String resourceVersion = "0.1"; + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + + assertNotNull("check response object is not null after create property", checkInResponse); + assertNotNull("check error code exists in response after create property", checkInResponse.getErrorCode()); + assertEquals("Check response code after create property", 200, checkInResponse.getErrorCode().intValue()); + + resourceVersion = "0.2"; + + RestResponse checkOutResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CHECKOUT, null); + + resourceId = ResponseParser.getUniqueIdFromResponse(checkOutResponse); + resource.setUniqueId(resourceId); + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 50, value); + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 51, value); + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 409, createProperty.getErrorCode().intValue()); + + RestResponse checkUndoOutResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.UNDOCHECKOUT, null); + + resourceVersion = "0.1"; + + checkOutResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CHECKOUT, null); + resourceId = ResponseParser.getUniqueIdFromResponse(checkOutResponse); + resource.setUniqueId(resourceId); + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 50, value); + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 51, value); + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 409, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createResourceLifeCycleCertifyAndMaximumInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + resource.setUniqueId(resourceId); + + String key = "AAA AAA"; + String value = "BBBB"; + + for (int i = 0; i < 49; i++) { + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + i, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + } + + String resourceVersion = "0.1"; + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + + // resourceUtils.addResourceMandatoryArtifacts(user, + // createResourceResponse); + + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + + assertNotNull("check response object is not null after create property", checkInResponse); + assertNotNull("check error code exists in response after create property", checkInResponse.getErrorCode()); + assertEquals("Check response code after create property", 200, checkInResponse.getErrorCode().intValue()); + + RestResponse changeStateResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST, null); + changeStateResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.STARTCERTIFICATION, null); + changeStateResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CERTIFY, null); + + assertNotNull("check response object is not null after create property", checkInResponse); + assertNotNull("check error code exists in response after create property", checkInResponse.getErrorCode()); + assertEquals("Check response code after create property", 200, checkInResponse.getErrorCode().intValue()); + + resourceId = ResponseParser.getUniqueIdFromResponse(changeStateResponse); + resource.setUniqueId(resourceId); + + resourceVersion = "1.0"; + + changeStateResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CHECKOUT, null); + resourceId = ResponseParser.getUniqueIdFromResponse(changeStateResponse); + resource.setUniqueId(resourceId); + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 50, value); + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 51, value); + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 409, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createServiceCycleAndMaximumInformationTest() throws Exception { + + User user = getUser(); + + ServiceReqDetails service = getServiceDetails(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + assertNotNull("check response object is not null after create resource", createServiceResponse); + assertNotNull("check error code exists in response after create resource", createServiceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createServiceResponse.getErrorCode().intValue()); + + service.setUniqueId(serviceId); + + String key = "AAA AAA"; + String value = "BBBB"; + + for (int i = 0; i < 49; i++) { + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + i, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + } + + String resourceVersion = "0.1"; + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + RestResponse checkInResponse = LifecycleRestUtils.changeServiceState(service, user, resourceVersion, LifeCycleStatesEnum.CHECKIN, checkinComentJson); + + assertNotNull("check response object is not null after create property", checkInResponse); + assertNotNull("check error code exists in response after create property", checkInResponse.getErrorCode()); + assertEquals("Check response code after create property", 200, checkInResponse.getErrorCode().intValue()); + + resourceVersion = "0.2"; + + RestResponse checkOutResponse = LifecycleRestUtils.changeServiceState(service, user, resourceVersion, LifeCycleStatesEnum.CHECKOUT, null); + + serviceId = ResponseParser.convertServiceResponseToJavaObject(checkOutResponse.getResponse()).getUniqueId(); + service.setUniqueId(serviceId); + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 50, value); + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 51, value); + createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 409, createProperty.getErrorCode().intValue()); + + RestResponse checkUndoOutResponse = LifecycleRestUtils.changeServiceState(service, user, resourceVersion, LifeCycleStatesEnum.UNDOCHECKOUT, null); + + resourceVersion = "0.1"; + + checkOutResponse = LifecycleRestUtils.changeServiceState(service, user, resourceVersion, LifeCycleStatesEnum.CHECKOUT, null); + serviceId = ResponseParser.convertServiceResponseToJavaObject(checkOutResponse.getResponse()).getUniqueId(); + service.setUniqueId(serviceId); + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 50, value); + createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + 51, value); + createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 409, createProperty.getErrorCode().intValue()); + + } + + @Test + public void createServiceMaximumInformationTest() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = "AAA AAA"; + String value = "BBBB"; + + String lastCreatedProperty = null; + + for (int i = 0; i < 50; i++) { + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key + i, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + lastCreatedProperty = fromJson.getUniqueId(); + + } + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 409, createProperty.getErrorCode().intValue()); + + RestResponse deletedProperty = deleteServiceAdditionalInformation(serviceId, lastCreatedProperty, user); + assertNotNull("check response object is not null after update additional information", deletedProperty); + assertNotNull("check error code exists in response after additional information", deletedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 200, deletedProperty.getErrorCode().intValue()); + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + } + + @Test + public void updateServiceAdditionalInformationTest() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = "AAA AAA"; + String value = "BBBB"; + + String updatedKey = "ZZZ ZZZ"; + String updatedValue = "JJJJ"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + fromJson.setKey(updatedKey); + fromJson.setValue(updatedValue); + + RestResponse updatedProperty = updateServiceAdditionalInformation(serviceId, fromJson, user, fromJson.getUniqueId()); + assertNotNull("check response object is not null after update additional information", updatedProperty); + assertNotNull("check error code exists in response after additional information", updatedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 200, updatedProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo updatedJson = gson.fromJson(updatedProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", updatedJson.getKey().contains(" ")); + assertEquals("check returned key", "ZZZ ZZZ", updatedJson.getKey()); + assertEquals("check returned value", updatedValue, updatedJson.getValue()); + assertEquals("check returned id", fromJson.getUniqueId(), updatedJson.getUniqueId()); + + fromJson.setKey(updatedKey); + fromJson.setValue("\uC2B5"); + + updatedProperty = updateServiceAdditionalInformation(serviceId, fromJson, user, fromJson.getUniqueId()); + assertNotNull("check response object is not null after update additional information", updatedProperty); + assertNotNull("check error code exists in response after additional information", updatedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 400, updatedProperty.getErrorCode().intValue()); + + } + + @Test + public void deleteServiceAdditionalInformationTest() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + RestResponse deletedProperty = deleteServiceAdditionalInformation(serviceId, fromJson.getUniqueId(), user); + assertNotNull("check response object is not null after update additional information", deletedProperty); + assertNotNull("check error code exists in response after additional information", deletedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 200, deletedProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo updatedJson = gson.fromJson(deletedProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", updatedJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", updatedJson.getKey()); + assertEquals("check returned value", value, updatedJson.getValue()); + assertEquals("check returned id", fromJson.getUniqueId(), updatedJson.getUniqueId()); + + deletedProperty = deleteServiceAdditionalInformation(serviceId, fromJson.getUniqueId(), user); + assertNotNull("check response object is not null after update additional information", deletedProperty); + assertNotNull("check error code exists in response after additional information", deletedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 409, deletedProperty.getErrorCode().intValue()); + + } + + @Test + public void getResourceAdditionalInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + RestResponse deletedProperty = getAdditionalInformation(resourceId, fromJson.getUniqueId(), user); + assertNotNull("check response object is not null after update additional information", deletedProperty); + assertNotNull("check error code exists in response after additional information", deletedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 200, deletedProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo updatedJson = gson.fromJson(deletedProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", updatedJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", updatedJson.getKey()); + assertEquals("check returned value", value, updatedJson.getValue()); + assertEquals("check returned id", fromJson.getUniqueId(), updatedJson.getUniqueId()); + + } + + @Test + public void getServiceAdditionalInformationTest() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + RestResponse deletedProperty = getServiceAdditionalInformation(serviceId, fromJson.getUniqueId(), user); + assertNotNull("check response object is not null after update additional information", deletedProperty); + assertNotNull("check error code exists in response after additional information", deletedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 200, deletedProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo updatedJson = gson.fromJson(deletedProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", updatedJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", updatedJson.getKey()); + assertEquals("check returned value", value, updatedJson.getValue()); + assertEquals("check returned id", fromJson.getUniqueId(), updatedJson.getUniqueId()); + + } + + @Test + public void getResourceAllAdditionalInformationTest() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + RestResponse deletedProperty = getResourceAllAdditionalInformation(resourceId, user); + assertNotNull("check response object is not null after update additional information", deletedProperty); + assertNotNull("check error code exists in response after additional information", deletedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 200, deletedProperty.getErrorCode().intValue()); + + AdditionalInformationDefinition updatedJson = gson.fromJson(deletedProperty.getResponse(), AdditionalInformationDefinition.class); + assertEquals("check number of parameters", 1, updatedJson.getParameters().size()); + AdditionalInfoParameterInfo info = updatedJson.getParameters().iterator().next(); + + assertFalse("check number of spaces", info.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", info.getKey()); + assertEquals("check returned value", value, info.getValue()); + assertEquals("check returned id", fromJson.getUniqueId(), info.getUniqueId()); + + } + + @Test + public void getServiceAllAdditionalInformationTest() throws Exception { + User user = getUser(); + + RestResponse createServiceResponse = createService(); + + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + RestResponse deletedProperty = getServiceAllAdditionalInformation(serviceId, user); + assertNotNull("check response object is not null after update additional information", deletedProperty); + assertNotNull("check error code exists in response after additional information", deletedProperty.getErrorCode()); + assertEquals("Check response code after additional information", 200, deletedProperty.getErrorCode().intValue()); + + AdditionalInformationDefinition updatedJson = gson.fromJson(deletedProperty.getResponse(), AdditionalInformationDefinition.class); + assertEquals("check number of parameters", 1, updatedJson.getParameters().size()); + AdditionalInfoParameterInfo info = updatedJson.getParameters().iterator().next(); + + assertFalse("check number of spaces", info.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", info.getKey()); + assertEquals("check returned value", value, info.getValue()); + assertEquals("check returned id", fromJson.getUniqueId(), info.getUniqueId()); + + } + + @Test + public void createServiceAdditionalInformationTestDuringLifecycle() throws Exception { + + User user = getUser(); + RestResponse createServiceResponse = createService(); + String serviceId = ResponseParser.convertServiceResponseToJavaObject(createServiceResponse.getResponse()).getUniqueId(); + String key = "AAA AAA"; + String value = "BBBB"; + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createServiceAdditionalInformation(serviceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + AdditionalInfoParameterInfo fromJson = gson.fromJson(createProperty.getResponse(), AdditionalInfoParameterInfo.class); + assertFalse("check number of spaces", fromJson.getKey().contains(" ")); + assertEquals("check returned key", "AAA AAA", fromJson.getKey()); + + ServiceReqDetails serviceDetails = getServiceDetails(); + + serviceDetails.setUniqueId(serviceId); + + // serviceUtils.addServiceMandatoryArtifacts(user, + // createServiceResponse); + + certifyService(user, serviceDetails, null); + + } + + @Test + public void createCascadeResource() { + + // TODO: to check after rebase + + User user = getUser(); + ResourceReqDetails resource = getResource(); + String newResourceNameSuffix = "aa"; + + RestResponse createResourceResponse = null; + try { + + createResourceResponse = createResource(resource, user); + assertEquals("check invalid type", 201, createResourceResponse.getErrorCode().intValue()); + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + String resourceVersion = "0.1"; + // resourceUtils.addResourceMandatoryArtifacts(user, + // createResourceResponse); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + resource.setUniqueId(resourceId); + Resource certifiedResource = certifyResource(user, resource, resourceVersion, 1); + + ResourceReqDetails newResourceDetails = getResource(); + String newResourceName = newResourceDetails.getName() + newResourceNameSuffix; + newResourceDetails.setName(newResourceName); + List derivedFrom = new ArrayList<>(); + derivedFrom.add(certifiedResource.getName()); + newResourceDetails.setDerivedFrom(derivedFrom); + newResourceDetails.getTags().add(newResourceName); + + user.setUserId(UserRoleEnum.ADMIN.getUserId()); + RestResponse newCreateResourceResponse = createResource(newResourceDetails, user); + assertEquals("Check response code after creating resource", 201, newCreateResourceResponse.getErrorCode().intValue()); + Resource newResource = gson.fromJson(newCreateResourceResponse.getResponse(), Resource.class); + + RestResponse allAdditionalInformation = getResourceAllAdditionalInformation(newResource.getUniqueId(), user); + + assertNotNull("check response object is not null after update additional information", allAdditionalInformation); + assertNotNull("check error code exists in response after additional information", allAdditionalInformation.getErrorCode()); + assertEquals("Check response code after additional information", 200, allAdditionalInformation.getErrorCode().intValue()); + + AdditionalInformationDefinition updatedJson = gson.fromJson(allAdditionalInformation.getResponse(), AdditionalInformationDefinition.class); + assertEquals("check number of parameters", 0, updatedJson.getParameters().size()); + // AdditionalInfoParameterInfo info = + // updatedJson.getParameters().iterator().next(); + + String newResourceId = newResource.getUniqueId(); + createProperty = createResourceAdditionalInformation(newResourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + allAdditionalInformation = getResourceAllAdditionalInformation(newResourceId, user); + + assertNotNull("check response object is not null after update additional information", allAdditionalInformation); + assertNotNull("check error code exists in response after additional information", allAdditionalInformation.getErrorCode()); + assertEquals("Check response code after additional information", 200, allAdditionalInformation.getErrorCode().intValue()); + + updatedJson = gson.fromJson(allAdditionalInformation.getResponse(), AdditionalInformationDefinition.class); + assertEquals("check number of parameters", 1, updatedJson.getParameters().size()); + + } catch (IOException e) { + assertTrue(false); + } + + } + + @Test + public void createSamePropertyAfterCiCOResource() { + + User user = getUser(); + ResourceReqDetails resource = getResource(); + + RestResponse createResourceResponse = null; + try { + + createResourceResponse = createResource(resource, user); + assertEquals("check invalid type", 201, createResourceResponse.getErrorCode().intValue()); + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + String resourceVersion = "0.1"; + // resourceUtils.addResourceMandatoryArtifacts(user, + // createResourceResponse); + + String key = "AAA AAA"; + String value = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + resource.setUniqueId(resourceId); + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CHECKIN); + + assertNotNull("check response object is not null after create user", checkInResponse); + assertNotNull("check error code exists in response after create user", checkInResponse.getErrorCode()); + assertEquals("Check response code after create user", 200, checkInResponse.getErrorCode().intValue()); + + Resource resourceAfterOperation = gson.fromJson(checkInResponse.getResponse(), Resource.class); + assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().size()); + assertEquals("check size of additional information", 1, resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + + RestResponse checkOutResponse = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CHECKOUT); + + assertNotNull("check response object is not null after create user", checkOutResponse); + assertNotNull("check error code exists in response after create user", checkOutResponse.getErrorCode()); + assertEquals("Check response code after create user", 200, checkOutResponse.getErrorCode().intValue()); + + Resource resourceAfterCoOperation = gson.fromJson(checkOutResponse.getResponse(), Resource.class); + assertEquals("check size of additional information", 1, resourceAfterCoOperation.getAdditionalInformation().size()); + assertEquals("check size of additional information", 1, resourceAfterCoOperation.getAdditionalInformation().get(0).getParameters().size()); + + String newResourceId = ResponseParser.getUniqueIdFromResponse(checkOutResponse); + + String key2 = "ZZZ"; + String value2 = "BBBB"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo2 = new AdditionalInfoParameterInfo(null, key2, value2); + + RestResponse createProperty2 = createResourceAdditionalInformation(newResourceId, additionalInfoParameterInfo2, user); + assertNotNull("check response object is not null after create property", createProperty2); + assertNotNull("check error code exists in response after create property", createProperty2.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty2.getErrorCode().intValue()); + + RestResponse afterCreateAI = ResourceRestUtils.getResource(user, newResourceId); + Resource resourceNew = gson.fromJson(afterCreateAI.getResponse(), Resource.class); + assertEquals("check size of additional information", 1, resourceNew.getAdditionalInformation().size()); + assertEquals("check size of additional information", 2, resourceNew.getAdditionalInformation().get(0).getParameters().size()); + + resource.setUniqueId(newResourceId); + Resource certifiedResource = certifyResource(user, resource, resourceVersion, 2); + assertEquals("check size of additional information", 1, certifiedResource.getAdditionalInformation().size()); + assertEquals("check size of additional information", 2, certifiedResource.getAdditionalInformation().get(0).getParameters().size()); + + user.setUserId(UserRoleEnum.DESIGNER.getUserId()); + resource.setUniqueId(certifiedResource.getUniqueId()); + RestResponse checkOutResponseAfterCertify = LifecycleRestUtils.changeResourceState(resource, user, resourceVersion, LifeCycleStatesEnum.CHECKOUT); + + assertNotNull("check response object is not null after create user", checkOutResponseAfterCertify); + assertNotNull("check error code exists in response after create user", checkOutResponseAfterCertify.getErrorCode()); + assertEquals("Check response code after create user", 200, checkOutResponseAfterCertify.getErrorCode().intValue()); + + Resource resourceAfterCertifyCoOperation = gson.fromJson(checkOutResponseAfterCertify.getResponse(), Resource.class); + assertEquals("check size of additional information", 1, resourceAfterCertifyCoOperation.getAdditionalInformation().size()); + assertEquals("check size of additional information", 2, resourceAfterCertifyCoOperation.getAdditionalInformation().get(0).getParameters().size()); + + } catch (IOException e) { + assertTrue(false); + } + + } + + // public Resource certifyService(User user, ServiceReqDetails service, + // String resourceVersion) throws Exception { + // + // RestResponse checkInResponse = + // LifecycleRestUtils.changeServiceState(service, user, resourceVersion, + // LifeCycleStates.CHECKIN); + // + // assertNotNull("check response object is not null after create user", + // checkInResponse); + // assertNotNull("check error code exists in response after create user", + // checkInResponse.getErrorCode()); + // assertEquals("Check response code after create user", 200, + // checkInResponse.getErrorCode().intValue()); + // + // Resource resourceAfterOperation = + // gson.fromJson(checkInResponse.getResponse(), Resource.class); + // assertEquals("check size of additional information", 1, + // resourceAfterOperation.getAdditionalInformation().size()); + // assertEquals("check size of additional information", 1, + // resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + // + //// TODO Andrey + // createAndAddCertResourceToService(service, user); + // + // RestResponse req4certResponse = + // LifecycleRestUtils.changeServiceState(service, user, resourceVersion, + // LifeCycleStates.CERTIFICATIONREQUEST); + // + // assertNotNull("check response object is not null after create user", + // req4certResponse); + // assertEquals("Check response code after checkout resource", 200, + // req4certResponse.getErrorCode().intValue()); + // + // resourceAfterOperation = gson.fromJson(req4certResponse.getResponse(), + // Resource.class); + // assertEquals("check size of additional information", 1, + // resourceAfterOperation.getAdditionalInformation().size()); + // assertEquals("check size of additional information", 1, + // resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + // + // //change modifier + // user.setUserId(UserRoleEnum.TESTER.getUserId()); + // + // //start certification + // RestResponse startCertResourceResponse3 = + // LifecycleRestUtils.changeServiceState(service, user, resourceVersion, + // LifeCycleStates.STARTCERTIFICATION); + // assertNotNull("check response object is not null after create user", + // startCertResourceResponse3); + // assertEquals("Check response code after checkout resource", 200, + // startCertResourceResponse3.getErrorCode().intValue()); + // + // resourceAfterOperation = + // gson.fromJson(startCertResourceResponse3.getResponse(), Resource.class); + // assertEquals("check size of additional information", 1, + // resourceAfterOperation.getAdditionalInformation().size()); + // assertEquals("check size of additional information", 1, + // resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + // + // //certify + // + // RestResponse certifyResponse = + // LifecycleRestUtils.changeServiceState(service, user, resourceVersion, + // LifeCycleStates.CERTIFY); + // assertNotNull("check response object is not null after create user", + // certifyResponse); + // assertEquals("Check response code after checkout resource", 200, + // certifyResponse.getErrorCode().intValue()); + // + // resourceAfterOperation = gson.fromJson(certifyResponse.getResponse(), + // Resource.class); + // assertEquals("check size of additional information", 1, + // resourceAfterOperation.getAdditionalInformation().size()); + // assertEquals("check size of additional information", 1, + // resourceAfterOperation.getAdditionalInformation().get(0).getParameters().size()); + // + // Resource certifyResource = gson.fromJson(certifyResponse.getResponse(), + // Resource.class); + // return certifyResource; + // } + + private void createAndAddCertResourceToService(ServiceReqDetails serviceDetails, User user) throws Exception { + + User sdncTesterUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory.getDefaultComponentInstance(); + + RestResponse response = ResourceRestUtils.createResource(resourceDetails, user); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("resource uniqueId is null:", resourceDetails.getUniqueId()); + + ArtifactReqDetails heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, user, resourceDetails.getUniqueId()); + assertTrue("add HEAT artifact to resource request returned status:" + response.getErrorCode(), response.getErrorCode() == 200); + + // certified resource + // response = LCSbaseTest.certifyResource(resourceDetails); + RestResponse restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, user, LifeCycleStatesEnum.CHECKIN); + assertTrue("certify resource request returned status:" + restResponseResource.getErrorCode(), response.getErrorCode() == 200); + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, user, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertTrue("certify resource request returned status:" + restResponseResource.getErrorCode(), response.getErrorCode() == 200); + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncTesterUser, LifeCycleStatesEnum.STARTCERTIFICATION); + assertTrue("certify resource request returned status:" + restResponseResource.getErrorCode(), response.getErrorCode() == 200); + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncTesterUser, LifeCycleStatesEnum.CERTIFY); + assertTrue("certify resource request returned status:" + restResponseResource.getErrorCode(), response.getErrorCode() == 200); + + // add resource instance with HEAT deployment artifact to the service + restResponseResource = LifecycleRestUtils.changeServiceState(serviceDetails, user, serviceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertTrue("certify resource request returned status:" + restResponseResource.getErrorCode(), response.getErrorCode() == 200); + resourceInstanceReqDetails.setComponentUid(resourceDetails.getUniqueId()); + response = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, user, serviceDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + assertTrue("response code is not 201, returned: " + response.getErrorCode(), response.getErrorCode() == 201); + } + + @Test + public void createResourceAdditionalInformationTestAddValue() throws Exception { + User user = getUser(); + ResourceReqDetails resource = getResource(); + + // deleteResource(resourceId, user); + RestResponse createResourceResponse = createResource(resource, user); + + String resourceId = ResponseParser.getUniqueIdFromResponse(createResourceResponse); + + assertNotNull("check response object is not null after create resource", createResourceResponse); + assertNotNull("check error code exists in response after create resource", createResourceResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResourceResponse.getErrorCode().intValue()); + + String key = "AAA AAA"; + String value = "\uC2B5"; + + AdditionalInfoParameterInfo additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + RestResponse createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + value = ""; + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 400, createProperty.getErrorCode().intValue()); + + value = "----<>;"; + + additionalInfoParameterInfo = new AdditionalInfoParameterInfo(null, key, value); + + createProperty = createResourceAdditionalInformation(resourceId, additionalInfoParameterInfo, user); + assertNotNull("check response object is not null after create property", createProperty); + assertNotNull("check error code exists in response after create property", createProperty.getErrorCode()); + assertEquals("Check response code after create property", 201, createProperty.getErrorCode().intValue()); + + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/ComponentInstancePropertyTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/ComponentInstancePropertyTest.java new file mode 100644 index 0000000000..6ba1b2ccca --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/ComponentInstancePropertyTest.java @@ -0,0 +1,1263 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.property; + +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.PropertyReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.PropertyRestUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import fj.data.Either; + +// open bug for this class: DE199108 - closed, DE199741 +public class ComponentInstancePropertyTest extends ComponentBaseTest { + + protected Resource basicVFC; + protected Resource vfc1FromBasicVFC; + protected Resource vfc2FromVfc1; + protected Resource vfResource; + + private List expectedPropertyList; + private List actualPropertyList; + // protected String updatedStringValue = "{Not Default String Value}"; + protected String updatedStringValue = "Not Default String Value"; + protected String updatedIntegerValue = "666"; + protected String updatedBooleanValue = "false"; + protected String newStringPropName = "stringProp2"; + protected String newIntegerPropName = "integerProp2"; + protected String newBooleanPropName = "booleanProp2"; + // bug DE199741 protected String newStringPropValue = ""; + protected String newStringPropValue = "second string value"; + protected String newIntegerPropValue = "888"; + protected String newBooleanPropValue = "false"; + + @BeforeMethod + public void init() { + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + } + + @Rule + public static TestName name = new TestName(); + + public ComponentInstancePropertyTest() { + super(name, ComponentInstancePropertyTest.class.getName()); + } + + // --------------Regular + // resource------------------------------------------------------------------------------- + + @Test + public void nestedResourceProperty3Levels() throws Exception { + + // first res + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + // second resource + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + // third resource + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + // verify property + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, actualPropertyList); + assertTrue("check list size failed, expected 3", actualPropertyList.size() == 3); + + } + + // --------------VF + // resource----------------------------------------------------------- + + @Test + public void nestedVfResourceProperty3Levels() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + // verify property + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + } + + @Test + public void nestedVfResourceProperty3LevelsAndCpWithProp() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + + // four resource + Resource cp = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.CP, + NormativeTypesEnum.NETWORK, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + PropertyReqDetails cpStringProperty = ElementFactory.getDefaultStringProperty(); + cpStringProperty.setName("Different Name"); + cpStringProperty.setPropertyDefaultValue("Different value from default"); + AtomicOperationUtils.addCustomPropertyToResource(cpStringProperty, cp, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + cp = AtomicOperationUtils.getResourceObject(cp, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(cp, expectedPropertyList); + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(cp, vfResource, UserRoleEnum.DESIGNER, true).left().value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, cp, expectedPropertyList, + vfResource); + // verify property + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + } + + @Test + public void nestedCertifiedVfResourceProperty3Levels() throws Exception { + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CERTIFY, vfc1FromBasicVFC); + + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + // verify property + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + } + + @Test + public void nestedVfResourceProperty3Levels2SameResInstances() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + // verify property + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + } + + // ------------------update resource + // property----------------------------------- + + @Test + public void nestedVfResourceProperty3LevelsUpdateFirstLevelProperty() throws Exception { + // first res + basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + Either propDetailsToUpdate = AtomicOperationUtils + .addDefaultPropertyToResource(PropertyTypeEnum.STRING, basicVFC, UserRoleEnum.DESIGNER, true); + String propNameToUpdate = propDetailsToUpdate.left().value().getName(); + String propTypeToUpdate = propDetailsToUpdate.left().value().getType(); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + + // verify property + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + // update property + ComponentInstanceProperty expectedUpdatePropDetails = PropertyRestUtils + .getPropFromListByPropNameAndType(actualPropertyList, propNameToUpdate, propTypeToUpdate); + expectedUpdatePropDetails.setValue(updatedStringValue); + String propUniqeId = expectedUpdatePropDetails.getUniqueId(); + RestResponse updatePropertyValueOnResourceInstance = ComponentInstanceRestUtils + .updatePropertyValueOnResourceInstance(vfResource, componentInstDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), expectedUpdatePropDetails); + assertTrue("expected updatePropertyValueOnResourceInstance response code: " + BaseRestUtils.STATUS_CODE_SUCCESS, + updatePropertyValueOnResourceInstance.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + actualPropertyList = new ArrayList<>(); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + + ComponentInstanceProperty actualUpdatedPropDetails = PropertyRestUtils + .getPropFromListByPropIdAndPath(actualPropertyList, propUniqeId, null); + assertTrue("property was not updated propely", + PropertyRestUtils.comparePropertyObjects(expectedUpdatePropDetails, actualUpdatedPropDetails, true)); + + } + + @Test + public void nestedVfResourceProperty3LevelsUpdateSecondLevelProperty() throws Exception { + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + + // second resource + vfc1FromBasicVFC = AtomicOperationUtils.createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum.VFC, + basicVFC, ResourceCategoryEnum.APPLICATION_L4_BORDER, UserRoleEnum.DESIGNER, true).left().value(); + Either propDetailsToUpdate = AtomicOperationUtils + .addCustomPropertyToResource(ElementFactory.getDefaultIntegerProperty(), vfc1FromBasicVFC, + UserRoleEnum.DESIGNER, true); + String propNameToUpdate = propDetailsToUpdate.left().value().getName(); + String propTypeToUpdate = propDetailsToUpdate.left().value().getType(); + AtomicOperationUtils.changeComponentState(vfc1FromBasicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, + true); + + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + + // verify property + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + // update property + ComponentInstanceProperty expectedUpdatePropDetails = PropertyRestUtils + .getPropFromListByPropNameAndType(actualPropertyList, propNameToUpdate, propTypeToUpdate); + expectedUpdatePropDetails.setValue(updatedIntegerValue); + String propUniqeId = expectedUpdatePropDetails.getUniqueId(); + RestResponse updatePropertyValueOnResourceInstance = ComponentInstanceRestUtils + .updatePropertyValueOnResourceInstance(vfResource, componentInstDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), expectedUpdatePropDetails); + assertTrue( + "expected updatePropertyValueOnResourceInstance response code: " + BaseRestUtils.STATUS_CODE_SUCCESS + + " ,but was " + updatePropertyValueOnResourceInstance.getErrorCode(), + updatePropertyValueOnResourceInstance.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + actualPropertyList = new ArrayList<>(); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + ComponentInstanceProperty actualUpdatedPropDetails = PropertyRestUtils + .getPropFromListByPropIdAndPath(actualPropertyList, propUniqeId, null); + assertTrue("property was not updated properly", + PropertyRestUtils.comparePropertyObjects(expectedUpdatePropDetails, actualUpdatedPropDetails, true)); + + } + + @Test + public void nestedVfResourceProperty3LevelsUpdateThirdLevelProperty() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + + // third resource + vfc2FromVfc1 = AtomicOperationUtils.createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum.VFC, + vfc1FromBasicVFC, ResourceCategoryEnum.GENERIC_DATABASE, UserRoleEnum.DESIGNER, true).left().value(); + Either propDetailsToUpdate = AtomicOperationUtils + .addCustomPropertyToResource(ElementFactory.getDefaultBooleanProperty(), vfc2FromVfc1, + UserRoleEnum.DESIGNER, true); + String propNameToUpdate = propDetailsToUpdate.left().value().getName(); + String propTypeToUpdate = propDetailsToUpdate.left().value().getType(); + AtomicOperationUtils.changeComponentState(vfc2FromVfc1, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, + true); + + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + + // verify property + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + // update property + ComponentInstanceProperty expectedUpdatePropDetails = PropertyRestUtils + .getPropFromListByPropNameAndType(actualPropertyList, propNameToUpdate, propTypeToUpdate); + expectedUpdatePropDetails.setValue(updatedBooleanValue); + String propUniqeId = expectedUpdatePropDetails.getUniqueId(); + RestResponse updatePropertyValueOnResourceInstance = ComponentInstanceRestUtils + .updatePropertyValueOnResourceInstance(vfResource, componentInstDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), expectedUpdatePropDetails); + assertTrue("expected updatePropertyValueOnResourceInstance response code: " + BaseRestUtils.STATUS_CODE_SUCCESS, + updatePropertyValueOnResourceInstance.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + actualPropertyList = new ArrayList<>(); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + ComponentInstanceProperty actualUpdatedPropDetails = PropertyRestUtils + .getPropFromListByPropIdAndPath(actualPropertyList, propUniqeId, null); + assertTrue("property was not updated propely", + PropertyRestUtils.comparePropertyObjects(expectedUpdatePropDetails, actualUpdatedPropDetails, true)); + + } + + // ---------------------Service------------------------------------------------------------------------ + + /** + * Service-->VF1(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p3) (p2) (p1) + */ + @Test + public void serviceWithNestedResourceProperty3Levels() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + } + + /** + * Service-->VF1(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p4) (p3) (p2) + * (p1) + */ + @Test + public void serviceWithNestedResourceProperty3LevelsAndVfProperty() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + PropertyReqDetails propDetails = ElementFactory.getDefaultBooleanProperty(); + propDetails.setName(newBooleanPropName); + propDetails.setPropertyDefaultValue(newBooleanPropValue); + AtomicOperationUtils.addCustomPropertyToResource(propDetails, vfResource, UserRoleEnum.DESIGNER, true); + propDetails = ElementFactory.getDefaultStringProperty(); + propDetails.setName(newStringPropName); + propDetails.setPropertyDefaultValue(newStringPropValue); + AtomicOperationUtils.addCustomPropertyToResource(propDetails, vfResource, UserRoleEnum.DESIGNER, true); + propDetails = ElementFactory.getDefaultIntegerProperty(); + propDetails.setName(newIntegerPropName); + propDetails.setPropertyDefaultValue(newIntegerPropValue); + AtomicOperationUtils.addCustomPropertyToResource(propDetails, vfResource, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfResource, expectedPropertyList); + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + } + + /** + * Service-->VF1(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p4) (p3) (p2) + * (p1) CP(VF inst) (p5) + */ + @Test + public void serviceWithNestedResourceProperty3LevelsAndCp() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + + // four resource + Resource cp = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.CP, + NormativeTypesEnum.NETWORK, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + PropertyReqDetails cpStringProperty = ElementFactory.getDefaultStringProperty(); + cpStringProperty.setName("Different Name"); + cpStringProperty.setPropertyDefaultValue("Different value from default"); + AtomicOperationUtils.addCustomPropertyToResource(cpStringProperty, cp, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + cp = AtomicOperationUtils.getResourceObject(cp, UserRoleEnum.DESIGNER); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(cp, expectedPropertyList); + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(cp, vfResource, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, cp, expectedPropertyList, + vfResource); + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + } + + /** + * Service-->VF1(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p4) (p3) (p2) + * (p1) CP(inst) (p5) + */ + @Test + public void serviceWithNestedResourceProperty3LevelsAndCpResInst() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + // expectedPropertyList = + // PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, + // expectedPropertyList); + + // four resource + Resource cp = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.CP, + NormativeTypesEnum.NETWORK, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + PropertyReqDetails cpStringProperty = ElementFactory.getDefaultStringProperty(); + cpStringProperty.setName("Different Name"); + cpStringProperty.setPropertyDefaultValue("Different value from default"); + AtomicOperationUtils.addCustomPropertyToResource(cpStringProperty, cp, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(cp, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + cp = AtomicOperationUtils.getResourceObject(cp, UserRoleEnum.DESIGNER); + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + // Service + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(cp, expectedPropertyList); + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(cp, service, UserRoleEnum.DESIGNER, true).left().value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + } + + /** + * Service-->VF1(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) | (p3) (p2) (p1) + * | (VFC(inst)-->VFC-->VFC-->VFC) (p3) (p2) (p1) + * + * VF2(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) | (p3') (p2') (p1') | + * (VFC(inst)-->VFC-->VFC-->VFC) (p3) (p2) (p1) + */ + @Test + public void serviceNestedVfResourceProperty3Levels2SameResInstances() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, expectedPropertyList); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + // verify property + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnResource(componentInstDetails, vfc2FromVfc1, expectedPropertyList, + vfResource); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + // Service + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + } + + // service test template + /** + * Service-->VF(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p4) (p3) (p2) + * (p1) + */ + @Test + public void serviceNestedVfResourceProperty3LevelsAndSelfVfProperty() throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + PropertyReqDetails newProp = ElementFactory.getDefaultStringProperty(); + newProp.setName(newStringPropName); + newProp.setPropertyDefaultValue(newStringPropValue); + AtomicOperationUtils.addCustomPropertyToResource(newProp, vfResource, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + // Service + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + } + + /** + * update property(p4) + * + * + * VFC(p1) ^ | VFC(p2) ^ | Service-->VF(inst)-->VF-->(VFC(inst)-->VFC(p3) + * (p4) + */ + @Test + public void serviceNestedVfResourceProperty3LevelsAndSelfVfProperty_UpdateVfproperty() throws Exception { + // Create VFC(check-in state) derived from another resource + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + + // add property to VF + PropertyReqDetails newProp = ElementFactory.getDefaultStringProperty(); + newProp.setName(newStringPropName); + newProp.setPropertyDefaultValue(newStringPropValue); + Either propDetailsToUpdate = AtomicOperationUtils + .addCustomPropertyToResource(newProp, vfResource, UserRoleEnum.DESIGNER, true); + String propNameToUpdate = propDetailsToUpdate.left().value().getName(); + String propTypeToUpdate = propDetailsToUpdate.left().value().getType(); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + // Service + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + // update VF instance property + ComponentInstanceProperty expectedUpdatePropDetails = PropertyRestUtils + .getPropFromListByPropNameAndType(actualPropertyList, propNameToUpdate, propTypeToUpdate); + expectedUpdatePropDetails.setValue(updatedStringValue); + String propUniqeId = expectedUpdatePropDetails.getUniqueId(); + RestResponse updatePropertyValueOnResourceInstance = ComponentInstanceRestUtils + .updatePropertyValueOnResourceInstance(service, componentInstDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), expectedUpdatePropDetails); + assertTrue("expected updatePropertyValueOnResourceInstance response code: " + BaseRestUtils.STATUS_CODE_SUCCESS, + updatePropertyValueOnResourceInstance.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + + actualPropertyList = new ArrayList<>(); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + + ComponentInstanceProperty actualUpdatedPropDetails = PropertyRestUtils + .getPropFromListByPropIdAndPath(actualPropertyList, propUniqeId, null); + assertTrue("property was not updated propely", + PropertyRestUtils.comparePropertyObjects(expectedUpdatePropDetails, actualUpdatedPropDetails, true)); + + } + + /** + * update property(p1) + * Service-->VF(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p4) (p3) (p2) + * (p1) + */ + @Test + public void serviceNestedVfResourceProperty3LevelsAndSelfVfPropertyUpdateVfInheritance1LevelProperty() + throws Exception { + + basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + Either propDetailsToUpdate = AtomicOperationUtils + .addDefaultPropertyToResource(PropertyTypeEnum.STRING, basicVFC, UserRoleEnum.DESIGNER, true); + String propNameToUpdate = propDetailsToUpdate.left().value().getName(); + String propTypeToUpdate = propDetailsToUpdate.left().value().getType(); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + // verify property + PropertyReqDetails newProp = ElementFactory.getDefaultStringProperty(); + newProp.setName(newStringPropName); + newProp.setPropertyDefaultValue(newStringPropValue); + AtomicOperationUtils.addCustomPropertyToResource(newProp, vfResource, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + // Service + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + // update VF property + ComponentInstanceProperty expectedUpdatePropDetails = PropertyRestUtils + .getPropFromListByPropNameAndType(actualPropertyList, propNameToUpdate, propTypeToUpdate); + expectedUpdatePropDetails.setValue(updatedStringValue); + String propUniqeId = expectedUpdatePropDetails.getUniqueId(); + RestResponse updatePropertyValueOnResourceInstance = ComponentInstanceRestUtils + .updatePropertyValueOnResourceInstance(service, componentInstDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), expectedUpdatePropDetails); + assertTrue("expected updatePropertyValueOnResourceInstance response code: " + BaseRestUtils.STATUS_CODE_SUCCESS, + updatePropertyValueOnResourceInstance.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + + actualPropertyList = new ArrayList<>(); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + + ComponentInstanceProperty actualUpdatedPropDetails = PropertyRestUtils + .getPropFromListByPropIdAndPath(actualPropertyList, propUniqeId, null); + assertTrue("property was not updated propely", + PropertyRestUtils.comparePropertyObjects(expectedUpdatePropDetails, actualUpdatedPropDetails, true)); + + } + + /** + * update property(p2) + * Service-->VF(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p4) (p3) (p2) + * (p1) + */ + @Test + public void serviceNestedVfResourceProperty3LevelsAndSelfVfPropertyUpdateVfInheritance2LevelProperty() + throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = AtomicOperationUtils.createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum.VFC, + basicVFC, ResourceCategoryEnum.APPLICATION_L4_BORDER, UserRoleEnum.DESIGNER, true).left().value(); + Either propDetailsToUpdate = AtomicOperationUtils + .addCustomPropertyToResource(ElementFactory.getDefaultIntegerProperty(), vfc1FromBasicVFC, + UserRoleEnum.DESIGNER, true); + String propNameToUpdate = propDetailsToUpdate.left().value().getName(); + String propTypeToUpdate = propDetailsToUpdate.left().value().getType(); + AtomicOperationUtils.changeComponentState(vfc1FromBasicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, + true); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + + // verify property + PropertyReqDetails newProp = ElementFactory.getDefaultStringProperty(); + newProp.setName(newStringPropName); + newProp.setPropertyDefaultValue(newStringPropValue); + AtomicOperationUtils.addCustomPropertyToResource(newProp, vfResource, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + // Service + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + // update VF property + ComponentInstanceProperty expectedUpdatePropDetails = PropertyRestUtils + .getPropFromListByPropNameAndType(actualPropertyList, propNameToUpdate, propTypeToUpdate); + expectedUpdatePropDetails.setValue(updatedIntegerValue); + String propUniqeId = expectedUpdatePropDetails.getUniqueId(); + RestResponse updatePropertyValueOnResourceInstance = ComponentInstanceRestUtils + .updatePropertyValueOnResourceInstance(service, componentInstDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), expectedUpdatePropDetails); + assertTrue("expected updatePropertyValueOnResourceInstance response code: " + BaseRestUtils.STATUS_CODE_SUCCESS, + updatePropertyValueOnResourceInstance.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + actualPropertyList = new ArrayList<>(); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + ComponentInstanceProperty actualUpdatedPropDetails = PropertyRestUtils + .getPropFromListByPropIdAndPath(actualPropertyList, propUniqeId, null); + assertTrue("property was not updated propely", + PropertyRestUtils.comparePropertyObjects(expectedUpdatePropDetails, actualUpdatedPropDetails, true)); + + } + + /** + * update property(p3) + * Service-->VF(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p4) (p3) (p2) + * (p1) + */ + @Test + public void serviceNestedVfResourceProperty3LevelsAndSelfVfPropertyUpdateVfInheritance3LevelProperty() + throws Exception { + + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = AtomicOperationUtils.createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum.VFC, + vfc1FromBasicVFC, ResourceCategoryEnum.GENERIC_DATABASE, UserRoleEnum.DESIGNER, true).left().value(); + Either propDetailsToUpdate = AtomicOperationUtils + .addCustomPropertyToResource(ElementFactory.getDefaultBooleanProperty(), vfc2FromVfc1, + UserRoleEnum.DESIGNER, true); + String propNameToUpdate = propDetailsToUpdate.left().value().getName(); + String propTypeToUpdate = propDetailsToUpdate.left().value().getType(); + AtomicOperationUtils.changeComponentState(vfc2FromVfc1, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, + true); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + // verify property + PropertyReqDetails newProp = ElementFactory.getDefaultStringProperty(); + newProp.setName(newStringPropName); + newProp.setPropertyDefaultValue(newStringPropValue); + AtomicOperationUtils.addCustomPropertyToResource(newProp, vfResource, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + // Service + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + // update VF property + ComponentInstanceProperty expectedUpdatePropDetails = PropertyRestUtils + .getPropFromListByPropNameAndType(actualPropertyList, propNameToUpdate, propTypeToUpdate); + expectedUpdatePropDetails.setValue(updatedBooleanValue); + String propUniqeId = expectedUpdatePropDetails.getUniqueId(); + RestResponse updatePropertyValueOnResourceInstance = ComponentInstanceRestUtils + .updatePropertyValueOnResourceInstance(service, componentInstDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), expectedUpdatePropDetails); + assertTrue("expected updatePropertyValueOnResourceInstance response code: " + BaseRestUtils.STATUS_CODE_SUCCESS, + updatePropertyValueOnResourceInstance.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + + actualPropertyList = new ArrayList<>(); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + + ComponentInstanceProperty actualUpdatedPropDetails = PropertyRestUtils + .getPropFromListByPropIdAndPath(actualPropertyList, propUniqeId, null); + assertTrue("property was not updated propely", + PropertyRestUtils.comparePropertyObjects(expectedUpdatePropDetails, actualUpdatedPropDetails, true)); + + } + + /** + * update property p5' + * Service-->VF1(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p4) (p3) (p2) + * (p1) CP(inst on VF) (p5) CP(inst) (p5') + */ + @Test + public void serviceWithNestedResourceProperty3LevelsAndCpOnVfUpdateCpInstanceOfService() throws Exception { + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CHECKIN, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + // expectedPropertyList = + // PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, + // expectedPropertyList); + + // four resource + Resource cp = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.CP, + NormativeTypesEnum.NETWORK, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + PropertyReqDetails cpStringProperty = ElementFactory.getDefaultStringProperty(); + cpStringProperty.setName("Different Name"); + cpStringProperty.setPropertyDefaultValue("Different value from default"); + AtomicOperationUtils.addCustomPropertyToResource(cpStringProperty, cp, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(cp, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + cp = AtomicOperationUtils.getResourceObject(cp, UserRoleEnum.DESIGNER); + // create VF + add RI + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(cp, vfResource, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + // Service + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(cp, expectedPropertyList); + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(cp, service, UserRoleEnum.DESIGNER, true).left().value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + + // service = AtomicOperationUtils.getServiceObject(service, + // UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + String propNameToUpdate = "cidr"; + String propTypeToUpdate = "string"; + + // update CP property + ComponentInstanceProperty expectedUpdatePropDetails = PropertyRestUtils.getCompPropInstListByInstIdAndPropName( + service, componentInstDetails, propNameToUpdate, propTypeToUpdate); + expectedUpdatePropDetails.setValue(updatedStringValue); + String propUniqeId = expectedUpdatePropDetails.getUniqueId(); + List path = expectedUpdatePropDetails.getPath(); + RestResponse updatePropertyValueOnResourceInstance = ComponentInstanceRestUtils + .updatePropertyValueOnResourceInstance(service, componentInstDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), expectedUpdatePropDetails); + assertTrue("expected updatePropertyValueOnResourceInstance response code: " + BaseRestUtils.STATUS_CODE_SUCCESS, + updatePropertyValueOnResourceInstance.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + + actualPropertyList = new ArrayList<>(); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + + ComponentInstanceProperty actualUpdatedPropDetails = PropertyRestUtils + .getPropFromListByPropIdAndPath(actualPropertyList, propUniqeId, path); + assertTrue("property was not updated propely", + PropertyRestUtils.comparePropertyObjects(expectedUpdatePropDetails, actualUpdatedPropDetails, true)); + } + + /** + * update property p5 + * Service-->VF1(inst)-->VF-->(VFC(inst)-->VFC-->VFC-->VFC) (p4) (p3) (p2) + * (p1) CP(inst on VF) (p5) CP(inst) (p5') + */ + @Test + public void serviceWithNestedResourceProperty3LevelsAndCpOnVfUpdateCpInstanceOfVf() throws Exception { + basicVFC = createResourceWithProperty(ElementFactory.getDefaultStringProperty(), LifeCycleStatesEnum.CERTIFY); + vfc1FromBasicVFC = createResourceWithPropertyDerivedFromOtherResource( + ElementFactory.getDefaultIntegerProperty(), LifeCycleStatesEnum.CERTIFY, basicVFC); + vfc2FromVfc1 = createResourceWithPropertyDerivedFromOtherResource(ElementFactory.getDefaultBooleanProperty(), + LifeCycleStatesEnum.CERTIFY, vfc1FromBasicVFC); + vfc2FromVfc1 = AtomicOperationUtils.getResourceObject(vfc2FromVfc1, UserRoleEnum.DESIGNER); + // expectedPropertyList = + // PropertyRestUtils.addResourcePropertiesToList(vfc2FromVfc1, + // expectedPropertyList); + + // four resource + Resource cp = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.CP, + NormativeTypesEnum.NETWORK, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + PropertyReqDetails cpStringProperty = ElementFactory.getDefaultStringProperty(); + cpStringProperty.setName("Different Name"); + cpStringProperty.setPropertyDefaultValue("Different value from default"); + AtomicOperationUtils.addCustomPropertyToResource(cpStringProperty, cp, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(cp, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + // create VF + add RI + cp = AtomicOperationUtils.getResourceObject(cp, UserRoleEnum.DESIGNER); + vfResource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + ComponentInstance componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfc2FromVfc1, vfResource, UserRoleEnum.DESIGNER, true).left() + .value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(cp, vfResource, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.changeComponentState(vfResource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + vfResource = AtomicOperationUtils.getResourceObject(vfResource, UserRoleEnum.DESIGNER); + + // Service + expectedPropertyList = new ArrayList(); + actualPropertyList = new ArrayList(); + expectedPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(vfResource, expectedPropertyList, + null); + expectedPropertyList = PropertyRestUtils.addResourcePropertiesToList(cp, expectedPropertyList); + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vfResource, service, UserRoleEnum.DESIGNER, true).left() + .value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + + componentInstDetails = AtomicOperationUtils + .addComponentInstanceToComponentContainer(cp, service, UserRoleEnum.DESIGNER, true).left().value(); + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + PropertyRestUtils.updatePropertyListWithPathOnComponentInstance(componentInstDetails, service, + expectedPropertyList); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + PropertyRestUtils.comparePropertyLists(expectedPropertyList, actualPropertyList, false); + + String propNameToUpdate = "cidr"; + String propTypeToUpdate = "string"; + + // update CP property + ComponentInstanceProperty expectedUpdatePropDetails = PropertyRestUtils.getCompPropInstListByInstIdAndPropName( + service, componentInstDetails, propNameToUpdate, propTypeToUpdate); + expectedUpdatePropDetails.setValue(updatedStringValue); + String propUniqeId = expectedUpdatePropDetails.getUniqueId(); + List path = expectedUpdatePropDetails.getPath(); + RestResponse updatePropertyValueOnResourceInstance = ComponentInstanceRestUtils + .updatePropertyValueOnResourceInstance(service, componentInstDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), expectedUpdatePropDetails); + assertTrue("expected updatePropertyValueOnResourceInstance response code: " + BaseRestUtils.STATUS_CODE_SUCCESS, + updatePropertyValueOnResourceInstance.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + service = AtomicOperationUtils.getServiceObject(service, UserRoleEnum.DESIGNER); + + actualPropertyList = new ArrayList<>(); + actualPropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, actualPropertyList, null); + + ComponentInstanceProperty actualUpdatedPropDetails = PropertyRestUtils + .getPropFromListByPropIdAndPath(actualPropertyList, propUniqeId, path); + assertTrue("property was not updated propely", + PropertyRestUtils.comparePropertyObjects(expectedUpdatePropDetails, actualUpdatedPropDetails, true)); + } + + // -------------------Methods-------------------------- + public static PropertyDataDefinition convertToPropertyDataDefinitionObject(PropertyReqDetails prop) { + PropertyDataDefinition propDataDef = new PropertyDataDefinition(); + propDataDef.setDefaultValue(prop.getPropertyDefaultValue()); + propDataDef.setType(prop.getPropertyType()); + propDataDef.setPassword(prop.getPropertyPassword()); + propDataDef.setDescription(prop.getPropertyDescription()); + return propDataDef; + } + + protected Resource createResourceWithPropertyDerivedFromOtherResource(PropertyReqDetails propertyReqDetails, + LifeCycleStatesEnum state, Resource derivedFromResource) throws Exception { + Resource resource = AtomicOperationUtils.createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum.VFC, + derivedFromResource, ResourceCategoryEnum.APPLICATION_L4_BORDER, UserRoleEnum.DESIGNER, true).left() + .value(); + if (propertyReqDetails != null) { + AtomicOperationUtils.addCustomPropertyToResource(propertyReqDetails, resource, UserRoleEnum.DESIGNER, true); + } + AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, state, true); + return AtomicOperationUtils.getResourceObject(resource, UserRoleEnum.DESIGNER); + // return resource; + } + + protected Resource createResourceWithProperty(PropertyReqDetails propertyReqDetails, LifeCycleStatesEnum state) + throws Exception { + Resource resource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + if (propertyReqDetails != null) { + AtomicOperationUtils.addCustomPropertyToResource(propertyReqDetails, resource, UserRoleEnum.DESIGNER, true); + } + AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, state, true); + return AtomicOperationUtils.getResourceObject(resource, UserRoleEnum.DESIGNER); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/ComponentProperty.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/ComponentProperty.java new file mode 100644 index 0000000000..7ecdcf457f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/ComponentProperty.java @@ -0,0 +1,1796 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.property; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_INVALID_CONTENT; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.PropertyReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class ComponentProperty extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public ComponentProperty() { + super(name, ComponentProperty.class.getName()); + } + + @DataProvider + private static final Object[][] propertiesListDefaultValueSuccessFlow() throws IOException, Exception { + return new Object[][] { + // integer + { "integer", "[1,2]", "[1,2]" }, + { "tosca.datatypes.Credential", + "[{\"protocol\":\"protocol1\",\"token\":\"token1\"},{\"protocol\":\"protocol2\",\"token\":\"token2\"}]", + "[{\"protocol\":\"protocol1\",\"token\":\"token1\"},{\"protocol\":\"protocol2\",\"token\":\"token2\"}]" }, + { "tosca.datatypes.Credential", + "[{\"protocol\":\"protocol1\",\"token\":\"token1\"},{\"protocol\":\"protocol
2\",\"token\":\"token2 2\"}]", + "[{\"protocol\":\"protocol1\",\"token\":\"token1\"},{\"protocol\":\"protocol2\",\"token\":\"token2 2\"}]" }, + { "tosca.datatypes.Credential", null, null }, { "tosca.datatypes.Credential", "[]", "[]" }, + { "integer", "[1,2,1,2]", "[1,2,1,2]" }, { "integer", "[1,,2]", "[1,2]" }, + { "integer", "[1,null,2]", "[1,2]" }, { "integer", "[1,2,null]", "[1,2]" }, + { "integer", "[null,1,2]", "[1,2]" }, { "integer", "[1,,2]", "[1,2]" }, + { "integer", "[,1,2]", "[1,2]" }, + // {"integer", + // "[1000000000000000000000000000000000000000000000000000,2]" , + // "[1000000000000000000000000000000000000000000000000000,2]"}, + { "integer", "[100000000,2]", "[100000000,2]" }, // Andrey, in + // success + // flow + // integer + // max value + // is + // 2147483647 + { "integer", null, null }, // no default value + { "integer", + "[1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2]", + "[1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2]" }, + // boolean + { "boolean", "[true,false]", "[true,false]" }, + { "boolean", "[true,false,false]", "[true,false,false]" }, + { "boolean", "[null,true,false]", "[true,false]" }, { "boolean", "[true,false,null]", "[true,false]" }, + { "boolean", "[true,,false]", "[true,false]" }, { "boolean", "[true,false,]", "[true,false]" }, + { "boolean", "[,true,false]", "[true,false]" }, { "boolean", null, null }, + // DE199713 - Default value for property type Boolean should + // support also the following values: "true", "t" , "on" , "1" , + // "false", "f" , "off" , "0" + { "boolean", "[on,off]", "[true,false]" }, { "boolean", "[ON,OFF]", "[true,false]" }, + { "boolean", "[On,Off]", "[true,false]" }, { "boolean", "[yes,no]", "[true,false]" }, + { "boolean", "[YES,NO]", "[true,false]" }, { "boolean", "[Yes,No]", "[true,false]" }, + { "boolean", "[y,n]", "[true,false]" }, { "boolean", "[Y,N]", "[true,false]" }, + // float + { "float", "[10.0,0.0]", "[10.0,0.0]" }, { "float", "[10,0]", "[10,0]" }, // contain + // integer + { "float", "[-10,-5.30]", "[-10,-5.30]" }, // Negative numbers + { "float", "[10,null,0]", "[10,0]" }, { "float", "[null,10,0]", "[10,0]" }, + { "float", "[10,0,null]", "[10,0]" }, + { "float", "[10,0.1111111111111111111111111111111111111111]", + "[10,0.1111111111111111111111111111111111111111]" }, + { "float", "[10, ,7.3 ]", "[10,7.3]" }, { "float", "[10 , 7.3 , ]", "[10,7.3]" }, + { "float", "[, , 10 , 7.3 , ]", "[10,7.3]" }, { "float", "[4.7f, -5.5f ]", "[4.7,-5.5]" }, + { "float", "[4.7f, 6.3 ,6.3, 4.7f]", "[4.7,6.3,6.3,4.7]" }, // duplicate + // value + { "float", null, null }, { "string", "[aaaa , AAAA ]", "[\"aaaa\",\"AAAA\"]" }, + + { "string", + "[1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2]", + "[\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\",\"1\",\"2\"]" }, + { "string", "[aaaa , AAAA, 1, off , true, false ]", + "[\"aaaa\",\"AAAA\",\"1\",\"off\",\"true\",\"false\"]" }, + { "string", "[aaaa , AAAA, aaaa, Aaaa , aaaa ]", "[\"aaaa\",\"AAAA\",\"aaaa\",\"Aaaa\",\"aaaa\"]" }, + { "string", "[aaaa , AAAA, , ]", "[\"aaaa\",\"AAAA\"]" }, + { "string", "[ , aaaa , AAAA ]", "[\"aaaa\",\"AAAA\"]" }, + { "string", "[ aaaa , , AAAA ]", "[\"aaaa\",\"AAAA\"]" }, + { "string", "[ aaaa , AAAA, null ]", "[\"aaaa\",\"AAAA\"]" }, + { "string", "[ null, aaaa , AAAA ]", "[\"aaaa\",\"AAAA\"]" }, + { "string", "[ aaaa , null , AAAA ]", "[\"aaaa\",\"AAAA\"]" }, { "string", null, null }, // without + // default + // values + // - + // Property + // will + // be + // without + // default + // parameter + { "string", "[ AAA ]", "[\"AAA\"]" }, // BUG DE199715 - + // Error 400 + // response + // received + // while adding + // property with + // default value + // contain HTML + // tags. + // Need to check + // whether / is + // legal in yaml + + }; + } + + @DataProvider + private static final Object[][] invalidListProperties() throws IOException, Exception { + return new Object[][] { + + { "integer", "[1,aaa]" }, + { "tosca.datatypes.Credential", + "[{\"protocol\":\"protocol1\",\"token\":\"token1\"},{\"protocol\":\"protocol2\",\"token1\":\"token2\"}]" }, + { "integer", "[1,false]" }, { "integer", "[1,3.5]" }, { "integer", "[1,3#]" }, + { "boolean", "[true,3.5]" }, { "boolean", "[true,1000]" }, { "boolean", "[false,trueee]" }, + { "boolean", "[true,false!]" }, { "float", "[5.0000001,true]" }, { "float", "[0.0001,koko]" }, + { "float", "[0.0001,6.3@]" }, { "float", "[0.0001f,6.3x]" }, }; + } + + @DataProvider + private static final Object[][] updatePropertiesListDefaultValueSuccessFlow() throws IOException, Exception { + return new Object[][] { + // integer + // Setting --- update properties + // ----------------------------------------------------------------------- + { "integer", "[1,2]", "[1,2]", "integer", "[200,100]", "[200,100]" }, + { "integer", "[1,2]", "[1,2]", "integer", "[200,100,null]", "[200,100]" }, + { "integer", "[1,2]", "[1,2]", "integer", "[null, 200,100]", "[200,100]" }, + { "integer", "[1,2]", "[1,2]", "integer", "[200,null,100]", "[200,100]" }, + { "integer", "[1,2]", "[1,2]", "integer", "[200,100, ]", "[200,100]" }, + { "integer", "[1,2]", "[1,2]", "integer", "[ , 200,100 ]", "[200,100]" }, + { "integer", "[1,2]", "[1,2]", "integer", "[200 , ,100 ]", "[200,100]" }, + { "integer", "[1,2]", "[1,2]", "integer", null, null }, + { "integer", "[1,2]", "[1,2]", "integer", "[200 , 100 , 200, 100]", "[200,100,200,100]" }, + // + // ////DE199829 update resource property schema_type is not + // updated + { "integer", "[1,2]", "[1,2]", "string", "[aaaa , bbbb ]", "[\"aaaa\",\"bbbb\"]" }, + { "integer", "[1,2]", "[1,2]", "boolean", "[true , false ]", "[true,false]" }, + { "integer", "[1,2]", "[1,2]", "float", "[3.5,4.8f ]", "[3.5,4.8]" }, + // {"string", "[aaa,bbb]" , "[\"aaa\",\"bbb\"]","integer","[100, + // 200]" , "[\"100\",\"200\"]"}, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "integer", "[100, 200]", "[100,200]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "float", "[0.1f, 3.01]", "[0.1,3.01]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "boolean", "[true, false]", "[true,false]" }, + { "float", "[1.2,2.3]", "[1.2,2.3]", "boolean", "[true, false]", "[true,false]" }, + { "float", "[1.2,2.3]", "[1.2,2.3]", "integer", "[100, 200]", "[100,200]" }, + { "float", "[1.2,2.3]", "[1.2,2.3]", "string", "[koko, moko]", "[\"koko\",\"moko\"]" }, + { "boolean", "[true,false]", "[true,false]", "string", "[koko, moko]", "[\"koko\",\"moko\"]" }, + // {"boolean", "[true,false]" , + // "[\"true\",\"false\"]","integer","[100, 300000000000000]" , + // "[\"100\",\"300000000000000\"]"},// Andrey, value not valid + // for integer success flow + { "boolean", "[true,false]", "[true,false]", "integer", "[100,2147483647]", "[100,2147483647]" }, // Andrey, + // in + // success + // flow + // integer + // max + // value + // is + // 2147483647 + { "boolean", "[true,false]", "[true,false]", "float", "[3.000000000000002, 5.67f]", + "[3.000000000000002,5.67]" }, + // ////DE199829 + // + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", "[xxx, yyy]", "[\"xxx\",\"yyy\"]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", "[xxx , yyy ,null]", "[\"xxx\",\"yyy\"]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", "[null, xxx, yyy]", "[\"xxx\",\"yyy\"]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", "[xxx ,null,yyy]", "[\"xxx\",\"yyy\"]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", "[xxx ,yyy, ]", "[\"xxx\",\"yyy\"]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", "[ , xxx,yyy ]", "[\"xxx\",\"yyy\"]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", "[xxx , ,yyy ]", "[\"xxx\",\"yyy\"]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", "[ xxx , yyy , xxx , yyy]", + "[\"xxx\",\"yyy\",\"xxx\",\"yyy\"]" }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", null, null }, + { "string", "[aaa,bbb]", "[\"aaa\",\"bbb\"]", "string", "[xxx_-x, y__y--y]", + "[\"xxx_-x\",\"y__y--y\"]" }, + // DE199715 + // {"string", "[aaa,bbb]" , "[\"aaa\",\"bbb\"]", "string" , + // "[\"xxx\", \"yyy\"]" , "[\"xxx\",\"yyy\"]"}, + // + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[2.1 , -0.1]", "[2.1,-0.1]" }, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[2.1, 0.1 ,null]", "[2.1,0.1]" }, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[null , 2.1, 0.1]", "[2.1,0.1]" }, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[2.1,null,0.1]", "[2.1,0.1]" }, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[2.1,0.1, ]", "[2.1,0.1]" }, + // {"float", "[1.00,0.02]" , "[1.00,0.02]","float","[ , + // 2.00000000000001,0.00000000000000100 ]" , + // "[2.00000000000001,0.00000000000000100]"}, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[2.1 , ,0.1 ]", "[2.1,0.1]" }, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", null, null }, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[2.1f , ,0.1f ]", "[2.1,0.1]" }, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[2.1 , 0.1 , 2.1, 0.1]", "[2.1,0.1,2.1,0.1]" }, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[200 , 100.11]", "[200,100.11]" }, + { "float", "[1.00,0.02]", "[1.00,0.02]", "float", "[-2.35 , 100.11]", "[-2.35,100.11]" }, + // + { "boolean", "[true,false]", "[true,false]", "boolean", "[false , false]", "[false,false]" }, + { "boolean", "[true,false]", "[true,false]", "boolean", "[false, true ,null]", "[false,true]" }, + { "boolean", "[true,false]", "[true,false]", "boolean", "[null , false, true]", "[false,true]" }, + { "boolean", "[true,false]", "[true,false]", "boolean", "[false,null,true]", "[false,true]" }, + { "boolean", "[true,false]", "[true,false]", "boolean", "[false ,true , ]", "[false,true]" }, + { "boolean", "[true,false]", "[true,false]", "boolean", "[ , false, true ]", "[false,true]" }, + { "boolean", "[true,false]", "[true,false]", "boolean", "[false , ,true ]", "[false,true]" }, + { "boolean", "[true,false]", "[true,false]", "boolean", null, null }, { "boolean", "[true,false]", + "[true,false]", "boolean", "[false , true , false, true]", "[false,true,false,true]" }, }; + } + + @DataProvider + private static final Object[][] updatePropertiesListDefaultValueFailureFlow() throws IOException, Exception { + return new Object[][] { + // integer + // Setting --- update properties + // ----------------------------------------------------------------------- + { "integer", "[1,2]", "[1,2]", "integer", "[aaa,bbb]" }, + { "integer", "[1,2]", "[1,2]", "integer", "[true,false]" }, + { "integer", "[1,2]", "[1,2]", "integer", "[1.0,100]" }, + { "integer", "[1,2]", "[1,2]", "integer", "[@12,100]" }, + { "float", "[0.11,0.22]", "[0.11,0.22]", "float", "[aaa, bbb]" }, + { "float", "[0.11,0.22]", "[0.11,0.22]", "float", "[0.88, false]" }, + { "float", "[0.11,0.22]", "[0.11,0.22]", "float", "[0.88g, 0.3]" }, + { "float", "[0.11,0.22]", "[0.11,0.22]", "float", "[@0.88, 0.3]" }, + { "boolean", "[true, false]", "[true,false]", "boolean", "[true, 100]" }, + { "boolean", "[true, false]", "[true,false]", "boolean", "[false, 0.01]" }, + { "boolean", "[true, false]", "[true,false]", "boolean", "[koko, true]" }, + { "boolean", "[true, false]", "[true,false]", "boolean", "[@false, true]" }, + + }; + } + + // Map properties + @DataProvider + private static final Object[][] updatePropertiesMapDefaultValueSuccessFlow() throws IOException, Exception { + return new Object[][] { + // entrySchemaType , propertyDefaultValues , + // expectedDefaultValue , newEntrySchemaType , + // newPropertyDefaultValue , newExpectedDefaultValue + // integer + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}", "integer", + "{\"key1\":200,\"key2\":null , \"key3\":300}", "{\"key1\":200,\"key2\":null,\"key3\":300}" }, + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}", "integer", + "{\"key1\":null,\"key2\":200 , \"key3\":100}", "{\"key1\":null,\"key2\":200,\"key3\":100}" }, + // string + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}", "string", + "{\"key1\":\"aaaa\" , \"key2\":\"aaaa\"}", "{\"key1\":\"aaaa\",\"key2\":\"aaaa\"}" }, + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}", "boolean", + "{\"key1\":true , \"key2\":false}", "{\"key1\":true,\"key2\":false}" }, + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}", "float", + "{\"key1\":3.5 , \"key2\":4.8f}", "{\"key1\":3.5,\"key2\":4.8}" }, + // string + { "string", "{\"key1\":aaa , \"key2\":bbb}", "{\"key1\":\"aaa\",\"key2\":\"bbb\"}", "string", + "{\"key1\":xxx , \"key2\":yyy}", "{\"key1\":\"xxx\",\"key2\":\"yyy\"}" }, + // float + { "float", "{\"key1\":1.00 , \"key2\":0.02}", "{\"key1\":1.00,\"key2\":0.02}", "float", + "{\"key1\":2.1, \"key2\":-0.1}", "{\"key1\":2.1,\"key2\":-0.1}" }, + { "float", "{\"key1\":1.00 , \"key2\":0.02}", "{\"key1\":1.00,\"key2\":0.02}", "float", + "{\"key1\":2.1 , \"key2\":0.1 , \"key3\":null}", "{\"key1\":2.1,\"key2\":0.1,\"key3\":null}" }, + // boolean + { "boolean", "{\"key1\":true , \"key2\":false}", "{\"key1\":true,\"key2\":false}", "boolean", + "{\"key1\":false , \"key2\":false}", "{\"key1\":false,\"key2\":false}" }, + { "boolean", "{\"key1\":true , \"key2\":false}", "{\"key1\":true,\"key2\":false}", "boolean", + "{\"key1\":false , \"key2\":true , \"key3\":null}", + "{\"key1\":false,\"key2\":true,\"key3\":null}" }, + // null + { "boolean", "{\"key1\":null , \"key2\":false}", "{\"key1\":null,\"key2\":false}", "boolean", + "{\"key1\":false , \"key2\":true , \"key3\":null}", + "{\"key1\":false,\"key2\":true,\"key3\":null}" }, + // tosca.datatypes.Credential + { "tosca.datatypes.Credential", + "{\"key1\":{\"protocol\":\"protocol
1\",\"token\":\"token1\"},\"key2\":{\"protocol\":\"protocol2\",\"token\":\"token2\"}}", + "{\"key1\":{\"protocol\":\"protocol1\",\"token\":\"token1\"},\"key2\":{\"protocol\":\"protocol2\",\"token\":\"token2\"}}", + "tosca.datatypes.Credential", + "{\"key1\":{\"protocol\":\"protocol
1\",\"token\":\"token1\"},\"key2\":{\"protocol\":\"protocol2\",\"token\":\"token2\"}}", + "{\"key1\":{\"protocol\":\"protocol1\",\"token\":\"token1\"},\"key2\":{\"protocol\":\"protocol2\",\"token\":\"token2\"}}" }, + + }; + } + + @DataProvider + private static final Object[][] propertiesMapDefaultValueSuccessFlow() throws IOException, Exception { + return new Object[][] { + + // entrySchemaType , propertyDefaultValues , + // expectedDefaultValue + // + // {"string", + // "{\"vf_module_id\":{\"get_input\":\"vf_module_id\"}, + // \"vnf_idw\": 2}", + // "{\"vf_module_id\":{\"get_input\":\"vf_module_id\"}, + // \"vnf_idw\": 2}"}, + + // tosca.datatypes.Credential + { "tosca.datatypes.Credential", + "{\"key1\":{\"protocol\":\"protocol
1\",\"token\":\"token1\"},\"key2\":{\"protocol\":\"protocol2\",\"token\":\"token2\"}}", + "{\"key1\":{\"protocol\":\"protocol1\",\"token\":\"token1\"},\"key2\":{\"protocol\":\"protocol2\",\"token\":\"token2\"}}" }, + // integer + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}" }, + { "integer", "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":2}", + "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":2}" }, + { "integer", "{\"key1\":1,\"key2\":null,\"key3\":1,\"key4\":2}", + "{\"key1\":1,\"key2\":null,\"key3\":1,\"key4\":2}" }, + { "integer", "{\"key1\":null,\"key2\":1,\"key3\":1,\"key4\":2}", + "{\"key1\":null,\"key2\":1,\"key3\":1,\"key4\":2}" }, + { "integer", "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":null}", + "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":null}" }, + { "integer", "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":NULL}", + "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":null}" }, + { "integer", "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":Null}", + "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":null}" }, + { "integer", "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":nuLL}", + "{\"key1\":1,\"key2\":2,\"key3\":1,\"key4\":null}" }, + { "integer", null, null }, // no default value + // //BUG + //// {"integer", + // "{\"key1\":1000000000000000000000000000000000000000000000000000,\"key2\":2}" + // ,"{\"key1\":1000000000000000000000000000000000000000000000000000,\"key2\":2}"}, + { "boolean", "{\"key1\":true , \"key2\":false}", "{\"key1\":true,\"key2\":false}" }, + { "boolean", "{\"key1\":true , \"key2\":false, \"key3\":false }", + "{\"key1\":true,\"key2\":false,\"key3\":false}" }, + { "boolean", "{\"key1\":null , \"key2\":true, \"key3\":false }", + "{\"key1\":null,\"key2\":true,\"key3\":false}" }, + { "boolean", "{\"key1\":true , \"key2\":Null, \"key3\":false }", + "{\"key1\":true,\"key2\":null,\"key3\":false}" }, + { "boolean", "{\"key1\":true , \"key2\":false, \"key3\":nULL }", + "{\"key1\":true,\"key2\":false,\"key3\":null}" }, + { "boolean", null, null }, + { "boolean", "{\"key1\":on , \"key2\":off}", "{\"key1\":true,\"key2\":false}" }, + { "boolean", "{\"key1\":ON , \"key2\":OFF}", "{\"key1\":true,\"key2\":false}" }, + { "boolean", "{\"key1\":On , \"key2\":Off}", "{\"key1\":true,\"key2\":false}" }, + { "boolean", "{\"key1\":yes , \"key2\":no}", "{\"key1\":true,\"key2\":false}" }, + { "boolean", "{\"key1\":YES , \"key2\":NO}", "{\"key1\":true,\"key2\":false}" }, + { "boolean", "{\"key1\":Yes , \"key2\":No}", "{\"key1\":true,\"key2\":false}" }, + { "boolean", "{\"key1\":y , \"key2\":n}", "{\"key1\":true,\"key2\":false}" }, + { "boolean", "{\"key1\":Y , \"key2\":N}", "{\"key1\":true,\"key2\":false}" }, + { "boolean", "{null:false}", "{\"null\":false}" }, + // float + { "float", "{\"key1\":10.0 , \"key2\":0.0}", "{\"key1\":10.0,\"key2\":0.0}" }, + { "float", "{\"key1\":10 , \"key2\":0}", "{\"key1\":10,\"key2\":0}" }, // contain + // integer + { "float", "{\"key1\":null , \"key2\":Null}", "{\"key1\":null,\"key2\":null}" }, // contain + // null + { "float", "{\"key1\":3.5 , \"key2\":nULL}", "{\"key1\":3.5,\"key2\":null}" }, + // BUG + { "float", "{\"key1\":3.5 , \"key2\":0.1111111111111111111111111111111111111111}", + "{\"key1\":3.5,\"key2\":0.1111111111111111111111111111111111111111}" }, + { "float", "{\"key1\":4.7f , \"key2\":-5.5f}", "{\"key1\":4.7,\"key2\":-5.5}" }, + { "float", "{\"key1\":4.7f , \"key2\":-5.5f, \"key3\":-5.5f}", + "{\"key1\":4.7,\"key2\":-5.5,\"key3\":-5.5}" }, + { "boolean", null, null }, + { "string", "{\"key1\":aaaa , \"key2\":AAAA}", "{\"key1\":\"aaaa\",\"key2\":\"AAAA\"}" }, + { "string", "{\"key1\":off , \"key2\":true , \"key3\":1}", + "{\"key1\":\"off\",\"key2\":\"true\",\"key3\":\"1\"}" }, + { "string", "{\"key1\":aaaa , \"key2\":Aaaa , \"key3\":aaaa}", + "{\"key1\":\"aaaa\",\"key2\":\"Aaaa\",\"key3\":\"aaaa\"}" }, + { "string", "{\"key1\":aaaa , \"key2\":bbbb , \"key3\":null}", + "{\"key1\":\"aaaa\",\"key2\":\"bbbb\",\"key3\":null}" }, + { "string", "{\"key1\":NULL , \"key2\":bbbb , \"key3\":aaaa}", + "{\"key1\":null,\"key2\":\"bbbb\",\"key3\":\"aaaa\"}" }, + { "string", "{\"key1\":aaaa , \"key2\":Null , \"key3\":bbbb}", + "{\"key1\":\"aaaa\",\"key2\":null,\"key3\":\"bbbb\"}" }, + { "string", null, null }, // without default values - Property + // will be without default parameter + { "string", "{\"key1\":\"AAAA\" }", "{\"key1\":\"AAAA\"}" }, + + }; + } + + @DataProvider + private static final Object[][] updatePropertiesMapDefaultValueFailureFlow() throws IOException, Exception { + return new Object[][] { + + // integer + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}", "integer", + "{\"key1\":aaa , \"key2\":bbb}" }, + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}", "integer", + "{\"key1\":true , \"key2\":false}" }, + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}", "integer", + "{\"key1\":1.0 , \"key2\":100}" }, + { "integer", "{\"key1\":1 , \"key2\":2}", "{\"key1\":1,\"key2\":2}", "integer", + "{\"key1\":12@ , \"key2\":100}" }, + // float + { "float", "{\"key1\":0.11 , \"key2\":0.22}", "{\"key1\":0.11,\"key2\":0.22}", "float", + "{\"key1\":aaa , \"key2\":bbb}" }, + { "float", "{\"key1\":0.11 , \"key2\":0.22}", "{\"key1\":0.11,\"key2\":0.22}", "float", + "{\"key1\":0.88 , \"key2\":false}" }, + { "float", "{\"key1\":0.11 , \"key2\":0.22}", "{\"key1\":0.11,\"key2\":0.22}", "float", + "{\"key1\":0.88g , \"key2\":0.3}" }, + { "float", "{\"key1\":0.11 , \"key2\":0.22}", "{\"key1\":0.11,\"key2\":0.22}", "float", + "{\"key1\":@0.88g , \"key2\":0.3}" }, + // boolean + { "boolean", "{\"key1\":true , \"key2\":false}", "{\"key1\":true,\"key2\":false}", "boolean", + "{\"key1\":true , \"key2\":100}" }, + { "boolean", "{\"key1\":true , \"key2\":false}", "{\"key1\":true,\"key2\":false}", "boolean", + "{\"key1\":false , \"key2\":0.01}" }, + { "boolean", "{\"key1\":true , \"key2\":false}", "{\"key1\":true,\"key2\":false}", "boolean", + "{\"key1\":koko , \"key2\":true}" }, + { "boolean", "{\"key1\":true , \"key2\":false}", "{\"key1\":true,\"key2\":false}", "boolean", + "{\"key1\":@false , \"key2\":true}" }, + { "boolean", "{\"key1\":true,\"key2\":false}", "{\"key1\":true,\"key2\":false}", "boolean", + "{:false , \"key2\":true}" }, + { "boolean", "{\"key1\":true,\"key2\":false}", "{\"key1\":true,\"key2\":false}", "boolean", + "{\"key1\":true , , \"key2\":false}" }, + // tosca.datatypes.Credential + { "tosca.datatypes.Credential", + "{\"key1\":{\"protocol\":\"protocol
1\",\"token\":\"token1\"},\"key2\":{\"protocol\":\"protocol2\",\"token\":\"token2\"}}", + "{\"key1\":{\"protocol\":\"protocol1\",\"token\":\"token1\"},\"key2\":{\"protocol\":\"protocol2\",\"token\":\"token2\"}}", + "tosca.datatypes.Credential", + "{\"key1\":{\"protocol\":\"protocol
1\",\"token\":\"token1\"},\"key2\":{\"protocol\":\"protocol2\",\"token2\":\"token2\"}}" }, + + }; + } + + // US594938 - UPDATE PROPERTY + // DE199718 + @Test(dataProvider = "updatePropertiesListDefaultValueFailureFlow") + public void updateDefaultValueOfResourcePropertyListFailureFlow(String entrySchemaType, String propertyDefaltValues, + String expecteddefaultValues, String newEntrySchemaType, String newPropertyDefaltValues) throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.setPropertyDefaultValue(propertyDefaltValues); + propertyDetails.getSchema().getProperty().setType(entrySchemaType); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // verify properties return from response + assertEquals("list", resourcePropertiesFromResponse.getType()); + assertEquals(expecteddefaultValues, resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(propertyDetails.getSchema().getProperty().getType(), + resourcePropertiesFromResponse.getSchema().getProperty().getType()); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, expecteddefaultValues); + // Update resource property type = "list" + propertyDetails.setPropertyDefaultValue(newPropertyDefaltValues); + propertyDetails.getSchema().getProperty().setType(newEntrySchemaType); + RestResponse updatePropertyResponse = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.DESIGNER, false) + .right().value(); + assertTrue(updatePropertyResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add(propertyDetails.getName()); + variables.add(propertyDetails.getPropertyType()); + variables.add(propertyDetails.getSchema().getProperty().getType()); + variables.add(newPropertyDefaltValues); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE.name(), variables, + updatePropertyResponse.getResponse()); + } + + @Test + public void updatePropertyOfDerivedResource() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(PropertyTypeEnum.STRING_LIST); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String derivedResourcePropertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + // second resource derived from basicVFC + Resource vfc1FromBasicVFC = AtomicOperationUtils + .createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum.VFC, basicVFC, + ResourceCategoryEnum.APPLICATION_L4_BORDER, UserRoleEnum.DESIGNER, true) + .left().value(); + // add property Type list to second resource + PropertyReqDetails defaultListProperty = ElementFactory.getDefaultListProperty(PropertyTypeEnum.INTEGER_LIST); + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(defaultListProperty, vfc1FromBasicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + // Update property (list) of derived resource + RestResponse updatePropertyResponse = AtomicOperationUtils.updatePropertyOfResource(propertyDetails, basicVFC, + derivedResourcePropertyUniqueId, UserRoleEnum.DESIGNER, false).right().value(); + assertTrue(updatePropertyResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION)); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updatePropertyResponse.getResponse()); + // Verify resource's priority list did not changed + verifyResourcePropertyList(basicVFC, propertyDetails, "[\"a\",\"b\"]"); + } + + @Test + public void updatePropertyOfNonDerivedResource() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(PropertyTypeEnum.STRING_LIST); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + // second resource derived from basicVFC + Resource vfc1FromBasicVFC = AtomicOperationUtils + .createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum.VFC, basicVFC, + ResourceCategoryEnum.APPLICATION_L4_BORDER, UserRoleEnum.DESIGNER, true) + .left().value(); + // add property Type list to second resource + PropertyReqDetails defaultListProperty = ElementFactory.getDefaultListProperty(PropertyTypeEnum.INTEGER_LIST); + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(defaultListProperty, vfc1FromBasicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // Update property (list) of derived resource + defaultListProperty.setPropertyDefaultValue("[1,2,3,4]"); + String expectedDefaultValue = "[1,2,3,4]"; + ComponentInstanceProperty resourcePropertyAfterUpdate = AtomicOperationUtils + .updatePropertyOfResource(defaultListProperty, vfc1FromBasicVFC, propertyUniqueId, + UserRoleEnum.DESIGNER, true) + .left().value(); + assertEquals(resourcePropertyAfterUpdate.getType(), "list"); + assertEquals(resourcePropertyAfterUpdate.getDefaultValue(), expectedDefaultValue); + assertEquals(resourcePropertyAfterUpdate.getSchema().getProperty().getType(), + defaultListProperty.getSchema().getProperty().getType()); // string/integer/boolean/float + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(vfc1FromBasicVFC.getUniqueId()); + String expectedDefaultValueFromDerivedResource = "[\"a\",\"b\"]"; + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + resource.getProperties().get(0).getDefaultValue().equals(expectedDefaultValue); + resource.getProperties().get(1).getDefaultValue().equals(expectedDefaultValueFromDerivedResource); + } + + @Test + public void updateListPropertyToNonCheckedOutResource() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + String PropertyDefaultValue = "[2,3]"; + propertyDetails.setPropertyDefaultValue(PropertyDefaultValue); + propertyDetails.getSchema().getProperty().setType("integer"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + // Update resource property type = "list" + propertyDetails.setPropertyDefaultValue("[3,4]"); + propertyDetails.getSchema().getProperty().setType("integer"); + RestResponse updatePropertyResponse = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.DESIGNER, false) + .right().value(); + assertTrue(updatePropertyResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION)); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updatePropertyResponse.getResponse()); + // Verify resource's priority list did not changed + verifyResourcePropertyList(basicVFC, propertyDetails, "[2,3]"); + } + + @Test + public void updateListPropertyResourceByNonResouceOwner() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + String PropertyDefaultValue = "[2,3]"; + propertyDetails.setPropertyDefaultValue(PropertyDefaultValue); + propertyDetails.getSchema().getProperty().setType("integer"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // AtomicOperationUtils.changeComponentState(basicVFC, + // UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + // Update resource property type = "list" + propertyDetails.setPropertyDefaultValue("[3,4]"); + propertyDetails.getSchema().getProperty().setType("integer"); + RestResponse updatePropertyResponse = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.DESIGNER2, false) + .right().value(); + assertTrue(updatePropertyResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION)); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updatePropertyResponse.getResponse()); + // Verify resource's priority list did not changed + verifyResourcePropertyList(basicVFC, propertyDetails, "[2,3]"); + } + + @Test + public void updateListPropertyResourceByTester() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + String PropertyDefaultValue = "[2,3]"; + propertyDetails.setPropertyDefaultValue(PropertyDefaultValue); + propertyDetails.getSchema().getProperty().setType("integer"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // AtomicOperationUtils.changeComponentState(basicVFC, + // UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + // Update resource property type = "list" + propertyDetails.setPropertyDefaultValue("[3,4]"); + propertyDetails.getSchema().getProperty().setType("integer"); + RestResponse updatePropertyResponse = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.TESTER, false) + .right().value(); + assertTrue(updatePropertyResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION)); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + updatePropertyResponse.getResponse()); + // Verify resource's priority list did not changed + verifyResourcePropertyList(basicVFC, propertyDetails, "[2,3]"); + } + + // DE199964 + @Test(enabled = false) + public void updateListPropertyToNonExistingResource() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + String PropertyDefaultValue = "[2,3]"; + propertyDetails.setPropertyDefaultValue(PropertyDefaultValue); + propertyDetails.getSchema().getProperty().setType("integer"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + String resourceUniqueId = basicVFC.getUniqueId(); + basicVFC.setUniqueId("1111111"); + RestResponse updatePropertyResponse = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.DESIGNER, false) + .right().value(); + assertTrue(updatePropertyResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_NOT_FOUND)); + ArrayList variables = new ArrayList<>(); + variables.add(basicVFC.getUniqueId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_NOT_FOUND.name(), variables, + updatePropertyResponse.getResponse()); + // Verify resource's priority list did not changed + basicVFC.setUniqueId(resourceUniqueId); + verifyResourcePropertyList(basicVFC, propertyDetails, "[2,3]"); + } + + // DE199725 + @Test + public void updateResourcePropertyListNonSupportedPropertyType() throws Exception { // Not + // "list" + // type + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + String PropertyDefaultValue = "[2,3]"; + propertyDetails.setPropertyDefaultValue(PropertyDefaultValue); + propertyDetails.getSchema().getProperty().setType("integer"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // update resource property + String propertyType = "listttttttt"; + propertyDetails.setPropertyType(propertyType); + RestResponse updatePropertyResponse = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.DESIGNER, false) + .right().value(); + ArrayList variables = new ArrayList<>(); + variables.add(propertyDetails.getPropertyType()); // property data type + // (koko instead + // list) + variables.add(propertyDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROPERTY_TYPE.name(), variables, + updatePropertyResponse.getResponse()); + // Verify resource's priority list did not changed + propertyDetails.setPropertyType("list"); + verifyResourcePropertyList(basicVFC, propertyDetails, "[2,3]"); + } + + @Test(enabled = false) // DE199732 + public void updateResourcePropertyListNonSupportedEntrySchemaType() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + String PropertyDefaultValue = "[2,3]"; + propertyDetails.setPropertyDefaultValue(PropertyDefaultValue); + propertyDetails.getSchema().getProperty().setType("integer"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // update resource property + String EntrySchemaType = "integerrrrrr"; + propertyDetails.getSchema().getProperty().setType(EntrySchemaType); + RestResponse updatePropertyResponse = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.DESIGNER, false) + .right().value(); + assertTrue(updatePropertyResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add(EntrySchemaType); + variables.add(propertyDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROPERTY_INNER_TYPE.name(), variables, + updatePropertyResponse.getResponse()); + propertyDetails.getSchema().getProperty().setType("integer"); + verifyResourcePropertyList(basicVFC, propertyDetails, "[2,3]"); + } + + @Test(dataProvider = "updatePropertiesListDefaultValueSuccessFlow") + public void updateResourcePropertyListSuccessFlow(String entrySchemaType, String propertyDefaltValues, + String expecteddefaultValues, String newEntrySchemaType, String newPropertyDefaltValues, + String newExpecteddefaultValues) throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.setPropertyDefaultValue(propertyDefaltValues); + propertyDetails.getSchema().getProperty().setType(entrySchemaType); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // verify properties return from response + assertEquals("list", resourcePropertiesFromResponse.getType()); + assertEquals(expecteddefaultValues, resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(propertyDetails.getSchema().getProperty().getType(), + resourcePropertiesFromResponse.getSchema().getProperty().getType()); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, expecteddefaultValues); + // Update resource property type = "list" + propertyDetails.setPropertyDefaultValue(newPropertyDefaltValues); + propertyDetails.getSchema().getProperty().setType(newEntrySchemaType); + ComponentInstanceProperty resourcePropertyAfterUpdate = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.DESIGNER, true) + .left().value(); + assertEquals("list", resourcePropertyAfterUpdate.getType()); + assertEquals(newExpecteddefaultValues, resourcePropertyAfterUpdate.getDefaultValue()); + assertEquals(propertyDetails.getSchema().getProperty().getType(), + resourcePropertyAfterUpdate.getSchema().getProperty().getType()); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, newExpecteddefaultValues); + } + + // Add property type list to resource + // DE199718 + @Test(dataProvider = "invalidListProperties") // invalid default values + public void addListPropertyToResourceFailureFlow(String entrySchemaType, String propertyDefaltValues) + throws Exception { + // String propertyType = "list"; + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType(entrySchemaType); + propertyDetails.setPropertyDefaultValue(propertyDefaltValues); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + RestResponse addPropertyToResourceResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, false).right().value(); + assertTrue(addPropertyToResourceResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add(propertyDetails.getName()); + variables.add(propertyDetails.getPropertyType()); + variables.add(propertyDetails.getSchema().getProperty().getType()); + variables.add(propertyDefaltValues); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE.name(), variables, + addPropertyToResourceResponse.getResponse()); + + } + + // DE199964 + @Test + public void addListPropertyToNonExistingResource() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType("integer"); + propertyDetails.setPropertyDefaultValue("[1,2]"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to non existing resource + basicVFC.setUniqueId("1111111"); + RestResponse addPropertyToResourceResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, false).right().value(); + assertTrue(addPropertyToResourceResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_NOT_FOUND)); + ArrayList variables = new ArrayList<>(); + variables.add(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_NOT_FOUND.name(), variables, + addPropertyToResourceResponse.getResponse()); + } + + @Test + public void addListPropertyToNonCheckedOutResource() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType("integer"); + propertyDetails.setPropertyDefaultValue("[1,2]"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + // Add property type list to non Checked-Out resource + RestResponse addPropertyToResourceResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, false).right().value(); + assertTrue(addPropertyToResourceResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION)); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + addPropertyToResourceResponse.getResponse()); + } + + @Test + public void addListPropertyToResourceByNonResourceOwner() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType("integer"); + propertyDetails.setPropertyDefaultValue("[1,2]"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to non Checked-Out resource + RestResponse addPropertyToResourceResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER2, false).right().value(); + assertTrue(addPropertyToResourceResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION)); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + addPropertyToResourceResponse.getResponse()); + } + + @Test + public void addListPropertyToResourcePropertyAlreadyExists01() throws Exception { + String propertyType = "list"; + String propertySchemaType = "integer"; + String defaultValues = "[1,2]"; + String expecteddefaultValues = "[1,2]"; + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType(propertySchemaType); + propertyDetails.setPropertyDefaultValue(defaultValues); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // check-in and check-out resource + RestResponse changeComponentState = LifecycleRestUtils.changeComponentState(basicVFC, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKIN); + assertTrue(changeComponentState.getErrorCode().equals(BaseRestUtils.STATUS_CODE_SUCCESS)); + changeComponentState = LifecycleRestUtils.changeComponentState(basicVFC, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKOUT); + assertTrue(changeComponentState.getErrorCode().equals(BaseRestUtils.STATUS_CODE_SUCCESS)); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + // verify properties return from response + assertEquals(resourcePropertiesFromResponse.getType(), propertyType); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), expecteddefaultValues); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), propertySchemaType); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, expecteddefaultValues); + // Add same property again to resource + RestResponse addPropertyRestResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, false).right().value(); + assertTrue(addPropertyRestResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_ALREADY_EXISTS)); + ArrayList variables = new ArrayList<>(); + variables.add(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.PROPERTY_ALREADY_EXIST.name(), variables, + addPropertyRestResponse.getResponse()); + // verify property not deleted + verifyResourcePropertyList(basicVFC, propertyDetails, expecteddefaultValues); + } + + @Test + public void addListPropertyToResourcePropertyAlreadyExists02() throws Exception { + String propertyType = "list"; + String propertySchemaType = "integer"; + String defaultValues = "[1,2]"; + String expecteddefaultValues = "[1,2]"; + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType(propertySchemaType); + propertyDetails.setPropertyDefaultValue(defaultValues); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + // verify properties return from response + assertEquals(resourcePropertiesFromResponse.getType(), propertyType); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), expecteddefaultValues); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), propertySchemaType); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, expecteddefaultValues); + // check-in and check-out resource + RestResponse changeComponentState = LifecycleRestUtils.changeComponentState(basicVFC, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKIN); + assertTrue(changeComponentState.getErrorCode().equals(BaseRestUtils.STATUS_CODE_SUCCESS)); + changeComponentState = LifecycleRestUtils.changeComponentState(basicVFC, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKOUT); + assertTrue(changeComponentState.getErrorCode().equals(BaseRestUtils.STATUS_CODE_SUCCESS)); + // Add same property again to resource + RestResponse addPropertyRestResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, false).right().value(); + assertTrue(addPropertyRestResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_ALREADY_EXISTS)); + ArrayList variables = new ArrayList<>(); + variables.add(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.PROPERTY_ALREADY_EXIST.name(), variables, + addPropertyRestResponse.getResponse()); + // verify property not deleted + verifyResourcePropertyList(basicVFC, propertyDetails, expecteddefaultValues); + } + + @Test // DE199725 + public void addListPropertyToResourceNonSupportedPropertyType() throws Exception { // Not + // "list" + // type + String propertyType = "listttttttt"; + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.setPropertyType(propertyType); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + RestResponse addPropertyRestResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, false).right().value(); + assertTrue(addPropertyRestResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add(propertyDetails.getPropertyType()); // property data type + // (koko instead + // list) + variables.add(propertyDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROPERTY_TYPE.name(), variables, + addPropertyRestResponse.getResponse()); + } + + @Test // DE199732 + public void addListPropertyToResourceNonSupportedEntrySchemaType() throws Exception { + String EntrySchemaType = "stringggg"; // instead "string" + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType(EntrySchemaType); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + RestResponse addPropertyRestResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, false).right().value(); + assertTrue(addPropertyRestResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add(EntrySchemaType); + variables.add(propertyDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_PROPERTY_INNER_TYPE.name(), variables, + addPropertyRestResponse.getResponse()); + } + + @Test + public void addHundredPropertyListToResourceSuccessFlow() throws Exception { + String propertyType = "list"; + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + String propertyName = propertyDetails.getName(); + int numberOfPropertiesToAddToResource = 100; + ComponentInstanceProperty resourcePropertiesFromResponse; + for (int x = 0; x < numberOfPropertiesToAddToResource; x++) { + propertyDetails.setName(propertyName + x); + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + // verify properties return from response + assertEquals(resourcePropertiesFromResponse.getName(), propertyName + x); + assertEquals(resourcePropertiesFromResponse.getType(), propertyType); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[\"a\",\"b\"]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetails.getSchema().getProperty().getType()); // string/integer/boolean/float + } + // get resource and verify that 100 properties exist + Resource resourceObject = AtomicOperationUtils.getResourceObject(basicVFC, UserRoleEnum.DESIGNER); + assertEquals(numberOfPropertiesToAddToResource, resourceObject.getProperties().size()); + + } + + @Test(dataProvider = "propertiesListDefaultValueSuccessFlow") + public void addListPropertyToResourceSuccessFlow(String entrySchemaType, String propertyDefaltValues, + String expecteddefaultValues) throws Exception { + String propertyType = "list"; + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType(entrySchemaType); + propertyDetails.setPropertyDefaultValue(propertyDefaltValues); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + // verify properties return from response + assertEquals(propertyType, resourcePropertiesFromResponse.getType()); + assertEquals(expecteddefaultValues, resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(entrySchemaType, resourcePropertiesFromResponse.getSchema().getProperty().getType()); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, expecteddefaultValues); + + assertEquals(resourcePropertiesFromResponse.getType(), propertyType); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), expecteddefaultValues); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), entrySchemaType); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, expecteddefaultValues); + } + + // Delete property type list + @Test + public void deleteOneOfTheListPropertiesFromResourceAndAddItAgain() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.STRING_LIST); + PropertyReqDetails propertyDetailsInteger = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.INTEGER_LIST); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[\"a\",\"b\"]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsInteger.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[1,2]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsInteger.getSchema().getProperty().getType()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + // Delete one resource + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyDetailsTypeString, "[\"a\",\"b\"]"); + // Add deleted property again to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsInteger.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[1,2]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsInteger.getSchema().getProperty().getType()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + } + + @Test + public void deletePropertyListTypeInteger() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.STRING_LIST); + PropertyReqDetails propertyDetailsInteger = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.INTEGER_LIST); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[\"a\",\"b\"]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsInteger.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[1,2]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsInteger.getSchema().getProperty().getType()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + // Delete one resource + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyDetailsInteger, "[1,2]"); + } + + @Test + public void deletePropertyListTypeBoolean() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.BOOLEAN_LIST); + PropertyReqDetails propertyDetailsInteger = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.INTEGER_LIST); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[true,false]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsInteger.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[1,2]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsInteger.getSchema().getProperty().getType()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + // Delete one property + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyDetailsInteger, "[1,2]"); + } + + @Test + public void deletePropertyListTypeFloat() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.FLOAT_LIST); + PropertyReqDetails propertyDetailsInteger = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.INTEGER_LIST); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[1.0,2.0]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsInteger.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[1,2]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsInteger.getSchema().getProperty().getType()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + // Delete one property + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyDetailsInteger, "[1,2]"); + } + + @Test + public void deletePropertyListAlreadyDeleted() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.FLOAT_LIST); + PropertyReqDetails propertyDetailsInteger = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.INTEGER_LIST); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[1.0,2.0]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsInteger.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), "[1,2]"); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsInteger.getSchema().getProperty().getType()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + // Delete one property + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyDetailsInteger, "[1,2]"); + // delete again the same property + deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_NOT_FOUND == deletePropertyOfResource.getErrorCode()); + ArrayList variables = new ArrayList<>(); + variables.add(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.PROPERTY_NOT_FOUND.name(), variables, + deletePropertyOfResource.getResponse()); + } + + @Test + public void deletePropertyListResourceIsNotCheckedOutState() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.FLOAT_LIST); + String expectedDefaultvalues = "[1.0,2.0]"; + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), expectedDefaultvalues); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + // Get resource and verify updated default value + verifyResourcePropertyList(basicVFC, propertyDetailsTypeString, expectedDefaultvalues); + // Check-in resource + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + // Delete property + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION == deletePropertyOfResource.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + deletePropertyOfResource.getResponse()); + // Get resource and verify property is not deleted + verifyResourcePropertyList(basicVFC, propertyDetailsTypeString, expectedDefaultvalues); + } + + @Test + public void deletePropertyListResourceByNotIsNonResouceOwner() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.FLOAT_LIST); + String expectedDefaultvalues = "[1.0,2.0]"; + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), expectedDefaultvalues); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + // Get resource and verify updated default value + verifyResourcePropertyList(basicVFC, propertyDetailsTypeString, expectedDefaultvalues); + // Delete property by non resource owner + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER2); + assertTrue(BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION == deletePropertyOfResource.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + deletePropertyOfResource.getResponse()); + // Get resource and verify property is not deleted + verifyResourcePropertyList(basicVFC, propertyDetailsTypeString, expectedDefaultvalues); + } + + @Test + public void deletePropertyListFromNonExistingResource() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.FLOAT_LIST); + String expectedDefaultvalues = "[1.0,2.0]"; + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + String actualResourceUniqueId = basicVFC.getUniqueId(); + // Add property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals(resourcePropertiesFromResponse.getDefaultValue(), expectedDefaultvalues); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + // Get resource and verify updated default value + verifyResourcePropertyList(basicVFC, propertyDetailsTypeString, expectedDefaultvalues); + // Delete property from non existing resource + basicVFC.setUniqueId("1111111"); + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(deletePropertyOfResource.getErrorCode().equals(BaseRestUtils.STATUS_CODE_NOT_FOUND)); + ArrayList variables = new ArrayList<>(); + variables.add(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_NOT_FOUND.name(), variables, + deletePropertyOfResource.getResponse()); + // Get resource and verify property is not deleted + basicVFC.setUniqueId(actualResourceUniqueId); + verifyResourcePropertyList(basicVFC, propertyDetailsTypeString, expectedDefaultvalues); + } + + @Test + public void deletePropertyOfDerivedResource() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(PropertyTypeEnum.STRING_LIST); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String derivedResourcePropertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + // second resource derived from basicVFC + Resource vfc1FromBasicVFC = AtomicOperationUtils + .createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum.VFC, basicVFC, + ResourceCategoryEnum.APPLICATION_L4_BORDER, UserRoleEnum.DESIGNER, true) + .left().value(); + // Delete property (list) of derived resource + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource( + vfc1FromBasicVFC.getUniqueId(), derivedResourcePropertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(deletePropertyOfResource.getErrorCode().equals(BaseRestUtils.STATUS_CODE_NOT_FOUND)); + ArrayList variables = new ArrayList<>(); + variables.add(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.PROPERTY_NOT_FOUND.name(), variables, + deletePropertyOfResource.getResponse()); + // Verify resource's priority list did not changed + verifyResourcePropertyList(vfc1FromBasicVFC, propertyDetails, "[\"a\",\"b\"]"); + } + + @Test + public void deletePropertyOfNonDerivedResource() throws Exception { + PropertyReqDetails propertyListString = ElementFactory.getDefaultListProperty(PropertyTypeEnum.STRING_LIST); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyListString, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.changeComponentState(basicVFC, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + // second resource derived from basicVFC + Resource vfc1FromBasicVFC = AtomicOperationUtils + .createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum.VFC, basicVFC, + ResourceCategoryEnum.APPLICATION_L4_BORDER, UserRoleEnum.DESIGNER, true) + .left().value(); + // add property Type list to second resource + PropertyReqDetails propertyListInteger = ElementFactory.getDefaultListProperty(PropertyTypeEnum.INTEGER_LIST); + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyListInteger, vfc1FromBasicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // Delete property (list) of derived resource + RestResponse deletePropertyOfResource = AtomicOperationUtils + .deletePropertyOfResource(vfc1FromBasicVFC.getUniqueId(), propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyListString, "[\"a\",\"b\"]"); + } + + private void verifyResourcePropertyList(Resource resource, PropertyReqDetails expectedProperty, + String expecteddefaultValues) throws Exception { + // get resource and verify property from type list + Resource getResource = AtomicOperationUtils.getResourceObject(resource, UserRoleEnum.DESIGNER); + List actualResourceProperties = getResource.getProperties(); + boolean isPropertyAppear = false; + for (PropertyDefinition pro : actualResourceProperties) { + if (expectedProperty.getName().equals(pro.getName())) { + assertTrue("Check Property Type ", pro.getType().equals(expectedProperty.getPropertyType())); + assertEquals("Check Property default values ", expecteddefaultValues, pro.getDefaultValue()); + // assertTrue("Check Property default values ", + // pro.getDefaultValue().equals(expecteddefaultValues)); + assertTrue("Check entrySchema Property Type ", pro.getSchema().getProperty().getType() + .equals(expectedProperty.getSchema().getProperty().getType())); + isPropertyAppear = true; + } + } + assertTrue(isPropertyAppear); + } + + // US656905 + // --------------------- Map Property + // ---------------------------------------------------------------- + @Test(dataProvider = "updatePropertiesMapDefaultValueFailureFlow") + public void updateDefaultValueOfResourcePropertyMapFailureFlow(String entrySchemaType, String propertyDefaultValues, + String expectedDefaultValue, String newEntrySchemaType, String newPropertyDefaultValue) throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultMapProperty(); + propertyDetails.setPropertyDefaultValue(propertyDefaultValues); + propertyDetails.getSchema().getProperty().setType(entrySchemaType); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // verify properties return from response + assertEquals("map", resourcePropertiesFromResponse.getType()); + assertEquals(expectedDefaultValue, resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(propertyDetails.getSchema().getProperty().getType(), + resourcePropertiesFromResponse.getSchema().getProperty().getType()); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, expectedDefaultValue); + // Update resource property type = "map" + propertyDetails.setPropertyDefaultValue(newPropertyDefaultValue); + propertyDetails.getSchema().getProperty().setType(newEntrySchemaType); + RestResponse updatePropertyResponse = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.DESIGNER, false) + .right().value(); + assertTrue(updatePropertyResponse.getErrorCode().equals(STATUS_CODE_INVALID_CONTENT)); + ArrayList variables = new ArrayList<>(); + variables.add(propertyDetails.getName()); + variables.add(propertyDetails.getPropertyType()); + variables.add(propertyDetails.getSchema().getProperty().getType()); + variables.add(newPropertyDefaultValue); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_COMPLEX_DEFAULT_VALUE.name(), variables, + updatePropertyResponse.getResponse()); + } + + @Test(dataProvider = "updatePropertiesMapDefaultValueSuccessFlow") + public void updateResourcePropertyMapSuccessFlow(String entrySchemaType, String propertyDefaultValues, + String expectedDefaultValue, String newEntrySchemaType, String newPropertyDefaultValue, + String newExpectedDefaultValue) throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultMapProperty(); + propertyDetails.setPropertyDefaultValue(propertyDefaultValues); + propertyDetails.getSchema().getProperty().setType(entrySchemaType); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + // verify properties return from response + assertEquals("map", resourcePropertiesFromResponse.getType()); + assertEquals(expectedDefaultValue, resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(propertyDetails.getSchema().getProperty().getType(), + resourcePropertiesFromResponse.getSchema().getProperty().getType()); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, expectedDefaultValue); + // Update resource property type = "map" + propertyDetails.setPropertyDefaultValue(newPropertyDefaultValue); + propertyDetails.getSchema().getProperty().setType(newEntrySchemaType); + ComponentInstanceProperty resourcePropertyAfterUpdate = AtomicOperationUtils + .updatePropertyOfResource(propertyDetails, basicVFC, propertyUniqueId, UserRoleEnum.DESIGNER, true) + .left().value(); + assertEquals("map", resourcePropertyAfterUpdate.getType()); + assertEquals(newExpectedDefaultValue, resourcePropertyAfterUpdate.getDefaultValue()); + assertEquals(propertyDetails.getSchema().getProperty().getType(), + resourcePropertyAfterUpdate.getSchema().getProperty().getType()); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, newExpectedDefaultValue); + } + + @Test + public void deletePropertyMapTypeString() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultMapProperty(PropertyTypeEnum.STRING_MAP); + PropertyReqDetails propertyDetailsInteger = ElementFactory.getDefaultMapProperty(PropertyTypeEnum.INTEGER_MAP); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals("{\"key1\":\"val1\",\"key2\":\"val2\"}", resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsInteger.getPropertyType()); + assertEquals("{\"key1\":123,\"key2\":-456}", resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsInteger.getSchema().getProperty().getType()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + // Delete one resource + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyDetailsInteger, "{\"key1\":123,\"key2\":-456}"); + } + + @Test + public void deletePropertyMapTypeFloat() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeFloat = ElementFactory.getDefaultMapProperty(PropertyTypeEnum.FLOAT_MAP); + PropertyReqDetails propertyDetailsInteger = ElementFactory.getDefaultMapProperty(PropertyTypeEnum.INTEGER_MAP); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeFloat, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeFloat.getPropertyType()); + assertEquals("{\"key1\":0.2123,\"key2\":43.545}", resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeFloat.getSchema().getProperty().getType()); // string/integer/boolean/float + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsInteger.getPropertyType()); + assertEquals("{\"key1\":123,\"key2\":-456}", resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsInteger.getSchema().getProperty().getType()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + // Delete one resource + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyDetailsInteger, "{\"key1\":123,\"key2\":-456}"); + } + + @Test + public void deletePropertyMapTypeBoolean() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeBoolean = ElementFactory + .getDefaultMapProperty(PropertyTypeEnum.BOOLEAN_MAP); + PropertyReqDetails propertyDetailsInteger = ElementFactory.getDefaultMapProperty(PropertyTypeEnum.INTEGER_MAP); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeBoolean, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeBoolean.getPropertyType()); + assertEquals("{\"key1\":true,\"key2\":false}", resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeBoolean.getSchema().getProperty().getType()); // string/integer/boolean/float + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsInteger.getPropertyType()); + assertEquals("{\"key1\":123,\"key2\":-456}", resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsInteger.getSchema().getProperty().getType()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + // Delete one resource + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyDetailsInteger, "{\"key1\":123,\"key2\":-456}"); + } + + @Test + public void deletePropertyMapTypeInteger() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeInteger = ElementFactory + .getDefaultMapProperty(PropertyTypeEnum.INTEGER_MAP); + PropertyReqDetails propertyDetailsBoolean = ElementFactory.getDefaultMapProperty(PropertyTypeEnum.BOOLEAN_MAP); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeInteger, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + String propertyUniqueId = resourcePropertiesFromResponse.getUniqueId(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeInteger.getPropertyType()); + assertEquals("{\"key1\":123,\"key2\":-456}", resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeInteger.getSchema().getProperty().getType()); // string/integer/boolean/float + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsBoolean, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsBoolean.getPropertyType()); + assertEquals("{\"key1\":true,\"key2\":false}", resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsBoolean.getSchema().getProperty().getType()); + // Get resource and verify updated default value + RestResponse restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(2, resource.getProperties().size()); + // Delete one resource + RestResponse deletePropertyOfResource = AtomicOperationUtils.deletePropertyOfResource(basicVFC.getUniqueId(), + propertyUniqueId, UserRoleEnum.DESIGNER); + assertTrue(BaseRestUtils.STATUS_CODE_DELETE == deletePropertyOfResource.getErrorCode()); + // Get resource and verify updated default value + restResponse = ResourceRestUtils.getResource(basicVFC.getUniqueId()); + resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + assertEquals(1, resource.getProperties().size()); + verifyResourcePropertyList(basicVFC, propertyDetailsBoolean, "{\"key1\":true,\"key2\":false}"); + } + + @Test(dataProvider = "propertiesMapDefaultValueSuccessFlow") + public void addMapPropertyToResourceSuccessFlow(String entrySchemaType, String propertyDefaltValues, + String expecteddefaultValues) throws Exception { + String propertyType = "map"; + PropertyReqDetails propertyDetails = ElementFactory.getDefaultMapProperty(); + propertyDetails.getSchema().getProperty().setType(entrySchemaType); + propertyDetails.setPropertyDefaultValue(propertyDefaltValues); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to resource + ComponentInstanceProperty resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, true).left().value(); + // verify properties return from response + assertEquals(propertyType, resourcePropertiesFromResponse.getType()); + assertEquals(expecteddefaultValues, resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(entrySchemaType, resourcePropertiesFromResponse.getSchema().getProperty().getType()); // string/integer/boolean/float + verifyResourcePropertyList(basicVFC, propertyDetails, expecteddefaultValues); + } + + @Test + public void addMapPropertyToNonExistingResource() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType("integer"); + propertyDetails.setPropertyDefaultValue("{\"key1\":1 , \"key2\":2}"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to non existing resource + basicVFC.setUniqueId("1111111"); + RestResponse addPropertyToResourceResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER, false).right().value(); + assertTrue(addPropertyToResourceResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_NOT_FOUND)); + ArrayList variables = new ArrayList<>(); + variables.add(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_NOT_FOUND.name(), variables, + addPropertyToResourceResponse.getResponse()); + } + + @Test + public void addMaptPropertyToResourceByNonResourceOwner() throws Exception { + PropertyReqDetails propertyDetails = ElementFactory.getDefaultListProperty(); + propertyDetails.getSchema().getProperty().setType("integer"); + propertyDetails.setPropertyDefaultValue("{\"key1\":1 , \"key2\":2}"); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add property type list to non Checked-Out resource + RestResponse addPropertyToResourceResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetails, basicVFC, UserRoleEnum.DESIGNER2, false).right().value(); + assertTrue(addPropertyToResourceResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION)); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + addPropertyToResourceResponse.getResponse()); + } + + @Test + public void addMapPropertyToResourcePropertyAlreadyExists() throws Exception { + ComponentInstanceProperty resourcePropertiesFromResponse; + PropertyReqDetails propertyDetailsTypeString = ElementFactory + .getDefaultListProperty(PropertyTypeEnum.STRING_MAP); + // create resource + Resource basicVFC = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left() + .value(); + // Add 2 property type list to resource + resourcePropertiesFromResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, true).left() + .value(); + assertEquals(resourcePropertiesFromResponse.getType(), propertyDetailsTypeString.getPropertyType()); + assertEquals("{\"key1\":\"val1\",\"key2\":\"val2\"}", resourcePropertiesFromResponse.getDefaultValue()); + assertEquals(resourcePropertiesFromResponse.getSchema().getProperty().getType(), + propertyDetailsTypeString.getSchema().getProperty().getType()); // string/integer/boolean/float + // check-in and check-out resource + RestResponse changeComponentState = LifecycleRestUtils.changeComponentState(basicVFC, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKIN); + assertTrue(changeComponentState.getErrorCode().equals(BaseRestUtils.STATUS_CODE_SUCCESS)); + changeComponentState = LifecycleRestUtils.changeComponentState(basicVFC, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKOUT); + assertTrue(changeComponentState.getErrorCode().equals(BaseRestUtils.STATUS_CODE_SUCCESS)); + // Add same property again to resource + RestResponse addPropertyRestResponse = AtomicOperationUtils + .addCustomPropertyToResource(propertyDetailsTypeString, basicVFC, UserRoleEnum.DESIGNER, false).right() + .value(); + assertTrue(addPropertyRestResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_ALREADY_EXISTS)); + ArrayList variables = new ArrayList<>(); + variables.add(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.PROPERTY_ALREADY_EXIST.name(), variables, + addPropertyRestResponse.getResponse()); + // verify property not deleted + verifyResourcePropertyList(basicVFC, propertyDetailsTypeString, "{\"key1\":\"val1\",\"key2\":\"val2\"}"); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/PropertyApisTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/PropertyApisTest.java new file mode 100644 index 0000000000..0586269a14 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/property/PropertyApisTest.java @@ -0,0 +1,384 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.property; + +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.lf5.util.ResourceUtils; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.PropertyReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.preRequisites.SimpleOneRsrcOneServiceTest; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.PropertyRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.UserRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class PropertyApisTest extends SimpleOneRsrcOneServiceTest { + + protected static final String RESOURCE_CATEGORY = "Generic/Databases"; + protected Config config = Config.instance(); + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json";; + + // protected User sdncDesignerDetails; + // protected ResourceReqDetails resourceDetails; + protected PropertyReqDetails property; + protected String body; + + protected HttpRequest httpRequest = new HttpRequest(); + protected Map headersMap = new HashMap(); + + @Rule + public static TestName testName = new TestName(); + + public PropertyApisTest() { + super(testName, PropertyApisTest.class.getName()); + } + + @BeforeMethod + public void init() throws Exception { + // + // //Delete resource + // + // resourceDetails = new ResourceReqDetails(); + // resourceDetails.setResourceName("testresourceDetails"); + // + // resourceUtils.deleteResource_allVersions(resourceDetails, + // sdncDesignerDetails); + // + // //Create resource + // resourceDetails = createResource(sdncDesignerDetails, + // "testresourceDetails"); + + // Create property + // property.setPropertyName("test"); + // property.setPropertyType("integer"); + // property.setPropertySource("A&AI"); + // property.setPropertyDescription("test property"); + + // body = gson.toJson(property); + property = ElementFactory.getDefaultProperty(); + body = property.propertyToJsonString(); + // System.out.println(body); + // HTTP (for negative tests) + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncDesignerDetails.getUserId()); + + } + + @Test + public void testPropertyApis() throws Exception { + // Create property + // System.out.println ("---- Create Property (POST) ----"); + + String propertyId = UniqueIdBuilder.buildComponentPropertyUniqueId(getResourceId(resourceDetails), property.getName()); + + PropertyRestUtils.deleteProperty(getResourceId(resourceDetails), propertyId, sdncDesignerDetails); + RestResponse createPropertyResponse = PropertyRestUtils.createProperty(getResourceId(resourceDetails), body, + sdncDesignerDetails); + AssertJUnit.assertTrue("Expected result code - 201, received - " + createPropertyResponse.getErrorCode(), + createPropertyResponse.getErrorCode() == 201); + + // Get property + // System.out.println ("---- Get Property (GET) ----"); + RestResponse getPropertyResponse = PropertyRestUtils.getProperty(getResourceId(resourceDetails), propertyId, + sdncDesignerDetails); + AssertJUnit.assertTrue("Expected result code - 200, received - " + getPropertyResponse.getErrorCode(), + getPropertyResponse.getErrorCode() == 200); + + JSONObject jsonResp = (JSONObject) JSONValue.parse(getPropertyResponse.getResponse()); + + // assertTrue("Wrong 'type' in the + // response",jsonResp.get("type").equals(property.getPropertyType())); + // assertTrue("Wrong 'source' in the + // response",jsonResp.get("name").equals(property.getPropertyName())); + // assertTrue("Wrong 'name' in the + // response",jsonResp.get("source").equals(property.getPropertySource())); + // assertTrue("Wrong 'description' in the + // response",jsonResp.get("description").equals(property.getPropertyDescription())); + + // Update property + // System.out.println ("---- Update Property (UPDATE) ----"); + property.setPropertyDescription("Updated description"); + // body = gson.toJson(property); + body = property.propertyToJsonString(); + + RestResponse updatePropertyResponse = PropertyRestUtils.updateProperty(getResourceId(resourceDetails), + propertyId, body, sdncDesignerDetails); + AssertJUnit.assertTrue("Expected result code - 200, received - " + updatePropertyResponse.getErrorCode(), + updatePropertyResponse.getErrorCode() == 200); + + // Get property + // System.out.println ("---- Get Property (GET) ----"); + getPropertyResponse = PropertyRestUtils.getProperty(getResourceId(resourceDetails), propertyId, + sdncDesignerDetails); + AssertJUnit.assertTrue("Expected result code - 200, received - " + getPropertyResponse.getErrorCode(), + getPropertyResponse.getErrorCode() == 200); + + jsonResp = (JSONObject) JSONValue.parse(getPropertyResponse.getResponse()); + + // assertTrue("Wrong 'type' in the + // response",jsonResp.get("type").equals(property.getPropertyType())); + // assertTrue("Wrong 'source' in the + // response",jsonResp.get("name").equals(property.getPropertyName())); + // assertTrue("Wrong 'name' in the + // response",jsonResp.get("source").equals(property.getPropertySource())); + // assertTrue("Wrong 'description' in the + // response",jsonResp.get("description").equals(property.getPropertyDescription())); + + // Delete property + // System.out.println ("---- Delete Property (DELETE) ----"); + RestResponse deletePropertyResponse = PropertyRestUtils.deleteProperty(getResourceId(resourceDetails), + propertyId, sdncDesignerDetails); + AssertJUnit.assertTrue("Expected result code - 204, received - " + deletePropertyResponse.getErrorCode(), + deletePropertyResponse.getErrorCode() == 204); + + // Get property - verify that the property doesn't exist. + // System.out.println("---- GET - Property Not Found ----"); + getPropertyResponse = PropertyRestUtils.getProperty(getResourceId(resourceDetails), propertyId, + sdncDesignerDetails); + List variables = Arrays.asList(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.PROPERTY_NOT_FOUND.name(), variables, + getPropertyResponse.getResponse()); + + } + + // -------------------------------------------------------------------------------------- + + protected String getPropertyId(ResourceReqDetails resource, PropertyReqDetails property) { + // return + // resource.getResourceName().toLowerCase()+".0.1."+property.getPropertyName(); + return UniqueIdBuilder.buildComponentPropertyUniqueId(resource.getUniqueId(), property.getName()); + } + + protected String getResourceId(ResourceReqDetails resource) { + // String resourceUid = + // UniqueIdBuilder.buildResourceUniqueId(resource.getResourceName(), + // "0.1"); + + return resource.getUniqueId(); + } + + protected User createUser(String cspUserId, String firstName, String lastName, String email, String role) + throws Exception { + User sdncUserDetails = new User(firstName, lastName, cspUserId, email, role, null); + + User adminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + UserRestUtils.createUser(sdncUserDetails, adminUser); + + return sdncUserDetails; + } + + protected ResourceReqDetails createResource(User sdncUserDetails, String resourceName) throws Exception { + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + // String category = ResourceCategoryEnum.DATABASE.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add("tosca.nodes.Root"); + String vendorName = "Oracle"; + String vendorRelease = "1.0"; + String contactId = sdncUserDetails.getUserId(); + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, null, + derivedFrom, vendorName, vendorRelease, contactId, icon); + resourceDetails.addCategoryChain(ResourceCategoryEnum.GENERIC_DATABASE.getCategory(), + ResourceCategoryEnum.GENERIC_DATABASE.getSubCategory()); + // deleteResource(resourceName.toLowerCase()+".0.1",sdncUserDetails.getUserId()); + // TODO delete by name + // deleteResource(UniqueIdBuilder.buildResourceUniqueId(resourceName, + // "0.1"), sdncUserDetails.getUserId()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncUserDetails); + AssertJUnit.assertTrue(createResource.getErrorCode().intValue() == 201); + String resourceId = ResponseParser.getUniqueIdFromResponse(createResource); + resourceDetails.setUniqueId(resourceId); + + return resourceDetails; + + } + + @Test + public void putReqToCreateUriNotAllowed() throws Exception { + // System.out.println("---- PUT request to Create uri - Not Allowed + // ----"); + String url = String.format(Urls.CREATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + getResourceId(resourceDetails)); + RestResponse propertyErrorResponse = httpRequest.httpSendByMethod(url, "PUT", body, headersMap); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), variables, + propertyErrorResponse.getResponse()); + } + + @Test + public void getReqToCreateUriNotAllowed() throws Exception { + // System.out.println("---- GET request to Create uri - Not Allowed + // ----"); + String url = String.format(Urls.CREATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + getResourceId(resourceDetails)); + RestResponse propertyErrorResponse = httpRequest.httpSendGet(url, headersMap); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), variables, + propertyErrorResponse.getResponse()); + } + + @Test + public void deleteReqToCreateUriNotAllowed() throws Exception { + // System.out.println("---- DELETE request to Create uri - Not Allowed + // ----"); + String url = String.format(Urls.CREATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + getResourceId(resourceDetails)); + RestResponse propertyErrorResponse = httpRequest.httpSendDelete(url, headersMap); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), variables, + propertyErrorResponse.getResponse()); + } + + @Test + public void postReqToUpdateUriNotAllowed() throws Exception { + // System.out.println("---- POST request to Update uri - Not Allowed + // ----"); + String url = String.format(Urls.UPDATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + getResourceId(resourceDetails), getPropertyId(resourceDetails, property)); + RestResponse propertyErrorResponse = httpRequest.httpSendPost(url, body, headersMap); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), variables, + propertyErrorResponse.getResponse()); + } + + @Test + public void deleteReqPropertyNotFound() throws Exception { + // System.out.println("---- DELETE - Property Not Found ----"); + String unknownPropertyId = getPropertyId(resourceDetails, property) + "111"; + String url = String.format(Urls.DELETE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + getResourceId(resourceDetails), unknownPropertyId); + RestResponse propertyErrorResponse = httpRequest.httpSendDelete(url, headersMap); + List variables = Arrays.asList(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.PROPERTY_NOT_FOUND.name(), variables, + propertyErrorResponse.getResponse()); + } + + @Test + public void updateReqPropertyNotFound() throws Exception { + // System.out.println("---- PUT - Property Not Found ----"); + String unknownPropertyId = getPropertyId(resourceDetails, property) + "111"; + String url = String.format(Urls.UPDATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + getResourceId(resourceDetails), unknownPropertyId); + RestResponse propertyErrorResponse = httpRequest.httpSendByMethod(url, "PUT", body, headersMap); + List variables = Arrays.asList(""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.PROPERTY_NOT_FOUND.name(), variables, + propertyErrorResponse.getResponse()); + } + + @Test + public void modifierNotTheStateOwner() throws Exception { + // System.out.println("---- The modifier is not the state owner - + // Operation Not Allowed ----"); + User sdncUserDetails2 = createUser("tu5555", "Test", "User", "tu5555@intl.sdc.com", "DESIGNER"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails2.getUserId()); + property.setPropertyDescription("new description"); + // body = gson.toJson(property); + body = property.propertyToJsonString(); + String url = String.format(Urls.UPDATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + getResourceId(resourceDetails), getPropertyId(resourceDetails, property)); + RestResponse propertyErrorResponse = httpRequest.httpSendByMethod(url, "PUT", body, headersMap); + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), variables, + propertyErrorResponse.getResponse()); + + } + + @Test + public void postReqInvalidContent() throws Exception { + // System.out.println("---- POST - Invalid Content ----"); + body = "invalid"; + String url = String.format(Urls.CREATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + getResourceId(resourceDetails), getPropertyId(resourceDetails, property)); + RestResponse propertyErrorResponse = httpRequest.httpSendPost(url, body, headersMap); + + // System.out.println(propertyErrorResponse.getResponse()+" "+ + // propertyErrorResponse.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), variables, + propertyErrorResponse.getResponse()); + } + + @Test + public void putReqInvalidContent() throws Exception { + + // Create property + // System.out.println ("---- Create Property (POST) ----"); + RestResponse createPropertyResponse = PropertyRestUtils.createProperty(getResourceId(resourceDetails), body, + sdncDesignerDetails); + assertTrue("Expected result code - 201, received - " + createPropertyResponse.getErrorCode(), + createPropertyResponse.getErrorCode() == 201); + + // System.out.println("---- PUT - Invalid Content ----"); + body = "invalid"; + + String url = String.format(Urls.UPDATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + getResourceId(resourceDetails), getPropertyId(resourceDetails, property)); + + // System.out.println(url + "\n" + body); + + RestResponse propertyErrorResponse = httpRequest.httpSendByMethod(url, "PUT", body, headersMap); + + // System.out.println(propertyErrorResponse.getResponse()+" "+ + // propertyErrorResponse.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), variables, + propertyErrorResponse.getResponse()); + } + + // -------------------------------------------------------------------------------------- + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/CheckGetResource.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/CheckGetResource.java new file mode 100644 index 0000000000..0ec6b00fdc --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/CheckGetResource.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.common.util.SerializationUtils; +import org.testng.annotations.Test; + +import fj.data.Either; + +public class CheckGetResource { + + public void checkGetVmmsc6() throws Exception { + + try { + + System.out.println("dddd"); + RestResponse getResource = ResourceRestUtils.getResource("96eb6583-2822-448b-a284-bfc144fa627e"); + + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + + Either serialize = SerializationUtils.serializeExt(resource); + + SerializationUtils.deserializeExt(serialize.left().value(), Resource.class, "ffff"); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ComponentRelationshipInVfTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ComponentRelationshipInVfTest.java new file mode 100644 index 0000000000..d05dd1039a --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ComponentRelationshipInVfTest.java @@ -0,0 +1,1408 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.apache.http.client.ClientProtocolException; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.RelationshipImpl; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class ComponentRelationshipInVfTest extends ComponentBaseTest { + + public ComponentRelationshipInVfTest() { + super(new TestName(), ComponentRelationshipInVfTest.class.getName()); + } + + private ResourceReqDetails resourceDetailsVF; + private User designerUser; + private User adminUser; + private User testerUser; + private ResourceReqDetails resourceDetailsReq; + private ResourceReqDetails resourceDetailsCap; + + @BeforeMethod + public void before() throws Exception { + designerUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + adminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + testerUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + + resourceDetailsVF = ElementFactory.getDefaultResourceByType("VF100", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, designerUser.getUserId(), ResourceTypeEnum.VF.toString()); + createResource(resourceDetailsVF, designerUser); + + resourceDetailsReq = ElementFactory.getDefaultResourceByType("SoftCompRouter", + NormativeTypesEnum.SOFTWARE_COMPONENT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, + designerUser.getUserId(), ResourceTypeEnum.CP.toString()); // resourceType + // = + // VFC + resourceDetailsCap = ElementFactory.getDefaultResourceByType("MyCompute", NormativeTypesEnum.COMPUTE, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, designerUser.getUserId(), ResourceTypeEnum.CP.toString()); // resourceType + // = + // VFC + + } + + private void createResource(ResourceReqDetails resourceDetails, User user) throws Exception, IOException { + RestResponse createResourceResponse = ResourceRestUtils.createResource(resourceDetails, user); + ResourceRestUtils.checkCreateResponse(createResourceResponse); + if (!resourceDetails.getResourceType().equals("VF")) + LifecycleRestUtils.changeResourceState(resourceDetails, user, "0.1", LifeCycleStatesEnum.CHECKIN); + } + + private void createAtomicResource(ResourceReqDetails resourceDetails, User user) throws Exception { + createResource(resourceDetails, user); + } + + private RequirementCapabilityRelDef setRelationshipBetweenInstances(ComponentInstance riReq, + ComponentInstance riCap, CapReqDef capReqDef) throws Exception { + + String capbilityUid = capReqDef.getCapabilities().get("tosca.capabilities.Container").get(0).getUniqueId(); + String requirementUid = capReqDef.getRequirements().get("tosca.capabilities.Container").get(0).getUniqueId(); + + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + requirementDef.setFromNode(riReq.getUniqueId()); + requirementDef.setToNode(riCap.getUniqueId()); + + RequirementAndRelationshipPair pair = new RequirementAndRelationshipPair(); + pair.setRequirementOwnerId(riReq.getUniqueId()); + pair.setCapabilityOwnerId(riCap.getUniqueId()); + pair.setRequirement("host"); + RelationshipImpl relationship = new RelationshipImpl(); + relationship.setType("tosca.capabilities.Container"); + pair.setRelationships(relationship); + pair.setCapabilityUid(capbilityUid); + pair.setRequirementUid(requirementUid); + List relationships = new ArrayList<>(); + relationships.add(pair); + requirementDef.setRelationships(relationships); + return requirementDef; + } + + private ComponentInstance createComponentInstance(ResourceReqDetails res) throws Exception { + return createComponentInstance(res, designerUser); + } + + private ComponentInstance createComponentInstance(ResourceReqDetails res, User user, ResourceReqDetails vf) + throws Exception { + RestResponse response = ResourceRestUtils.createResourceInstance(res, user, vf.getUniqueId()); + ResourceRestUtils.checkCreateResponse(response); + ComponentInstance compInstance = ResponseParser.parseToObject(response.getResponse(), ComponentInstance.class); + return compInstance; + } + + private ComponentInstance createComponentInstance(ResourceReqDetails res, User user) throws Exception { + return createComponentInstance(res, user, resourceDetailsVF); + } + + private void createTwoAtomicResourcesByType(String reqType, String capType, User user1, User user2) + throws Exception { + resourceDetailsReq.setResourceType(reqType); + createAtomicResource(resourceDetailsReq, user1); + resourceDetailsCap.setResourceType(capType); + createAtomicResource(resourceDetailsCap, user2); + } + + private void createTwoAtomicResourcesByType(String reqType, String capType) throws Exception { + createTwoAtomicResourcesByType(reqType, capType, designerUser, designerUser); + } + + @Test + public void associateInVF() throws Exception { + + createTwoAtomicResourcesByType(ResourceTypeEnum.VFC.toString(), ResourceTypeEnum.VFC.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDef = getResourceReqCap(); + + List capList = capReqDef.getCapabilities().get("tosca.capabilities.Container"); + List reqList = capReqDef.getRequirements().get("tosca.capabilities.Container"); + + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + requirementDef.setFromNode(riReq.getUniqueId()); + requirementDef.setToNode(riCap.getUniqueId()); + + RequirementAndRelationshipPair pair = new RequirementAndRelationshipPair(); + pair.setRequirementOwnerId(riReq.getUniqueId()); + pair.setCapabilityOwnerId(riCap.getUniqueId()); + pair.setRequirement("host"); + RelationshipImpl relationship = new RelationshipImpl(); + relationship.setType("tosca.capabilities.Container"); + pair.setRelationships(relationship); + pair.setCapabilityUid(capList.get(0).getUniqueId()); + pair.setRequirementUid(reqList.get(0).getUniqueId()); + List relationships = new ArrayList<>(); + relationships.add(pair); + requirementDef.setRelationships(relationships); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(designerUser, + resourceDetailsVF); + capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + + List list = capReqDef.getRequirements().get("tosca.capabilities.Container"); + assertEquals("Check requirement", null, list); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, dissociateInstances.getErrorCode().intValue()); + + getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(designerUser, resourceDetailsVF); + capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + + list = capReqDef.getRequirements().get("tosca.capabilities.Container"); + assertEquals("Check requirement", 1, list.size()); + } + + //////////////////////////////// Q A ////////////////////////////// + private boolean checkRealtionship(String fromNode, String toNode, String resourceUniqueId) throws Exception { + List componentInstancesRelations = getComponentInstancesRelations( + resourceUniqueId); + RequirementCapabilityRelDef requirementCapabilityRelDef = componentInstancesRelations.get(0); + boolean fromNodeCheck = requirementCapabilityRelDef.getFromNode().equals(fromNode); + boolean toNodeCheck = requirementCapabilityRelDef.getToNode().equals(toNode); + + return fromNodeCheck && toNodeCheck; + } + + private List getComponentInstancesRelations(String resourceUniqueId) + throws ClientProtocolException, IOException { + Resource resource = getVfAsResourceObject(resourceUniqueId); + List componenRelationInstances = resource.getComponentInstancesRelations(); + + return componenRelationInstances; + } + + private Resource getVfAsResourceObject(String resourceUniqueId) throws ClientProtocolException, IOException { + RestResponse getResource = ResourceRestUtils.getResource(resourceUniqueId); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + return resource; + } + + private List getComponentInstancesList(String resourceUniqueId) throws Exception { + Resource resource = getVfAsResourceObject(resourceUniqueId); + List componentInstances = resource.getComponentInstances(); + return componentInstances; + } + + @Test + public void associateCpToCpTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.CP.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + CapReqDef capReqDef = getResourceReqCap(); + + requirementsBeforeAssociate.remove("tosca.capabilities.Container"); + assertTrue(capReqDef.getRequirements().equals(requirementsBeforeAssociate)); + + List list = capabilitiesBeforeAssociate.get("tosca.capabilities.Container"); + for (CapabilityDefinition cap : list) { + cap.setMinOccurrences("0"); + } + + Map> capabilitiesAfterAssociate = capReqDef.getCapabilities(); + assertTrue(capabilitiesAfterAssociate.equals(capabilitiesBeforeAssociate)); + } + + private CapReqDef getResourceReqCap(ResourceReqDetails res) throws IOException { + RestResponse getResourceBeforeAssociate = ComponentRestUtils.getComponentRequirmentsCapabilities(designerUser, + resourceDetailsVF); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceBeforeAssociate.getResponse(), CapReqDef.class); + return capReqDef; + } + + private CapReqDef getResourceReqCap() throws IOException { + return getResourceReqCap(resourceDetailsVF); + } + + @Test + public void associateCpToVLTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + CapReqDef capReqDef = getResourceReqCap(); + + requirementsBeforeAssociate.remove("tosca.capabilities.Container"); + assertTrue(capReqDef.getRequirements().equals(requirementsBeforeAssociate)); + + List list = capabilitiesBeforeAssociate.get("tosca.capabilities.Container"); + for (CapabilityDefinition cap : list) { + cap.setMinOccurrences("0"); + } + + Map> capabilitiesAfterAssociate = capReqDef.getCapabilities(); + assertTrue(capabilitiesAfterAssociate.equals(capabilitiesBeforeAssociate)); + + } + + // Error handling + // ELLA - more informative error + @Test + public void associateCpToVlInVFCTest() throws Exception { + ResourceReqDetails vfcDetails = ElementFactory.getDefaultResourceByType("VFC100", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, designerUser.getUserId(), ResourceTypeEnum.VFC.toString()); + RestResponse createVfcResponse = ResourceRestUtils.createResource(vfcDetails, designerUser); + ResourceRestUtils.checkCreateResponse(createVfcResponse); + + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + vfcDetails.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 400, associateInstances.getErrorCode().intValue()); + + // "messageId": "SVC4116", + // "text": "Error: Invalid Content.", + // "variables": [ + // "SoftCompRouter 1", + // "MyCompute 2", + // "host" + // ] + } + + // Error handling + @Test + public void associateCpToVfTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riCapInVfInstance = createComponentInstance(resourceDetailsCap, designerUser, + resourceDetailsVF); + ComponentInstance riReqInVfInstance = createComponentInstance(resourceDetailsReq, designerUser, + resourceDetailsVF); + + ResourceReqDetails vfHigh = new ResourceReqDetails(resourceDetailsVF, "0.1"); + vfHigh.setName("vfHigh"); + vfHigh.setTags(new ArrayList(Arrays.asList(vfHigh.getName()))); + vfHigh.setResourceType(ResourceTypeEnum.VF.toString()); + createResource(vfHigh, designerUser); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq, designerUser, vfHigh); + LifecycleRestUtils.changeResourceState(resourceDetailsVF, designerUser, "0.1", LifeCycleStatesEnum.CHECKIN); + ComponentInstance riCap = createComponentInstance(resourceDetailsVF, designerUser, vfHigh); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 409, associateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + associateInstances.getResponse()); + // "messageId": "SVC4116", + // "text": "Error: Invalid Content.", + // "variables": [ + // "SoftCompRouter 1", + // "VF100 2", + // "host" + // ] + } + + // Error handling + @Test + public void associateVfcToVfcNotFoundTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.VFC.toString(), ResourceTypeEnum.VFC.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + riCap.setUniqueId("123"); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 400, associateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_INSTANCE_BAD_REQUEST.name(), + new ArrayList(), associateInstances.getResponse()); + + // "messageId": "SVC4116", + // "text": "Error: Invalid Content.", + // "variables": [ + // "SoftCompRouter 1", + // "012f6dcd-bcdf-4d9b-87be-ff1442b95831.5d265453-0b6a-4453-8f3d-57a253b88432.softcomprouter1", + // "host" + } + + @Test + public void associateCpToDeletedVfcTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VFC.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse deleteResourceResponse = ResourceRestUtils.deleteResource(resourceDetailsCap.getUniqueId(), + designerUser.getUserId()); + ResourceRestUtils.checkDeleteResponse(deleteResourceResponse); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + } + + @Test + public void associateCpToDeletedVlTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse deleteResourceResponse = ResourceRestUtils.deleteResource(resourceDetailsCap.getUniqueId(), + designerUser.getUserId()); + ResourceRestUtils.checkDeleteResponse(deleteResourceResponse); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + } + + @Test + public void associateCpToDeletedCpTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.CP.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse deleteResourceResponse = ResourceRestUtils.deleteResource(resourceDetailsCap.getUniqueId(), + designerUser.getUserId()); + ResourceRestUtils.checkDeleteResponse(deleteResourceResponse); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + } + + // Error handling + @Test + public void associateCpToDeletedCpInstanceTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.CP.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse deleteComponentInstance = ComponentInstanceRestUtils.deleteComponentInstance(designerUser, + resourceDetailsVF.getUniqueId(), riReq.getUniqueId(), ComponentTypeEnum.RESOURCE); + ComponentInstanceRestUtils.checkDeleteResponse(deleteComponentInstance); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 400, associateInstances.getErrorCode().intValue()); + + // "messageId": "SVC4116", + // "text": "Error: Invalid Content.", + // "variables": [ + // "7d6aca08-9321-4ea1-a781-c52c8214a30e.c0e63466-5283-44d8-adff-365c0885a6ba.softcomprouter1", + // "MyCompute 2", + // "host" + // ] + } + + // Error handling + @Test + public void associateVfcToDeletedVFCInstanceTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.VFC.toString(), ResourceTypeEnum.VFC.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse deleteComponentInstance = ComponentInstanceRestUtils.deleteComponentInstance(designerUser, + resourceDetailsVF.getUniqueId(), riReq.getUniqueId(), ComponentTypeEnum.RESOURCE); + ComponentInstanceRestUtils.checkDeleteResponse(deleteComponentInstance); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 400, associateInstances.getErrorCode().intValue()); + + // "messageId": "SVC4116", + // "text": "Error: Invalid Content.", + // "variables": [ + // "7d6aca08-9321-4ea1-a781-c52c8214a30e.c0e63466-5283-44d8-adff-365c0885a6ba.softcomprouter1", + // "MyCompute 2", + // "host" + // ] + } + + @Test + public void associateWithDifferentOwnerOfVf() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2), resourceDetailsVF.getUniqueId(), + ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 409, associateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + associateInstances.getResponse()); + + CapReqDef capReqDef = getResourceReqCap(); + + Map> capabilitiesAfterAssociate = capReqDef.getCapabilities(); + Map> requirementsAfterAssociate = capReqDef.getRequirements(); + + assertTrue(capabilitiesAfterAssociate.equals(capabilitiesBeforeAssociate)); + assertTrue(requirementsAfterAssociate.equals(requirementsBeforeAssociate)); + } + + @Test + public void associateWithTester() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), resourceDetailsVF.getUniqueId(), + ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 409, associateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + associateInstances.getResponse()); + + CapReqDef capReqDef = getResourceReqCap(); + + Map> capabilitiesAfterAssociate = capReqDef.getCapabilities(); + Map> requirementsAfterAssociate = capReqDef.getRequirements(); + + assertTrue(capabilitiesAfterAssociate.equals(capabilitiesBeforeAssociate)); + assertTrue(requirementsAfterAssociate.equals(requirementsBeforeAssociate)); + } + + // Error handling + @Test + public void associateCpToVLIntoVFNotFound() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + String uidNotFound = "123"; + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + uidNotFound, ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 404, associateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_NOT_FOUND.name(), + new ArrayList(Arrays.asList("")), associateInstances.getResponse()); + + // {"serviceException":{"messageId":"SVC4063","text":"Error: Requested + // '%1' resource was not found.","variables":[""]}}} + } + + // Error Handling + @Test + public void associateCpToVlWithMissingUid() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + requirementDef.setToNode(""); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 400, associateInstances.getErrorCode().intValue()); + // ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), + // new ArrayList(), associateInstances.getResponse()); + + // "messageId": "SVC4116", + // "text": "Error: Invalid Content.", + // "variables": [ + // "SoftCompRouter 1", + // "fd3a689b-fa1c-4105-933d-d1310e642f05.95bce626-ce73-413b-8c14-2388d1589d5c.softcomprouter1", + // "host" + // ] + } + + @Test + public void associateInServiceWithUidOfVf() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.SERVICE); + assertEquals("Check response code ", 404, associateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_FOUND.name(), + new ArrayList(Arrays.asList("")), associateInstances.getResponse()); + } + + @Test + public void associateCpToVl_DifferentOwners() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString(), designerUser, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2)); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + CapReqDef capReqDef = getResourceReqCap(); + + requirementsBeforeAssociate.remove("tosca.capabilities.Container"); + assertTrue(capReqDef.getRequirements().equals(requirementsBeforeAssociate)); + + List list = capabilitiesBeforeAssociate.get("tosca.capabilities.Container"); + for (CapabilityDefinition cap : list) { + cap.setMinOccurrences("0"); + } + + Map> capabilitiesAfterAssociate = capReqDef.getCapabilities(); + assertTrue(capabilitiesAfterAssociate.equals(capabilitiesBeforeAssociate)); + } + + @Test(enabled = false) + public void associateToNotCheckedoutVf() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse changeResourceStateToCheckin = LifecycleRestUtils.changeResourceState(resourceDetailsVF, + designerUser, LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.checkSuccess(changeResourceStateToCheckin); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 409, associateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + associateInstances.getResponse()); + + CapReqDef capReqDef = getResourceReqCap(); + assertTrue(capReqDef.getRequirements().equals(requirementsBeforeAssociate)); + assertTrue(capReqDef.getCapabilities().equals(capabilitiesBeforeAssociate)); + + String firstUniqueId = resourceDetailsVF.getUniqueId(); + + // checkout + + RestResponse changeResourceStateToCheckout = LifecycleRestUtils.changeResourceState(resourceDetailsVF, + designerUser, LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.checkSuccess(changeResourceStateToCheckout); + String secondUniqueId = resourceDetailsVF.getUniqueId(); + + CapReqDef capReqDefAfterFirstCheckout = getResourceReqCap(); + Map> capabilitiesAfterFirstCheckout = capReqDefAfterFirstCheckout + .getCapabilities(); + Map> requirementsAfterFirstCheckout = capReqDefAfterFirstCheckout + .getRequirements(); + + requirementDef = setUidsOfInstancesAfterLifecycleStateChange(riReq, riCap, capReqDefBeforeAssociate); + + RestResponse firstAssociateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + designerUser, resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, firstAssociateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + CapReqDef capReqDefAfterFirstAssociate = getResourceReqCap(); + Map> capabilitiesAfterFirstAssociate = capReqDefAfterFirstAssociate + .getCapabilities(); + Map> requirementsAfterFirstAssociate = capReqDefAfterFirstAssociate + .getRequirements(); + + requirementsAfterFirstCheckout.remove("tosca.capabilities.Container"); + assertTrue(requirementsAfterFirstAssociate.equals(requirementsAfterFirstCheckout)); + assertTrue(capabilitiesAfterFirstAssociate.equals(capabilitiesAfterFirstCheckout)); + + resourceDetailsVF.setUniqueId(firstUniqueId); + CapReqDef capReqDefOfFirstVersion = getResourceReqCap(); + Map> capabilitiesOfFirstVersion = capReqDefOfFirstVersion.getCapabilities(); + Map> requirementsOfFirstVersion = capReqDefOfFirstVersion.getRequirements(); + + assertTrue(getComponentInstancesRelations(resourceDetailsVF.getUniqueId()).isEmpty()); + assertTrue(requirementsBeforeAssociate.equals(requirementsOfFirstVersion)); + assertTrue(capabilitiesBeforeAssociate.equals(capabilitiesOfFirstVersion)); + + // checkin-checkout + resourceDetailsVF.setUniqueId(secondUniqueId); + RestResponse changeResourceStateToCheckin2 = LifecycleRestUtils.changeResourceState(resourceDetailsVF, + designerUser, LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.checkSuccess(changeResourceStateToCheckin2); + RestResponse changeResourceStateToCheckout2 = LifecycleRestUtils.changeResourceState(resourceDetailsVF, + designerUser, LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.checkSuccess(changeResourceStateToCheckout2); + + List componentInstancesRelations = getComponentInstancesRelations( + resourceDetailsVF.getUniqueId()); + assertFalse(componentInstancesRelations.isEmpty()); + assertEquals(1, componentInstancesRelations.size()); + List componentInstancesList = getComponentInstancesList(resourceDetailsVF.getUniqueId()); + for (ComponentInstance comp : componentInstancesList) { + String instanceUid = comp.getUniqueId(); + assertTrue(checkNodesInRelations(instanceUid, componentInstancesRelations.get(0))); + } + assertEquals(2, componentInstancesList.size()); + + } + + private RequirementCapabilityRelDef setUidsOfInstancesAfterLifecycleStateChange(ComponentInstance riReq, + ComponentInstance riCap, CapReqDef capReqDefBeforeAssociate) + throws ClientProtocolException, IOException, Exception { + RequirementCapabilityRelDef requirementDef; + // RestResponse getResourceResponse = + // ResourceRestUtils.getResource(resourceDetailsVF.getUniqueId()); + // Resource resource_0_2 = + // ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), + // Resource.class); + // List componentInstances = + // resource_0_2.getComponentInstances(); + List componentInstances = getComponentInstancesList(resourceDetailsVF.getUniqueId()); + + for (ComponentInstance comp : componentInstances) { + if (comp.getName().equals(riReq.getName())) { + riReq.setUniqueId(comp.getUniqueId()); + } else if (comp.getName().equals(riCap.getName())) { + riCap.setUniqueId(comp.getUniqueId()); + } + } + requirementDef = setRelationshipBetweenInstances(riReq, riCap, capReqDefBeforeAssociate); + return requirementDef; + } + + private boolean checkNodesInRelations(String instanceUid, RequirementCapabilityRelDef relation) { + if (relation.getToNode().equals(instanceUid)) { + return true; + } else if (relation.getFromNode().equals(instanceUid)) { + return true; + } else { + return false; + } + } + + @Test + public void associateOneOfTwoCPsToVl_ThenDiscocciate() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + ResourceReqDetails secondResourceDetailsReq = new ResourceReqDetails(resourceDetailsReq, "0.1"); + secondResourceDetailsReq.setName("secondCP"); + secondResourceDetailsReq.setTags(Arrays.asList(secondResourceDetailsReq.getName())); + createAtomicResource(secondResourceDetailsReq, designerUser); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riReq2 = createComponentInstance(secondResourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + CapReqDef capReqDef = getResourceReqCap(); + + List expectedList = requirementsBeforeAssociate.get("tosca.capabilities.Container"); + for (RequirementDefinition req : expectedList) { + if (req.getOwnerName().equals(riReq2.getName())) { + expectedList = new ArrayList(Arrays.asList(req)); + break; + } + } + requirementsBeforeAssociate.put("tosca.capabilities.Container", expectedList); + assertTrue(capReqDef.getRequirements().equals(requirementsBeforeAssociate)); + + List list = capabilitiesBeforeAssociate.get("tosca.capabilities.Container"); + for (CapabilityDefinition cap : list) { + cap.setMinOccurrences("0"); + } + + Map> capabilitiesAfterAssociate = capReqDef.getCapabilities(); + assertTrue(capabilitiesAfterAssociate.equals(capabilitiesBeforeAssociate)); + + // second relationship + + RequirementCapabilityRelDef secondRequirementDef = setRelationshipBetweenInstances(riReq2, riCap, + capReqDefBeforeAssociate); + RestResponse secondAssociateInstances = ComponentInstanceRestUtils.associateInstances(secondRequirementDef, + designerUser, resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, secondAssociateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(secondRequirementDef.getFromNode(), secondRequirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + CapReqDef capReqDefAfterSecondAssociation = getResourceReqCap(); + + requirementsBeforeAssociate.remove("tosca.capabilities.Container"); + assertTrue(capReqDefAfterSecondAssociation.getRequirements().equals(requirementsBeforeAssociate)); + + Map> capabilitiesAfterSecondAssociate = capReqDefAfterSecondAssociation + .getCapabilities(); + assertTrue(capabilitiesAfterSecondAssociate.equals(capabilitiesBeforeAssociate)); + + // dissociate + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(secondRequirementDef, + designerUser, resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, dissociateInstances.getErrorCode().intValue()); + assertTrue(getComponentInstancesRelations(resourceDetailsVF.getUniqueId()).isEmpty()); + + CapReqDef capReqDefAfterDissociation = getResourceReqCap(); + Map> capabilitiesAfterDissociate = capReqDefAfterDissociation + .getCapabilities(); + Map> requirementsAfterDissociate = capReqDefAfterDissociation + .getRequirements(); + + assertTrue(capabilitiesAfterDissociate.equals(capReqDef.getCapabilities())); + requirementsBeforeAssociate.put("tosca.capabilities.Container", expectedList); + assertTrue(requirementsAfterDissociate.equals(requirementsBeforeAssociate)); + } + + @Test + public void associateNotCompitableCapAndReq() throws Exception { + resourceDetailsReq = ElementFactory.getDefaultResourceByType("Database", NormativeTypesEnum.DATABASE, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, designerUser.getUserId(), ResourceTypeEnum.CP.toString()); // resourceType + // = + // VFC + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + assertTrue(requirementDef.getRelationships().size() == 1); + String requirement = requirementDef.getRelationships().get(0).getRequirement(); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 404, associateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_INSTANCE_MATCH_NOT_FOUND.name(), + new ArrayList(Arrays.asList(riReq.getName(), riCap.getName(), requirement)), + associateInstances.getResponse()); + + CapReqDef capReqDef = getResourceReqCap(); + + Map> capabilitiesAfterAssociate = capReqDef.getCapabilities(); + Map> requirementsAfterAssociate = capReqDef.getRequirements(); + + assertTrue(capabilitiesAfterAssociate.equals(capabilitiesBeforeAssociate)); + assertTrue(requirementsAfterAssociate.equals(requirementsBeforeAssociate)); + + } + + @Test + public void disassociateCpAndCpTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.CP.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, dissociateInstances.getErrorCode().intValue()); + assertTrue(getComponentInstancesRelations(resourceDetailsVF.getUniqueId()).isEmpty()); + + CapReqDef capReqDefAfterDissociate = getResourceReqCap(); + + List listOfRequierments = capReqDefAfterDissociate.getRequirements() + .get("tosca.capabilities.Container"); + assertEquals("Check requirement", 1, listOfRequierments.size()); + assertTrue(capReqDefAfterDissociate.getRequirements().equals(requirementsBeforeAssociate)); + assertTrue(capReqDefAfterDissociate.getCapabilities().equals(capabilitiesBeforeAssociate)); + } + + @Test + public void disassociateCpAndVfcTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VFC.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, dissociateInstances.getErrorCode().intValue()); + assertTrue(getComponentInstancesRelations(resourceDetailsVF.getUniqueId()).isEmpty()); + + CapReqDef capReqDefAfterDissociate = getResourceReqCap(); + + List listOfRequierments = capReqDefAfterDissociate.getRequirements() + .get("tosca.capabilities.Container"); + assertEquals("Check requirement", 1, listOfRequierments.size()); + assertTrue(capReqDefAfterDissociate.getRequirements().equals(requirementsBeforeAssociate)); + assertTrue(capReqDefAfterDissociate.getCapabilities().equals(capabilitiesBeforeAssociate)); + } + + @Test + public void disassociateCpAndVLTest() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, dissociateInstances.getErrorCode().intValue()); + assertTrue(getComponentInstancesRelations(resourceDetailsVF.getUniqueId()).isEmpty()); + + CapReqDef capReqDefAfterDissociate = getResourceReqCap(); + + List listOfRequierments = capReqDefAfterDissociate.getRequirements() + .get("tosca.capabilities.Container"); + assertEquals("Check requirement", 1, listOfRequierments.size()); + assertTrue(capReqDefAfterDissociate.getRequirements().equals(requirementsBeforeAssociate)); + assertTrue(capReqDefAfterDissociate.getCapabilities().equals(capabilitiesBeforeAssociate)); + } + + // Error handliing + // in the error should we get the unique id of instances instead of names + @Test + public void disassociateNotFoundAssociation() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + String requirementName = requirementDef.getRelationships().get(0).getRequirement(); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 404, dissociateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND.name(), + new ArrayList(Arrays.asList(riReq.getName(), riCap.getName(), requirementName)), + dissociateInstances.getResponse()); + + CapReqDef capReqDefAfterDissociate = getResourceReqCap(); + + List listOfRequierments = capReqDefAfterDissociate.getRequirements() + .get("tosca.capabilities.Container"); + assertEquals("Check requirement", 1, listOfRequierments.size()); + assertTrue(capReqDefAfterDissociate.getRequirements().equals(requirementsBeforeAssociate)); + assertTrue(capReqDefAfterDissociate.getCapabilities().equals(capabilitiesBeforeAssociate)); + } + + // Error handliing + @Test + public void disassociateRelationInVfNotFound() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + String uidNotFound = "123"; + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + uidNotFound, ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 404, dissociateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_NOT_FOUND.name(), + new ArrayList(Arrays.asList(uidNotFound)), dissociateInstances.getResponse()); + + // "serviceException": { + // "messageId": "SVC4063", + // "text": "Error: Requested \u0027%1\u0027 resource was not found.", + // "variables": [ + // "" + // ] + } + + @Test + public void disassociateWithDifferentDesigner() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2), resourceDetailsVF.getUniqueId(), + ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 409, dissociateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + dissociateInstances.getResponse()); + + CapReqDef capReqDefAfterDissociate = getResourceReqCap(); + + List listOfRequierments = capReqDefAfterDissociate.getRequirements() + .get("tosca.capabilities.Container"); + assertEquals("Check requirement", 1, listOfRequierments.size()); + assertTrue(capReqDefAfterDissociate.getRequirements().equals(requirementsBeforeAssociate)); + assertTrue(capReqDefAfterDissociate.getCapabilities().equals(capabilitiesBeforeAssociate)); + + } + + @Test + public void disassociateWithTester() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), resourceDetailsVF.getUniqueId(), + ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 409, dissociateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + dissociateInstances.getResponse()); + + CapReqDef capReqDefAfterDissociate = getResourceReqCap(); + + List listOfRequierments = capReqDefAfterDissociate.getRequirements() + .get("tosca.capabilities.Container"); + assertNotNull("Requierment is null after disassociate with tester", listOfRequierments); + assertEquals("Check requirement", 1, listOfRequierments.size()); + assertTrue(capReqDefAfterDissociate.getRequirements().equals(requirementsBeforeAssociate)); + assertTrue(capReqDefAfterDissociate.getCapabilities().equals(capabilitiesBeforeAssociate)); + } + + @Test + public void disassociateServiceWithUidOfVF() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VFC.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.SERVICE); + assertEquals("Check response code ", 404, dissociateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_FOUND.name(), + new ArrayList(Arrays.asList("")), dissociateInstances.getResponse()); + + CapReqDef capReqDefAfterDissociate = getResourceReqCap(); + + List listOfRequierments = capReqDefAfterDissociate.getRequirements() + .get("tosca.capabilities.Container"); + assertTrue(listOfRequierments == null); + assertTrue(getComponentInstancesRelations(resourceDetailsVF.getUniqueId()).size() != 0); + } + + @Test + public void disassociateWithEmptyVfUid() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + "", ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 404, dissociateInstances.getErrorCode().intValue()); + + CapReqDef capReqDef = getResourceReqCap(); + + requirementsBeforeAssociate.remove("tosca.capabilities.Container"); + assertTrue(capReqDef.getRequirements().equals(requirementsBeforeAssociate)); + + List list = capabilitiesBeforeAssociate.get("tosca.capabilities.Container"); + for (CapabilityDefinition cap : list) { + cap.setMinOccurrences("0"); + } + + Map> capabilitiesAfterAssociate = capReqDef.getCapabilities(); + assertTrue(capabilitiesAfterAssociate.equals(capabilitiesBeforeAssociate)); + } + + @Test + public void disassociateOneComponentDeleted() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + + RestResponse deleteResourceResponse = ResourceRestUtils.deleteResource(resourceDetailsCap.getUniqueId(), + designerUser.getUserId()); + ResourceRestUtils.checkDeleteResponse(deleteResourceResponse); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, dissociateInstances.getErrorCode().intValue()); + assertTrue(getComponentInstancesRelations(resourceDetailsVF.getUniqueId()).isEmpty()); + + CapReqDef capReqDefAfterDissociate = getResourceReqCap(); + + List listOfRequierments = capReqDefAfterDissociate.getRequirements() + .get("tosca.capabilities.Container"); + assertEquals("Check requirement", 1, listOfRequierments.size()); + assertTrue(capReqDefAfterDissociate.getRequirements().equals(requirementsBeforeAssociate)); + assertTrue(capReqDefAfterDissociate.getCapabilities().equals(capabilitiesBeforeAssociate)); + } + + @Test + public void disassociateNotCheckedoutVf() throws Exception { + createTwoAtomicResourcesByType(ResourceTypeEnum.CP.toString(), ResourceTypeEnum.VL.toString()); + + ComponentInstance riReq = createComponentInstance(resourceDetailsReq); + ComponentInstance riCap = createComponentInstance(resourceDetailsCap); + + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(); + Map> capabilitiesBeforeAssociate = capReqDefBeforeAssociate + .getCapabilities(); + Map> requirementsBeforeAssociate = capReqDefBeforeAssociate + .getRequirements(); + + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(riReq, riCap, + capReqDefBeforeAssociate); + + RestResponse changeResourceStateToCheckin = LifecycleRestUtils.changeResourceState(resourceDetailsVF, + designerUser, LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.checkSuccess(changeResourceStateToCheckin); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", 409, dissociateInstances.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + dissociateInstances.getResponse()); + + CapReqDef capReqDefAfterDissociate = getResourceReqCap(); + assertTrue(capReqDefAfterDissociate.getRequirements().equals(requirementsBeforeAssociate)); + assertTrue(capReqDefAfterDissociate.getCapabilities().equals(capabilitiesBeforeAssociate)); + + RestResponse changeResourceStateToCheckout = LifecycleRestUtils.changeResourceState(resourceDetailsVF, + designerUser, LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.checkSuccess(changeResourceStateToCheckout); + + requirementDef = setUidsOfInstancesAfterLifecycleStateChange(riReq, riCap, capReqDefBeforeAssociate); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, designerUser, + resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF.getUniqueId())); + + RestResponse secondDisociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, + designerUser, resourceDetailsVF.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, secondDisociateInstances.getErrorCode().intValue()); + assertTrue(getComponentInstancesRelations(resourceDetailsVF.getUniqueId()).isEmpty()); + + RestResponse changeResourceStateToCheckout2 = LifecycleRestUtils.changeResourceState(resourceDetailsVF, + designerUser, LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.checkSuccess(changeResourceStateToCheckout2); + RestResponse changeResourceStateToCheckout3 = LifecycleRestUtils.changeResourceState(resourceDetailsVF, + designerUser, LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.checkSuccess(changeResourceStateToCheckout3); + + assertTrue(getComponentInstancesRelations(resourceDetailsVF.getUniqueId()).isEmpty()); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/CreateResourceApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/CreateResourceApiTest.java new file mode 100644 index 0000000000..50d1056d76 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/CreateResourceApiTest.java @@ -0,0 +1,2222 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.validation.constraints.AssertTrue; + +import org.apache.log4j.lf5.util.ResourceUtils; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceRespJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.Convertor; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ResourceValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ServiceValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +/** + * @author yshlosberg + * + */ +public class CreateResourceApiTest extends ComponentBaseTest { + + private static Logger log = LoggerFactory.getLogger(CreateResourceApiTest.class.getName()); + + String contentTypeHeaderData = "application/json"; + String acceptHeaderDate = "application/json"; + String resourceVersion = "0.1"; + + @Rule + public static TestName name = new TestName(); + + public CreateResourceApiTest() { + super(name, CreateResourceApiTest.class.getName()); + } + + @Test + public void createResourceTest() throws Exception { + + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // ResourceReqDetails resourceDetails = new + // ResourceReqDetails(resourceName, description, resourceTags, category, + // derivedFrom, vendorName, vendorRelease, contactId, icon); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + String resourceName = resourceDetails.getName(); + resourceDetails.setTags(Arrays.asList(resourceName, resourceName, resourceName, resourceName, "tag2", "tag2")); + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResponse.getErrorCode().intValue()); + + // validate response + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails, + resourceVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + ResourceValidationUtils.validateResp(createResponse, resourceRespJavaObject); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + @Test + public void createResourceNonDefaultResourceTypeTest() throws Exception { + + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + String resourceType = ResourceTypeEnum.CP.toString(); + resourceDetails.setResourceType(resourceType); + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResponse.getErrorCode().intValue()); + + // validate response + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails, + resourceVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + resourceRespJavaObject.setResourceType(resourceType); + ResourceValidationUtils.validateResp(createResponse, resourceRespJavaObject); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + @Test + public void createResourceTest_costAndLicenseType() throws Exception { + + // init ADMIN user + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("12355.345"); + resourceDetails.setLicenseType("User"); + + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResponse.getErrorCode().intValue()); + + // validate response + String resourceVersion = "0.1"; + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails, + resourceVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + ResourceValidationUtils.validateResp(createResponse, resourceRespJavaObject); + + // validate get response + + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + + } + + // ////Benny + @Test + public void createResourceTest_CostIsMissing() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + // resourceDetails.setCost("12355.345"); + resourceDetails.setLicenseType("User"); + + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResponse.getErrorCode().intValue()); + + // validate response + String resourceVersion = "0.1"; + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails, + resourceVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + ResourceValidationUtils.validateResp(createResponse, resourceRespJavaObject); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + } + + @Test + public void createResourceTest_LicenseTypeMissing() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("12355.345"); + // resourceDetails.setLicenseType("User"); + + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResponse.getErrorCode().intValue()); + + // validate response + String resourceVersion = "0.1"; + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails, + resourceVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + ResourceValidationUtils.validateResp(createResponse, resourceRespJavaObject); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + } + + @Test + public void createResourceTest_LicenseType_Installation() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("99999.999"); + resourceDetails.setLicenseType("Installation"); + + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResponse.getErrorCode().intValue()); + + // validate response + String resourceVersion = "0.1"; + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails, + resourceVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + ResourceValidationUtils.validateResp(createResponse, resourceRespJavaObject); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + } + + @Test + public void createResourceTest_LicenseType_CPU() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("0.0"); + resourceDetails.setLicenseType("CPU"); + + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResponse.getErrorCode().intValue()); + + // validate response + String resourceVersion = "0.1"; + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails, + resourceVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + ResourceValidationUtils.validateResp(createResponse, resourceRespJavaObject); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + } + + @Test + public void createResourceTest_LicenseType_Uppercase() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("0.0"); + resourceDetails.setLicenseType("INSTALLATION"); + + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", createResponse.getResponseMessage()); + } + + @Test + public void createResourceTest_LicenseType_Invalid() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("0.0"); + resourceDetails.setLicenseType("CPUUU"); + + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", createResponse.getResponseMessage()); + } + + @Test + public void createResourceTest_CostValidation_noNumeric() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("12355.345"); + resourceDetails.setLicenseType("User"); + resourceDetails.setCost("12355.34b"); + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", + createResponse.getResponseMessage().toString()); + + } + + @Test + public void createResourceTest_CostValidation_valueLength() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("12355.345"); + resourceDetails.setLicenseType("User"); + + // Adding invalid cost + resourceDetails.setCost("12355.3434"); + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", + createResponse.getResponseMessage().toString()); + } + + @Test + public void createResourceTest_CostValidation_PriceLimitations() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("12355.345"); + resourceDetails.setLicenseType("User"); + + // Adding invalid cost + RestResponse createResponse; + // create resource + + resourceDetails.setCost("000000.000"); + createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", + createResponse.getResponseMessage().toString()); + + /* + * resourceDetails.setCost("0550.457"); createResponse = + * resourceUtils.createResource(resourceDetails, sdncModifierDetails); + * assertNotNull("check response object is not null after create resource" + * , createResponse); + * assertNotNull("check error code exists in response after create resource" + * , createResponse.getErrorCode()); + * assertEquals("Check response code after create resource", 400, + * createResponse.getErrorCode().intValue()); + * assertEquals("Check response code after create resource", + * "Bad Request", createResponse.getResponseMessage().toString()); + */ + + resourceDetails.setCost("1"); + createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", + createResponse.getResponseMessage().toString()); + + resourceDetails.setCost("123555.340"); + createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", + createResponse.getResponseMessage().toString()); + + resourceDetails.setCost("123.4570"); + createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", + createResponse.getResponseMessage().toString()); + + resourceDetails.setCost("123555.30"); + createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", + createResponse.getResponseMessage().toString()); + + resourceDetails.setCost("123.5550"); + createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", + createResponse.getResponseMessage().toString()); + + } + + @Test + public void createResourceTest_CostIsNull() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("12355.345"); + resourceDetails.setLicenseType("User"); + resourceDetails.setCost(""); + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", createResponse.getResponseMessage()); + + } + + @Test + public void createResourceTest_LicenseIsNull() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // set resource details + String resourceName = "CISCO4572"; + String description = "description"; + // Duplicate tags are allowed and should be de-duplicated by the server + // side + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add(resourceName); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + // Adding cost and licenseType + resourceDetails.setCost("12355.345"); + resourceDetails.setLicenseType("User"); + resourceDetails.setLicenseType(""); + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 400, createResponse.getErrorCode().intValue()); + assertEquals("Check response code after create resource", "Bad Request", createResponse.getResponseMessage()); + + } + + @Test + public void createResourceTest_uri_methods() throws Exception { + + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + ResourceReqDetails resourceDetails = createRandomResource(); + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(resourceDetails); + log.debug(userBodyJson); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.CREATE_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort()); + + RestResponse createResourceResponse2 = http.httpSendByMethod(url, "PUT", userBodyJson, headersMap); + + // validate response + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.NOT_ALLOWED.name()); + + assertNotNull("check response object is not null after create resource", createResourceResponse2); + assertNotNull("check error code exists in response after create resource", + createResourceResponse2.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), + createResourceResponse2.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), variables, + createResourceResponse2.getResponse()); + + } + + private ResourceReqDetails createRandomResource() { + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + return resourceDetails; + } + + @Test + public void createResource_role_tester() throws Exception { + + // init TESTER user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + + ResourceReqDetails resourceDetails2 = createRandomResource(); + + // create resource + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), variables, + restResponse2.getResponse()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setModifierUid(UserRoleEnum.TESTER.getUserId()); + expectedResourceAuditJavaObject.setModifierName(UserRoleEnum.TESTER.getUserName()); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + // TODO DE171450(to check) + @Test + public void createResource_role_DESIGNER() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ResourceReqDetails resourceDetails = createRandomResource(); + RestResponse restResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + // validate response + assertNotNull("check response object is not null after create resource", restResponse); + assertNotNull("check error code exists in response after create resource", restResponse.getErrorCode()); + assertEquals( + "Check response code after create resource, response message is: " + restResponse.getResponseMessage(), + 201, restResponse.getErrorCode().intValue()); + + } + + @Test + public void createResource_missing_header() throws Exception { + // init ADMIN user + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + ResourceReqDetails resourceDetails = createRandomResource(); + + // set null in userId header + sdncModifierDetails.setUserId(null); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_INFORMATION.name(), variables, + restResponse2.getResponse()); + + // //validate audit + // + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // resourceUtils.constructFieldsForAuditValidation(resourceDetails,resourceVersion); + // + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setModifierUid("null null"); + // expectedResourceAuditJavaObject.setModifierName("null null"); + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setCurrState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrVersion(""); + // expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + // + // String auditDesc = + // AuditValidationUtils.buildAuditDescription(errorInfo, variables); + // expectedResourceAuditJavaObject.setDesc(auditDesc); + // + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction); + // TODO: yshlosberg enable back + + } + + @Test + public void createResource_existing_resource() throws Exception { + // init ADMIN user + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // ResourceReqDetails resourceDetails = createRandomResource(); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + + // create resource + RestResponse restResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + assertNotNull("check response object is not null after create resource", restResponse); + assertNotNull("check error code exists in response after create resource", restResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + + // set resource details + ResourceReqDetails resourceDetails2 = ElementFactory.getDefaultResource(); + resourceDetails2.setName(resourceDetails.getName()); + + // clean ES DB + DbUtils.cleanAllAudits(); + + // create resource + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_NAME_ALREADY_EXIST.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList("Resource", resourceDetails2.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_NAME_ALREADY_EXIST.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_without_category() throws Exception { + + // init ADMIN user + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + ; + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + category = null; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_CATEGORY.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList("Resource"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_CATEGORY.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_empty_category() throws Exception { + + // init ADMIN user + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + category = ""; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_CATEGORY.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList("Resource"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_CATEGORY.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_without_tags() throws Exception { + + // init ADMIN user + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + ; + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_TAGS.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_TAGS.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + // TODO DE171450(to check) + @Test + public void createResourceTest_with_multiple_tags() throws Exception { + + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // // set resource details + // String resourceName = "CISCO4"; + // String description = "description"; + // ArrayList resourceTags = new ArrayList(); + // resourceTags.add(resourceName); + // resourceTags.add("tag2"); + // String category = ResourceServiceCategoriesEnum.VOIP.getValue(); + // ArrayList derivedFrom = new ArrayList(); + // derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + // String vendorName = "Oracle"; + // String vendorRelease = "1.5"; + // String icon = "myICON"; + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setTags(Arrays.asList(resourceDetails.getName(), "tag2")); + + // create resource + RestResponse restResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + assertNotNull("check response object is not null after create resource", restResponse); + assertNotNull("check error code exists in response after create resource", restResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + + } + + @Test + public void createResourceTest_empty_tag() throws Exception { + + // init ADMIN user + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(""); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + RestResponse restResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_FIELD_FORMAT.name()); + + assertNotNull("check response object is not null after create resouce", restResponse); + assertNotNull("check error code exists in response after create resource", restResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), restResponse.getErrorCode()); + + List variables = Arrays.asList("Resource", "tag"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FIELD_FORMAT.name(), variables, + restResponse.getResponse()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_with_empty_vendorName() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + vendorName = ""; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_VENDOR_NAME.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_VENDOR_NAME.name(), variables, + restResponse2.getResponse()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_without_vendorName() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + vendorName = null; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + assertNotNull("check response object is not null after create resource", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create resource", 400, restResponse2.getErrorCode().intValue()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_VENDOR_NAME.name(), variables, + restResponse2.getResponse()); + + } + + @Test + public void createResourceTest_with_empty_vendorRelease() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add("root"); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + vendorRelease = ""; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_VENDOR_RELEASE.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_VENDOR_RELEASE.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_without_vendorRelease() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + vendorRelease = null; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_VENDOR_RELEASE.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_VENDOR_RELEASE.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_with_empty_contactId() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + contactId = ""; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_CONTACT.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList("Resource"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_CONTACT.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_without_contactId() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + contactId = null; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_CONTACT.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList("Resource"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_CONTACT.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_with_empty_icon() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + icon = ""; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_ICON.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList("Resource"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_ICON.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_without_icon() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + icon = null; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_ICON.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList("Resource"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_ICON.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_with_empty_description() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + description = ""; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList("Resource"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createResourceTest_without_description() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // set resource details + String resourceName = "CISCO4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + // set resource details + description = null; + + ResourceReqDetails resourceDetails2 = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + // create resource + + RestResponse restResponse2 = ResourceRestUtils.createResource(resourceDetails2, sdncModifierDetails); + + // validate response + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name()); + + assertNotNull("check response object is not null after create resouce", restResponse2); + assertNotNull("check error code exists in response after create resource", restResponse2.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse2.getErrorCode()); + + List variables = Arrays.asList("Resource"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name(), variables, + restResponse2.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails2, resourceVersion); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createAndGetResourceByNameAndVersion() throws Exception { + + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + ResourceReqDetails resourceDetailsComp = ElementFactory.getDefaultResource("testresourceComp", + NormativeTypesEnum.COMPUTE, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, sdncModifierDetails.getUserId()); + + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetailsComp, sdncModifierDetails); + // validate response + assertEquals("Check response code after create resource", 201, createResponse.getErrorCode().intValue()); + + String resourceVersion = "0.1"; + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetailsComp, + resourceVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + ResourceValidationUtils.validateResp(createResponse, resourceRespJavaObject); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResourceByNameAndVersion( + sdncModifierDetails.getUserId(), resourceDetailsComp.getName(), resourceDetailsComp.getVersion()); + assertEquals("Check response code after delete resource", 200, resourceGetResponse.getErrorCode().intValue()); + // Resource resource = + // ResourceRestUtils.parseResourceFromListResp(resourceGetResponse); + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + // resourceDetailsComp.setUniqueId(resource.getUniqueId()); + + } + + @Test + public void createResourceResourceTypeNotExistsTest() throws Exception { + + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + String resourceType = "NOT EXISTS"; + resourceDetails.setResourceType(resourceType); + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_CONTENT.name()); + + assertNotNull("check response object is not null after create resouce", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), createResponse.getErrorCode()); + + List variables = new ArrayList<>(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), variables, + createResponse.getResponse()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resourceDetails, resourceVersion); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + @Test + public void createResourceResourceTypeEmptyTest() throws Exception { + + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + // String resourceType = ""; + // resourceDetails.setResourceType(resourceType); + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // ErrorInfo errorInfo = + // ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_CONTENT.name()); + // + // assertNotNull("check response object is not null after create + // resouce", createResponse); + // assertNotNull("check error code exists in response after create + // resource", createResponse.getErrorCode()); + // assertEquals("Check response code after create service", + // errorInfo.getCode(), createResponse.getErrorCode()); + // + // List variables = new ArrayList<>(); + // ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), + // variables, createResponse.getResponse()); + // + // // validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // Convertor.constructFieldsForAuditValidation(resourceDetails, + // resourceVersion); + // String auditAction = "Create"; + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState(""); + // expectedResourceAuditJavaObject.setCurrVersion(""); + // expectedResourceAuditJavaObject.setResourceName(""); + // expectedResourceAuditJavaObject.setModifierUid(ElementFactory.getDefaultUser(UserRoleEnum.ADMIN).getUserId()); + // expectedResourceAuditJavaObject.setModifierName(ElementFactory.getDefaultUser(UserRoleEnum.ADMIN).getFullName()); + // expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + // + // String auditDesc = + // AuditValidationUtils.buildAuditDescription(errorInfo, variables); + // expectedResourceAuditJavaObject.setDesc(auditDesc); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + } + + @Test + public void checkInvariantUuidIsImmutable() throws Exception { + // choose the user to create resource + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + String invariantUuidDefinedByUser = "!!!!!!!!!!!!!!!!!!!!!!!!"; + resourceDetails.setInvariantUUID(invariantUuidDefinedByUser); + String resourceName = resourceDetails.getName(); + resourceDetails.setTags(Arrays.asList(resourceName, resourceName, resourceName, resourceName, "tag2", "tag2")); + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncUserDetails); + BaseRestUtils.checkStatusCode(createResponse, "create request failed", false, 201); + // validate response + assertNotNull("check response object is not null after create resource", createResponse); + assertNotNull("check error code exists in response after create resource", createResponse.getErrorCode()); + assertEquals("Check response code after create resource", 201, createResponse.getErrorCode().intValue()); + + Resource resourceCreation = ResponseParser.convertResourceResponseToJavaObject(createResponse.getResponse()); + String invariantUUIDcreation = resourceCreation.getInvariantUUID(); + // validate response + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails, + resourceVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + ResourceValidationUtils.validateResp(createResponse, resourceRespJavaObject); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncUserDetails, + resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(resourceGetResponse); + Resource resourceGetting = ResponseParser + .convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + String invariantUUIDgetting = resourceGetting.getInvariantUUID(); + assertEquals(invariantUUIDcreation, invariantUUIDgetting); + + // Update resource with new invariant UUID + RestResponse restResponseUpdate = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncUserDetails, + resourceDetails.getUniqueId()); + BaseRestUtils.checkSuccess(restResponseUpdate); + Resource updatedResource = ResponseParser.convertResourceResponseToJavaObject(restResponseUpdate.getResponse()); + String invariantUUIDupdating = updatedResource.getInvariantUUID(); + assertEquals(invariantUUIDcreation, invariantUUIDupdating); + + // Do checkin + RestResponse restResponseCheckin = LifecycleRestUtils.changeResourceState(resourceDetails, sdncUserDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + BaseRestUtils.checkSuccess(restResponseCheckin); + Resource checkinResource = ResponseParser + .convertResourceResponseToJavaObject(restResponseCheckin.getResponse()); + String invariantUUIDcheckin = checkinResource.getInvariantUUID(); + String version = checkinResource.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDcheckin); + assertEquals(version, "0.1"); + + // Do checkout + RestResponse restResponseCheckout = LifecycleRestUtils.changeResourceState(resourceDetails, sdncUserDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + BaseRestUtils.checkSuccess(restResponseCheckout); + Resource ResourceResource = ResponseParser + .convertResourceResponseToJavaObject(restResponseCheckout.getResponse()); + String invariantUUIDcheckout = ResourceResource.getInvariantUUID(); + version = ResourceResource.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDcheckout); + assertEquals(version, "0.2"); + + // do certification request + RestResponse restResponseCertificationRequest = LifecycleRestUtils.changeResourceState(resourceDetails, + sdncUserDetails, resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + BaseRestUtils.checkSuccess(restResponseCertificationRequest); + Resource certificationRequestResource = ResponseParser + .convertResourceResponseToJavaObject(restResponseCertificationRequest.getResponse()); + String invariantUUIDcertificationRequest = certificationRequestResource.getInvariantUUID(); + version = certificationRequestResource.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDcertificationRequest); + assertEquals(version, "0.2"); + + // start certification + RestResponse restResponseStartCertification = LifecycleRestUtils.changeResourceState(resourceDetails, + sdncUserDetails, resourceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + BaseRestUtils.checkSuccess(restResponseStartCertification); + Resource startCertificationRequestResource = ResponseParser + .convertResourceResponseToJavaObject(restResponseStartCertification.getResponse()); + String invariantUUIDStartCertification = startCertificationRequestResource.getInvariantUUID(); + version = startCertificationRequestResource.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDStartCertification); + assertEquals(version, "0.2"); + + // certify + RestResponse restResponseCertify = LifecycleRestUtils.changeResourceState(resourceDetails, sdncUserDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFY); + BaseRestUtils.checkSuccess(restResponseCertify); + Resource certifyResource = ResponseParser + .convertResourceResponseToJavaObject(restResponseCertify.getResponse()); + String invariantUUIDcertify = certifyResource.getInvariantUUID(); + version = certifyResource.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDcertify); + assertEquals(version, "1.0"); + + } + + // US672129 BENNY + + private void getResourceValidateInvariantUuid(String resourceUniqueId, String invariantUUIDcreation) + throws Exception { + RestResponse getResource = ResourceRestUtils.getResource(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + resourceUniqueId); + BaseRestUtils.checkSuccess(getResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + assertEquals(invariantUUIDcreation, resource.getInvariantUUID()); + } + + @Test + public void resourceInvariantUuid() throws Exception { + + User designerUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + User testerUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResourceByType("VF200", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, designerUser.getUserId(), ResourceTypeEnum.VF.toString()); + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService("newtestservice1", + ServiceCategoriesEnum.MOBILITY, designerUser.getUserId()); + + // ResourceReqDetails resourceDetails = + // ElementFactory.getDefaultResource(); + resourceDetails.setInvariantUUID("kokomoko"); + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, designerUser); + assertEquals("Check response code after create resource", BaseRestUtils.STATUS_CODE_CREATED, + createResponse.getErrorCode().intValue()); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResponse.getResponse(), Resource.class); + String invariantUUIDcreation = resource.getInvariantUUID(); // generated + // when the + // component + // is + // created + // and never + // changed + // get resource and verify InvariantUuid is not changed + getResourceValidateInvariantUuid(resource.getUniqueId(), invariantUUIDcreation); + + // Update resource with new invariant UUID + resourceDetails.setInvariantUUID("1234567890"); + RestResponse updateResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, designerUser, + resourceDetails.getUniqueId()); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, + updateResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resource.getUniqueId(), invariantUUIDcreation); + + // checkIn resource + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUser, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getResourceValidateInvariantUuid(resource.getUniqueId(), invariantUUIDcreation); + + // checkIn resource + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUser, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getResourceValidateInvariantUuid(resource.getUniqueId(), invariantUUIDcreation); + // certification request + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUser, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getResourceValidateInvariantUuid(resource.getUniqueId(), invariantUUIDcreation); + // start certification + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getResourceValidateInvariantUuid(resource.getUniqueId(), invariantUUIDcreation); + // certify + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUser, LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getResourceValidateInvariantUuid(resource.getUniqueId(), invariantUUIDcreation); + // update resource + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUser, + LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + resourceDetails.setDescription("updatedDescription"); + resourceDetails.setVendorRelease("1.2.3.4"); + updateResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, designerUser, + resourceDetails.getUniqueId()); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, updateResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + + // certification request + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUser, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + + // checkout resource + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUser, + LifeCycleStatesEnum.CHECKOUT); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + + // certification request + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUser, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + // start certification + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + + // cancel certification + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUser, + LifeCycleStatesEnum.CANCELCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + + // start certification + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + + // failure + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, testerUser, + LifeCycleStatesEnum.FAILCERTIFICATION); + assertEquals(STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + + // upload artifact + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUser, + LifeCycleStatesEnum.CHECKOUT); + ArtifactReqDetails artifactDetails = ElementFactory.getDefaultArtifact(); + ArtifactRestUtils.addInformationalArtifactToResource(artifactDetails, designerUser, + resourceDetails.getUniqueId()); + assertEquals(STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + + // checkIn resource + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, designerUser, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + // create instance + RestResponse createServiceResponse = ServiceRestUtils.createService(serviceDetails, designerUser); + ResourceRestUtils.checkCreateResponse(createServiceResponse); + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetails); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, designerUser, serviceDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_CREATED, + createResourceInstanceResponse.getErrorCode().intValue()); + getResourceValidateInvariantUuid(resourceDetails.getUniqueId(), invariantUUIDcreation); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/GetAllResourceVersions.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/GetAllResourceVersions.java new file mode 100644 index 0000000000..25c3242d2c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/GetAllResourceVersions.java @@ -0,0 +1,582 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.lf5.util.ResourceUtils; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class GetAllResourceVersions extends ComponentBaseTest { + + private static Logger logger = LoggerFactory.getLogger(GetAllResourceVersions.class.getName()); + protected User designerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + protected User adminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + protected ResourceReqDetails resourceDetails; + + public static TestName name = new TestName(); + + public GetAllResourceVersions() { + super(name, GetAllResourceVersions.class.getName()); + + } + + //// NEW + + protected void deleteAllVersionOfResource() throws Exception { + RestResponse response = null; + + String[] versions = { "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "2.0", + "2.1", "2.2", "2.3", "2.4", "2.5", "3.0", "4.0", "4.1" }; + + for (String version : versions) { + + response = ResourceRestUtils.deleteResourceByNameAndVersion(designerDetails, + resourceDetails.getName().toUpperCase(), version); + AssertJUnit.assertTrue("delete request returned status:" + response.getErrorCode(), + response.getErrorCode() == 204 || response.getErrorCode() == 404); + + response = ResourceRestUtils.deleteResourceByNameAndVersion(designerDetails, resourceDetails.getName(), + version); + AssertJUnit.assertTrue("delete request returned status:" + response.getErrorCode(), + response.getErrorCode() == 204 || response.getErrorCode() == 404); + + } + } + + @BeforeMethod + public void init() throws Exception { + resourceDetails = defineResourse(); + deleteAllVersionOfResource(); + + } + + @AfterMethod + public void endOfTests() throws Exception { + deleteAllVersionOfResource(); + } + + protected ResourceReqDetails defineResourse() { + String resourceName = "cisco4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + // String category = ServiceCategoriesEnum.MOBILITY.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add("tosca.nodes.Root"); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, null, + derivedFrom, vendorName, vendorRelease, contactId, icon); + resourceDetails.addCategoryChain(ResourceCategoryEnum.GENERIC_INFRASTRUCTURE.getCategory(), + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE.getSubCategory()); + + return resourceDetails; + } + + @Test + public void getResourceAllVersions_version15() throws Exception { + // create resource + Map origVersionsMap = new HashMap(); + RestResponse restResponse = createResource(designerDetails, resourceDetails); + AssertJUnit.assertTrue("create request returned status:" + restResponse.getErrorCode(), + restResponse.getErrorCode() == 201); + String resourceName = resourceDetails.getName(); + // resourceUtils.addResourceMandatoryArtifacts(designerDetails, + // restResponse); + + // change resource version to 0.5 + RestResponse checkoutResource; + for (int x = 0; x < 4; x++) { + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + } + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFY); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + // change resource version to 1.5 + for (int x = 0; x < 5; x++) { + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + } + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(designerDetails, + resourceDetails.getUniqueId()); + Resource res = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + AssertJUnit.assertTrue(origVersionsMap.equals(getVersionsMap)); + + } + + protected RestResponse createResource(User sdncModifierDetails, ResourceReqDetails resourceDetails) + throws Exception { + // clean ES DB + DbUtils.cleanAllAudits(); + + // create resource + RestResponse restResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + AssertJUnit.assertNotNull("check response object is not null after create resource", restResponse); + AssertJUnit.assertNotNull("check error code exists in response after create resource", + restResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create resource", 201, + restResponse.getErrorCode().intValue()); + + return restResponse; + } + + @Test + public void getResourceAllVersions_version05() throws Exception { + + // create resource + RestResponse restResponse = createResource(designerDetails, resourceDetails); + Map origVersionsMap = new HashMap(); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + // resourceUtils.addResourceMandatoryArtifacts(designerDetails, + // restResponse); + // change resource version to 0.5 + RestResponse checkoutResource; + + logger.debug("Changing resource life cycle "); + for (int x = 0; x < 4; x++) { + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + } + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(designerDetails, + resourceDetails.getUniqueId()); + Resource res = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + + } + + @Test + public void getResourceAllVersions_version01() throws Exception { + // create resource + RestResponse restResponse = createResource(designerDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + Map origVersionsMap = new HashMap(); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + + // resourceUtils.addResourceMandatoryArtifacts(designerDetails, + // restResponse); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(designerDetails, + resourceDetails.getUniqueId()); + Resource res = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + + } + + @Test + public void getResourceAllVersions_version25() throws Exception { + + Map origVersionsMap = new HashMap(); + + // create resource + RestResponse restResponse = createResource(designerDetails, resourceDetails); + assertTrue("create request returned status:" + restResponse.getErrorCode(), restResponse.getErrorCode() == 201); + String resourceName = resourceDetails.getName(); + // resourceUtils.addResourceMandatoryArtifacts(designerDetails, + // restResponse); + + // change resource version to 0.5 + RestResponse checkoutResource; + for (int x = 0; x < 4; x++) { + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + } + + // resource version 1.0 + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + + // change resource version to 1.5 + for (int x = 0; x < 5; x++) { + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + } + + // resource version 2.0 + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + + // change resource version to 2.5 + for (int x = 0; x < 5; x++) { + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + } + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(designerDetails, + resourceDetails.getUniqueId()); + Resource res = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + + } + + @Test + public void getResourceAllVersions_ReadyForCertification_version05() throws Exception { + Map origVersionsMap = new HashMap(); + // create resource + RestResponse restResponse = createResource(designerDetails, resourceDetails); + assertTrue("create request returned status:" + restResponse.getErrorCode(), restResponse.getErrorCode() == 201); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + String resourceName = resourceDetails.getName(); + // resourceUtils.addResourceMandatoryArtifacts(designerDetails, + // restResponse); + + // change resource version to 0.5 + RestResponse checkoutResource; + for (int x = 0; x < 4; x++) { + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + } + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(designerDetails, + resourceDetails.getUniqueId()); + Resource res = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + + } + + @Test + public void getResourceAllVersions_CertifactionInProgress_version05() throws Exception { + Map origVersionsMap = new HashMap(); + // create resource + RestResponse restResponse = createResource(designerDetails, resourceDetails); + assertTrue("create request returned status:" + restResponse.getErrorCode(), restResponse.getErrorCode() == 201); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + + String resourceName = resourceDetails.getName(); + // resourceUtils.addResourceMandatoryArtifacts(designerDetails, + // restResponse); + + // change resource version to 0.5 + RestResponse checkoutResource; + for (int x = 0; x < 4; x++) { + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + } + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(designerDetails, + resourceDetails.getUniqueId()); + Resource res = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + + } + + @Test + public void getResourceAllVersions_Certified_version10() throws Exception { + + Map origVersionsMap = new HashMap(); + + // create resource + RestResponse restResponse = createResource(designerDetails, resourceDetails); + assertTrue("create request returned status:" + restResponse.getErrorCode(), restResponse.getErrorCode() == 201); + String resourceName = resourceDetails.getName(); + // resourceUtils.addResourceMandatoryArtifacts(designerDetails, + // restResponse); + + // change resource version to 0.5 + RestResponse checkoutResource; + for (int x = 0; x < 4; x++) { + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + + } + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(designerDetails, + resourceDetails.getUniqueId()); + Resource res = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + + } + + @Test + public void getResourceAllVersions_Certified_version20() throws Exception { + + Map origVersionsMap = new HashMap(); + + // create resource + RestResponse restResponse = createResource(designerDetails, resourceDetails); + assertTrue("create request returned status:" + restResponse.getErrorCode(), restResponse.getErrorCode() == 201); + String resourceName = resourceDetails.getName(); + // resourceUtils.addResourceMandatoryArtifacts(designerDetails, + // restResponse); + + // change resource version to 0.5 + RestResponse checkoutResource; + for (int x = 0; x < 4; x++) { + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + } + + // get to version 1.0 + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + + // change resource version to 1.5 + for (int x = 0; x < 4; x++) { + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, designerDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, + checkoutResource.getErrorCode().intValue()); + } + + // get to version 1.0 + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + origVersionsMap.put(resourceDetails.getVersion(), resourceDetails.getUniqueId()); + + // validate get response + RestResponse resourceGetResponse = ResourceRestUtils.getResource(designerDetails, + resourceDetails.getUniqueId()); + Resource res = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + + } + + @Test + public void getResourceAllVersions_ResourceNotFound() throws Exception { + + RestResponse resourceGetResponse = ResourceRestUtils.getResource(designerDetails, "123456789"); + assertEquals("Check response code after checkout resource", 404, resourceGetResponse.getErrorCode().intValue()); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/GetResourceNotAbstractApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/GetResourceNotAbstractApiTest.java new file mode 100644 index 0000000000..562150e5e2 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/GetResourceNotAbstractApiTest.java @@ -0,0 +1,328 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.lf5.util.ResourceUtils; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.imports.ImportGenericResourceCITest; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class GetResourceNotAbstractApiTest extends ComponentBaseTest { + + private static Logger logger = LoggerFactory.getLogger(ComponentBaseTest.class.getName()); + protected static final int STATUS_CODE_GET_SUCCESS = 200; + + protected Config config = Config.instance(); + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json"; + + @Rule + public static TestName name = new TestName(); + + public GetResourceNotAbstractApiTest() { + super(name, GetResourceNotAbstractApiTest.class.getName()); + } + + @Test + public void getNotAbstractResourceList() throws Exception { + + // remove all the not abstract resources + // Map originalState = + // ImportResourceCITest.removeAllNormativeTypeResources(); + + // import all the default not abstract resources + // ImportGenericResourceCITest.importAllNormativeTypesResources(UserRoleEnum.ADMIN); + + // Get not abstract resources + RestResponse getResourceNotAbstarctResponse = getNotAbstractResources(); + // Check that received 200. + assertEquals("Check response code after get abstract resources", STATUS_CODE_GET_SUCCESS, + getResourceNotAbstarctResponse.getErrorCode().intValue()); + // Verify that all the resources not abstract + assertTrue("One or more resources are abstract", isAllResourcesNotAbstract(getResourceNotAbstarctResponse)); + // Verify that all the resources are certified + assertTrue("Not all the resources are certified", isAllResourcesCertified(getResourceNotAbstarctResponse)); + + String objectStorageUid = "ObjectStorage"; + String computeUid = "Compute"; + String blockStorageUid = "BlockStorage"; + String loadBalancerUid = "LoadBalancer"; + // String portUid = "tosca.nodes.Network.Port"; + String portUid = "Port"; + String networkUid = "Network"; + String databaseUid = "Database"; + + // Compare expected list of abstract resources to actual list of + // abstract resources. + List expectedNotAbstractResourcesUniqueIdArray = new ArrayList(Arrays.asList(computeUid, + databaseUid, objectStorageUid, blockStorageUid, loadBalancerUid, portUid, networkUid)); + + List actualNotAbstarctResourcesUniqueIdArray = restResponseToListByHeader( + getResourceNotAbstarctResponse, "name"); + + // Collections.sort(actualNotAbstarctResourcesUniqueIdArray); + // Collections.sort(expectedNotAbstractResourcesUniqueIdArray); + + List toFind = new ArrayList<>(); + toFind.add(objectStorageUid); + toFind.add(computeUid); + toFind.add(blockStorageUid); + toFind.add(loadBalancerUid); + toFind.add(portUid); + + boolean removeAll = toFind.removeAll(actualNotAbstarctResourcesUniqueIdArray); + logger.debug("Cannot find resources {}", toFind.toString()); + + for (String expectedResource : expectedNotAbstractResourcesUniqueIdArray) { + if (false == actualNotAbstarctResourcesUniqueIdArray.contains(expectedResource)) { + // System.out.println("Not found abstract resource " + + // expectedResource); + } + } + + assertTrue( + "Expected abstract resources list: " + expectedNotAbstractResourcesUniqueIdArray.toString() + + " Actual: " + actualNotAbstarctResourcesUniqueIdArray.toString(), + actualNotAbstarctResourcesUniqueIdArray.containsAll(expectedNotAbstractResourcesUniqueIdArray)); + + /* + * java.lang.AssertionError: Expected abstract resources list: + * [tosca.nodes.Compute, tosca.nodes.ObjectStorage, + * tosca.nodes.BlockStorage, tosca.nodes.LoadBalancer, + * tosca.nodes.Network.Port] Actual: [resourceforproperty216, + * tosca.nodes.Compute, tosca.nodes.Database, resourceforproperty217, + * resourceforproperty217, tosca.nodes.ObjectStorage, + * tosca.nodes.BlockStorage, tosca.nodes.LoadBalancer, + * tosca.nodes.network.Port, tosca.nodes.network.Network, + * resourceforproperty217, resourceforproperty217, + * resourceforproperty217, resourceforproperty217, + * resourceforproperty217, resourceforproperty217, + * resourceforproperty217, resourceforproperty217, + * resourceforproperty217, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317, + * resourceforproperty317, resourceforproperty317] + */ + + // Create resource (not certified) + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + String resourceName = "TestResource"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String category = ServiceCategoriesEnum.MOBILITY.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add("tosca.nodes.root"); + String vendorName = "Oracle"; + String vendorRelease = "1.0"; + String contactId = "Peter"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + // assertEquals("Check response code after create user", 201, + // restResponse.getErrorCode().intValue()); + + // Get not abstract resources + getResourceNotAbstarctResponse = getNotAbstractResources(); + // Check that received 200. + assertEquals("Check response code after get abstract resources", STATUS_CODE_GET_SUCCESS, + getResourceNotAbstarctResponse.getErrorCode().intValue()); + // Verify that all the resources not abstract + assertTrue("One or more resources are abstract", isAllResourcesNotAbstract(getResourceNotAbstarctResponse)); + // Verify that all the resources are certified + assertTrue("Not all the resources are certified", isAllResourcesCertified(getResourceNotAbstarctResponse)); + + // Compare expected list of abstract resources to actual list of + // abstract resources. + // expectedNotAbstractResourcesUniqueIdArray = new + // ArrayList(Arrays.asList("tosca.nodes.compute.1.0", + // "tosca.nodes.objectstorage.1.0", "tosca.nodes.blockstorage.1.0", + // "tosca.nodes.loadbalancer.1.0", "tosca.nodes.network.port.1.0")); + + // actualNotAbstarctResourcesUniqueIdArray = + // restResponseToListByHeader(getResourceNotAbstarctResponse, + // "uniqueId"); + + actualNotAbstarctResourcesUniqueIdArray = restResponseToListByHeader(getResourceNotAbstarctResponse, "name"); + + Collections.sort(actualNotAbstarctResourcesUniqueIdArray); + Collections.sort(expectedNotAbstractResourcesUniqueIdArray); + + for (String expectedResource : expectedNotAbstractResourcesUniqueIdArray) { + if (false == actualNotAbstarctResourcesUniqueIdArray.contains(expectedResource)) { + // System.out.println("Not found abstract resource " + + // expectedResource); + } + } + assertTrue( + "Expected abstract resources list: " + expectedNotAbstractResourcesUniqueIdArray.toString() + + " Actual: " + actualNotAbstarctResourcesUniqueIdArray.toString(), + actualNotAbstarctResourcesUniqueIdArray.containsAll(expectedNotAbstractResourcesUniqueIdArray)); + // assertTrue("Expected abstract resources list: "+ + // expectedNotAbstractResourcesUniqueIdArray.toString()+ " Actual: + // "+actualNotAbstarctResourcesUniqueIdArray.toString(),expectedNotAbstractResourcesUniqueIdArray.equals(actualNotAbstarctResourcesUniqueIdArray)); + + // restore the resources + // ImportResourceCITest.restoreToOriginalState(originalState); + + } + + protected RestResponse getNotAbstractResources() throws Exception { + HttpRequest httpRequest = new HttpRequest(); + + String url = String.format(Urls.GET_ALL_NOT_ABSTRACT_RESOURCES, config.getCatalogBeHost(), + config.getCatalogBePort()); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), "cs0008"); + + RestResponse getResourceNotAbstarctResponse = httpRequest.httpSendGet(url, headersMap); + + return getResourceNotAbstarctResponse; + } + + protected List restResponseToListByHeader(RestResponse restResponse, String restResponseHeader) { + JsonElement jelement = new JsonParser().parse(restResponse.getResponse()); + JsonArray jsonArray = jelement.getAsJsonArray(); + + List restResponseArray = new ArrayList<>(); + + for (int i = 0; i < jsonArray.size(); i++) { + JsonObject jobject = (JsonObject) jsonArray.get(i); + String header = jobject.get(restResponseHeader).toString(); + header = header.replace("\"", ""); + restResponseArray.add(header); + } + + return restResponseArray; + + } + + protected boolean isAllResourcesNotAbstract(RestResponse restResponse) { + JsonElement jelement = new JsonParser().parse(restResponse.getResponse()); + JsonArray jsonArray = jelement.getAsJsonArray(); + + for (int i = 0; i < jsonArray.size(); i++) { + JsonObject jobject = (JsonObject) jsonArray.get(i); + + if (jobject.get("abstract").getAsBoolean()) { + return false; + } + + } + return true; + + } + + protected boolean isEmptyList(RestResponse restResponse) { + JsonElement jelement = new JsonParser().parse(restResponse.getResponse()); + JsonArray jsonArray = jelement.getAsJsonArray(); + + if (jsonArray.size() == 0) { + return true; + } + return false; + } + + protected boolean isAllResourcesCertified(RestResponse restResponse) { + JsonElement jelement = new JsonParser().parse(restResponse.getResponse()); + JsonArray jsonArray = jelement.getAsJsonArray(); + + String certified = "CERTIFIED"; + String lifecycleState; + + for (int i = 0; i < jsonArray.size(); i++) { + JsonObject jobject = (JsonObject) jsonArray.get(i); + lifecycleState = jobject.get("lifecycleState").getAsString(); + if (!lifecycleState.equals(certified)) { + return false; + } + + } + return true; + } + + @Test(enabled = false) + public void getEmptyNonAbstractResourcesList() throws Exception { + // remove all the not abstract resources + Map originalState = ImportGenericResourceCITest.removeAllNormativeTypeResources(); + + // Get not abstract resources + RestResponse getResourceNotAbstarctResponse = getNotAbstractResources(); + // Check that received 200. + assertEquals("Check response code after get abstract resources", STATUS_CODE_GET_SUCCESS, + getResourceNotAbstarctResponse.getErrorCode().intValue()); + // Verify empty list + assertTrue("Received list is not empty", isEmptyList(getResourceNotAbstarctResponse)); + + // restore the resources + // ImportResourceCITest.restoreToOriginalState(originalState); + // import the resources + ImportGenericResourceCITest.importAllNormativeTypesResources(UserRoleEnum.ADMIN); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ResourceApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ResourceApiTest.java new file mode 100644 index 0000000000..feb7b6f42e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ResourceApiTest.java @@ -0,0 +1,372 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.apache.log4j.lf5.util.ResourceUtils; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.CatalogRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.ResourceValidationUtils; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class ResourceApiTest extends ComponentBaseTest { + + protected final String contentTypeHeaderData = "application/json"; + protected final String acceptHeaderDate = "application/json"; + + @Rule + public static TestName name = new TestName(); + + public ResourceApiTest() { + super(name, ResourceApiTest.class.getName()); + } + + // Keep + @Test + public void updateResourceMetadataSuccess() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncModifierDetails.setUserId("jh0003"); + RestResponse restResponse = createResourceForUpdate(sdncModifierDetails); + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + + Config config = Utils.getConfig(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + // set resource details + ResourceReqDetails resourceDetails = new ResourceReqDetails(); + resourceDetails.setDescription("updatedDescription"); + ArrayList resourceTags = new ArrayList(); + // Duplicate tags are allowed and should be de-duplicated by the server + // side + resourceTags.add(resourceRespJavaObject.getName()); + resourceTags.add("tag1"); + resourceTags.add("tag1"); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + resourceDetails.setTags(resourceTags); + resourceDetails.addCategoryChain(ResourceCategoryEnum.NETWORK_L2_3_ROUTERS.getCategory(), + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS.getSubCategory()); + resourceDetails.setVendorName("OracleUp"); + resourceDetails.setVendorRelease("1.5Up"); + resourceDetails.setContactId("pe1116"); + + resourceDetails.setIcon(resourceRespJavaObject.getIcon()); + resourceDetails.setName(resourceRespJavaObject.getName()); + resourceDetails.setDerivedFrom(resourceRespJavaObject.getDerivedFrom()); + + // ResourceReqDetails resourceDetails = new + // ResourceReqDetails(resourceName, description, resourceTags, category, + // derivedFrom, vendorName, vendorRelease, contactId, null); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(resourceDetails); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.UPDATE_RESOURCE_METADATA, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceRespJavaObject.getUniqueId()); + RestResponse updateResourceResponse = http.httpSendByMethod(url, "PUT", userBodyJson, headersMap); + + // resourceDetails.setResourceName(resourceRespJavaObject.getResourceName()); + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, + ResponseParser.convertResourceResponseToJavaObject(updateResourceResponse.getResponse())); + + // Delete resource + deleteResource(resourceRespJavaObject.getUniqueId(), sdncModifierDetails.getUserId()); + + } + + protected void deleteResource(String resourceUniqueId, String httpCspUserId) throws Exception { + RestResponse res = ResourceRestUtils.deleteResource(resourceUniqueId, httpCspUserId); + + // System.out.println("Delete resource was finished with response: " + + // res.getErrorCode()); + } + + protected RestResponse createResourceForUpdate(User sdncModifierDetails) throws Exception { + + ResourceReqDetails resourceDetails = getResourceObj(); + + // create resource + return ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + } + + public ResourceReqDetails getResourceObj() { + // set resource details + String resourceName = "ResourceForUpdate" + (int) (Math.random() * 100); + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + // String category = ResourceCategoriesEnum.MOBILITY.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add("tosca.nodes.Root"); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "pe1116"; + String icon = "myICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, null, + derivedFrom, vendorName, vendorRelease, contactId, icon); + resourceDetails.addCategoryChain(ResourceCategoryEnum.GENERIC_INFRASTRUCTURE.getCategory(), + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE.getSubCategory()); + return resourceDetails; + } + + // ------------------------------------------------------------------- + + protected ResourceReqDetails defineResourse_Benny(int n) { + String resourceName = "cisco" + String.valueOf(n); + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add("tag1"); + String category = ServiceCategoriesEnum.MOBILITY.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add("tosca.nodes.Root"); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "borderElement"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + return resourceDetails; + } + + @Test + public void getAllAbstractResources() throws Exception { + RestResponse abstractResources = CatalogRestUtils.getAbstractResources(); + + int status = abstractResources.getErrorCode(); + assertTrue(status == 200); + String json = abstractResources.getResponse(); + JSONArray array = (JSONArray) JSONValue.parse(json); + for (Object o : array) { + JSONObject value = (JSONObject) o; + Boolean element = (Boolean) value.get("abstract"); + assertTrue(element); + } + + } + + @Test + public void getAllNotAbstractResources() throws Exception { + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + String url = String.format(Urls.GET_ALL_NOT_ABSTRACT_RESOURCES, config.getCatalogBeHost(), + config.getCatalogBePort()); + HttpGet httpget = new HttpGet(url); + + httpget.addHeader(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + + httpget.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + + httpget.addHeader(HttpHeaderEnum.USER_ID.getValue(), + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + + // System.out.println("Executing request " + + // httpget.getRequestLine()); + CloseableHttpResponse response = httpclient.execute(httpget); + int status = response.getStatusLine().getStatusCode(); + assertTrue(status == 200); + try { + String json = EntityUtils.toString(response.getEntity()); + JSONArray array = (JSONArray) JSONValue.parse(json); + for (Object o : array) { + JSONObject value = (JSONObject) o; + Boolean element = (Boolean) value.get("abstract"); + assertTrue(!element); + } + + } finally { + response.close(); + } + } finally { + httpclient.close(); + } + } + + @Test + public void updateResourceMetadata_methodNotAllowed() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + Config config = Utils.getConfig(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + // set resource details + String resourceName = "ResForUpdate"; + String description = "updatedDescription"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add("tag1"); + resourceTags.add("tag2"); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add("tosca.nodes.root"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + String vendorName = "OracleUp"; + String vendorRelease = "1.5Up"; + String contactId = "pe1117"; + String icon = "myICON.jpgUp"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(resourceDetails); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.UPDATE_RESOURCE_METADATA, config.getCatalogBeHost(), config.getCatalogBePort(), + "NotExistsId"); + + RestResponse updateResourceResponse = http.httpSendByMethod(url, "POST", userBodyJson, headersMap); + + assertNotNull("Check error code exists in response after wrong update resource", + updateResourceResponse.getErrorCode()); + assertEquals("Check error code after update resource", 405, updateResourceResponse.getErrorCode().intValue()); + } + + @Test + public void validateResourceNameTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncModifierDetails.setUserId("jh0003"); + + ResourceReqDetails resourceDetails = getResourceObj(); + + // create resource + RestResponse restResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + Resource resourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + CloseableHttpClient httpclient = HttpClients.createDefault(); + try { + + // check invalid + String url = String.format(Urls.VALIDATE_RESOURCE_NAME, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetails.getName()); + + HttpGet httpget = new HttpGet(url); + + httpget.addHeader(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + + httpget.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + + httpget.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + // System.out.println("Executing request " + + // httpget.getRequestLine()); + CloseableHttpResponse response = httpclient.execute(httpget); + int status = response.getStatusLine().getStatusCode(); + assertTrue(status == 200); + try { + String json = EntityUtils.toString(response.getEntity()); + JSONObject object = (JSONObject) JSONValue.parse(json); + Boolean element = (Boolean) object.get("isValid"); + assertTrue(!element); + + } finally { + response.close(); + } + // check valid + url = String.format(Urls.VALIDATE_RESOURCE_NAME, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceDetails.getName() + "temp"); + + httpget = new HttpGet(url); + + httpget.addHeader(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + + httpget.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + + httpget.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + // System.out.println("Executing request " + + // httpget.getRequestLine()); + response = httpclient.execute(httpget); + status = response.getStatusLine().getStatusCode(); + assertTrue(status == 200); + try { + String json = EntityUtils.toString(response.getEntity()); + JSONObject object = (JSONObject) JSONValue.parse(json); + Boolean element = (Boolean) object.get("isValid"); + assertTrue(element); + + } finally { + response.close(); + } + } finally { + httpclient.close(); + } + + // Delete resource + ResourceRestUtils.deleteResource(resourceDetails, sdncModifierDetails, "0.1"); + + } + + // ------------------------------------------------------------------- + // //Benny Tal + // @Test + // public void createResource_Benny() throws Exception { + // for (int i = 0; i < 100; i++) { + // ResourceReqDetails resourceDetails = defineResourse_Benny(i); + // + // ResourceRestUtils.createResource(resourceDetails, + // UserUtils.getDesignerDetails()); + // // resourceUtils.deleteResource(resourceDetails, + // UserUtils.getDesignerDetails(), "0.1"); + // } + // } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/SampleDataProvider.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/SampleDataProvider.java new file mode 100644 index 0000000000..f4a4fa108a --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/SampleDataProvider.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import java.io.IOException; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.testng.ITestContext; +import org.testng.annotations.DataProvider; + +public class SampleDataProvider { + + @DataProvider + public static Object[][] getResourceByType(ITestContext context) throws IOException, Exception { + return new Object[][] { + { AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true) }, + { AtomicOperationUtils.createResourceByType(ResourceTypeEnum.CP, UserRoleEnum.DESIGNER, true) }, + { AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VL, UserRoleEnum.DESIGNER, true) } }; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/SimultaneousApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/SimultaneousApiTest.java new file mode 100644 index 0000000000..3002523ccb --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/SimultaneousApiTest.java @@ -0,0 +1,124 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.testng.annotations.Test; + +public class SimultaneousApiTest extends ComponentBaseTest { + + protected static ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + + @Rule + public static TestName name = new TestName(); + + static String httpCspUserId = "km2000"; + static String userFirstName = "Kot"; + static String userLastName = "Matroskin"; + static String email = "km2000@intl.sdc.com"; + static String role = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN).getRole(); + + public SimultaneousApiTest() { + super(name, SimultaneousApiTest.class.getName()); + + } + + public static class WorkerThread implements Runnable { + CountDownLatch countDownLatch; + int threadIndex; + + public WorkerThread(int threadIndex, CountDownLatch countDownLatch) { + this.threadIndex = threadIndex; + this.countDownLatch = countDownLatch; + } + + @Override + public void run() { + System.out.println("**** Thread started " + threadIndex); + try { + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + String id = ResponseParser.getUniqueIdFromResponse(createResource); + // System.out.println("**** Thread " + threadIndex + " create + // resource status " + createResource.getErrorCode() + " id = " + // + id + " error " + createResource.getResponse()); + // assertEquals("**** create resource: " + + // createResource.getErrorCode() + " thread " + threadIndex, + // 201, status); + } catch (Exception e) { + // System.out.println("**** Thread " + threadIndex + " exception + // " + e); + } + countDownLatch.countDown(); + // System.out.println("**** Thread finished " + threadIndex); + + } + + // public void run_() { + // System.out.println("**** Thread started " + threadIndex); + // try { + // UserUtils userUtils = new UserUtils(); + // User userDetails = new User(userFirstName, userLastName, + // httpCspUserId, email, role , 0L); + // RestResponse response = + // userUtils.createUserTowardsCatalogBe(userDetails, + // userUtils.getUserDetailesAdmin()); + // System.out.println("**** Thread " + threadIndex + " create resource + // status " + response.getErrorCode() + " response " + + // response.getResponse()); + //// assertEquals("**** create resource: " + + // createResource.getErrorCode() + " thread " + threadIndex, 201, + // status); + // } catch (Exception e) { + // System.out.println("**** Thread " + threadIndex + " exception " + e); + // } + // countDownLatch.countDown(); + // System.out.println("**** Thread finished " + threadIndex); + // + // } + } + + @Test + public void create2Resources() throws InterruptedException { + int threadCount = 5; + CountDownLatch countDownLatch = new CountDownLatch(threadCount); + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + for (int i = 0; i < threadCount; i++) { + Runnable worker = new WorkerThread(i + 1, countDownLatch); + executor.execute(worker); + } + countDownLatch.await(); + // System.out.println(" finished "); + + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/UpdateResourceMetadataTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/UpdateResourceMetadataTest.java new file mode 100644 index 0000000000..9d519c8b33 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/UpdateResourceMetadataTest.java @@ -0,0 +1,2650 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ResourceValidationUtils; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class UpdateResourceMetadataTest extends ComponentBaseTest { + private static Logger logger = LoggerFactory.getLogger(UpdateResourceMetadataTest.class.getName()); + protected List Empty_List = new ArrayList(); + protected String extendedChars; + + protected final String contentTypeHeaderData = "application/json"; + protected final String acceptHeaderDate = "application/json"; + protected final String CHARSET_ISO_8859 = "charset=ISO-8859-1"; + + public static TestName name = new TestName(); + protected User sdncModifierDetails; + protected ResourceReqDetails resourceDetails; + + public UpdateResourceMetadataTest() { + super(name, UpdateResourceMetadataTest.class.getName()); + + } + + public String extendedCharsStringBuilder() throws Exception { + char[] extendedCharsArray = new char[128]; + char ch = 128; + for (int i = 0; i < extendedCharsArray.length - 1; i++) { + extendedCharsArray[i] = ch; + ch++; + } + extendedChars = new String(extendedCharsArray); + return extendedChars; + + } + + @BeforeMethod + public void setup() throws Exception { + sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + resourceDetails = defineResourse(); + + } + + // Keep + @Test + public void UpdateDerivedFromSuccess() throws Exception { + + String oldDerivedFromName = NormativeTypesEnum.ROOT.getNormativeName(); + String newDerivedFromName = NormativeTypesEnum.SOFTWARE_COMPONENT.getNormativeName(); + + // Getting both derived from resources for validation + /* + * RestResponse resourceByNameAndVersion = + * resourceUtils.getResourceByNameAndVersion(sdncModifierDetails, + * oldDerivedFromName, "1.0"); + * assertEquals("Check response code after get database normative", 200, + * resourceByNameAndVersion.getErrorCode().intValue()); Resource + * databaseNormative = + * resourceUtils.parseResourceResp(resourceByNameAndVersion); + * + * resourceByNameAndVersion = + * resourceUtils.getResourceByNameAndVersion(sdncModifierDetails, + * newDerivedFromName, "1.0"); + * assertEquals("Check response code after get database normative", 200, + * resourceByNameAndVersion.getErrorCode().intValue()); Resource + * lbNormative = + * resourceUtils.parseResourceResp(resourceByNameAndVersion); + */ + + // Derived from set to Database + List derivedFrom = new ArrayList<>(); + derivedFrom.add(oldDerivedFromName); + resourceDetails.setDerivedFrom(derivedFrom); + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + AssertJUnit.assertEquals("Check response code after create resource", 201, + restResponse.getErrorCode().intValue()); + Resource currentResource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + + derivedFrom.clear(); + derivedFrom.add(newDerivedFromName); + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, currentResource.getUniqueId(), ""); + AssertJUnit.assertEquals("Check response code after create resource", 200, + updatedRestResponse.getErrorCode().intValue()); + + } + + protected ResourceReqDetails defineUpdateResourceWithNonUpdatableFields(Resource resourceBeforeUpdate) { + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceBeforeUpdate.getName()); + + updatedResourceDetails.setVersion("mumu"); + updatedResourceDetails.setIsAbstract(true); + updatedResourceDetails.setIsHighestVersion(true); + updatedResourceDetails.setCreatorUserId("df4444"); + updatedResourceDetails.setCreatorFullName("John Doe"); + updatedResourceDetails.setLastUpdaterUserId("gf5646"); + updatedResourceDetails.setLastUpdaterFullName("Viktor Tzoy"); + updatedResourceDetails.setCreationDate(new Long(4444)); + updatedResourceDetails.setLastUpdateDate(new Long("534535")); + updatedResourceDetails.setLifecycleState(LifecycleStateEnum.READY_FOR_CERTIFICATION); + updatedResourceDetails.setCost("6.1"); + updatedResourceDetails.setLicenseType("Installation"); + updatedResourceDetails.setUUID("dfsfsdf"); + return updatedResourceDetails; + } + + public void UpdateResourceNotFoundTest() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + String resourceName = "cisco4"; + // update resource + String description = "updatedDescription"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.MOBILITY.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "newOracle"; + String vendorRelease = "2.5"; + String contactId = "jh0003"; + String icon = "myICON"; + + ResourceReqDetails updatedResourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, + category, derivedFrom, vendorName, vendorRelease, contactId, icon); + updatedResourceDetails.setUniqueId("dummyId"); + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, "0.1"); + + // validate response + AssertJUnit.assertNotNull("check response object is not null after update resource", updatedRestResponse); + AssertJUnit.assertNotNull("check error code exists in response after update resource", + updatedRestResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after update resource", 404, + updatedRestResponse.getErrorCode().intValue()); + // String resourceId = + // UniqueIdBuilder.buildResourceUniqueId(resourceName, "0.1"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_NOT_FOUND.name(), Arrays.asList("dummyId"), + updatedRestResponse.getResponse()); + + resourceName = ""; + // resourceId = UniqueIdBuilder.buildResourceUniqueId(resourceName, + // "0.1"); + updatedResourceDetails = defineUpdatedResourse(resourceName); + updatedResourceDetails.setUniqueId("dummyId"); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncModifierDetails, + "0.1"); + AssertJUnit.assertNotNull("check response object is not null after update resource", updatedRestResponse); + AssertJUnit.assertNotNull("check error code exists in response after update resource", + updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_NOT_FOUND.name(), Arrays.asList("dummyId"), + updatedRestResponse.getResponse()); + + } + + public char[] getInValidChars() throws Exception { + + char[] extendedCharsArray = new char[59]; + char ch = 1; + for (int i = 0; i < 44; i++) { + extendedCharsArray[i] = ch; + ch++; + } + ch = 58; + for (int i = 44; i < 51; i++) { + extendedCharsArray[i] = ch; + ch++; + } + ch = 91; + for (int i = 51; i < 55; i++) { + extendedCharsArray[i] = ch; + ch++; + } + ch = 123; + for (int i = 55; i < 59; i++) { + extendedCharsArray[i] = ch; + ch++; + } + return extendedCharsArray; + } + + public char[] getTagInValidFormatChars() throws Exception { + // Tag format is the same as defined for "Resource Name" : + // Allowed characters: Alphanumeric (a-zA-Z0-9), space (' '), underscore + // ('_'), dash ('-'), dot ('.') + char[] notValidCharsArray = new char[30]; + char ch = 33; + for (int i = 0; i < 12; i++) { + notValidCharsArray[i] = ch; + ch++; + } + notValidCharsArray[13] = 47; + ch = 58; + for (int i = 14; i < 21; i++) { + notValidCharsArray[i] = ch; + ch++; + } + ch = 91; + for (int i = 21; i < 24; i++) { + notValidCharsArray[i] = ch; + ch++; + } + notValidCharsArray[24] = 96; + ch = 123; + for (int i = 25; i < 30; i++) { + notValidCharsArray[i] = ch; + ch++; + } + return notValidCharsArray; + } + + public void Validation_UpdateWithIncompleteJsonBodyTest() throws Exception { + // init ADMIN user + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // define and create resource + ResourceReqDetails resourceDetails = defineResourse(); + ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, resourceDetails.getName(), "0.1"); + ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, resourceDetails.getName(), "1.0"); + ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, resourceDetails.getName(), "1.1"); + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceId = resourceDetails.getUniqueId(); + resourceDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(restResponse)); + + // build Json Object + JSONObject jsonObject = JsonObjectBuilder(resourceDetails); + + List resource = new ArrayList<>(); + resource.add("Resource"); + + // remove Description + UpdateAndValidateWithIncompletedJsonBody(sdncModifierDetails, jsonObject, resourceId, "description", + ActionStatus.COMPONENT_MISSING_DESCRIPTION.name(), resource); + // remove Tags + UpdateAndValidateWithIncompletedJsonBody(sdncModifierDetails, jsonObject, resourceId, "tags", + ActionStatus.COMPONENT_MISSING_TAGS.name(), Empty_List); + // remove Category + UpdateAndValidateWithIncompletedJsonBody(sdncModifierDetails, jsonObject, resourceId, "category", + ActionStatus.COMPONENT_MISSING_CATEGORY.name(), resource); + // remove VendorName + UpdateAndValidateWithIncompletedJsonBody(sdncModifierDetails, jsonObject, resourceId, "vendorName", + ActionStatus.MISSING_VENDOR_NAME.name(), Empty_List); + // remove VendorRelease + UpdateAndValidateWithIncompletedJsonBody(sdncModifierDetails, jsonObject, resourceId, "vendorRelease", + ActionStatus.MISSING_VENDOR_RELEASE.name(), Empty_List); + // remove AT&T Contact + UpdateAndValidateWithIncompletedJsonBody(sdncModifierDetails, jsonObject, resourceId, "contactId", + ActionStatus.COMPONENT_MISSING_CONTACT.name(), resource); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, "0.1"); + // validate response + AssertJUnit.assertNotNull("check response object is not null after get resource", getRestResponse); + AssertJUnit.assertNotNull("check error code exists in response after get resource", + getRestResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after update resource", 200, + getRestResponse.getErrorCode().intValue()); + + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, resourceDetails.getName(), "0.1"); + ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, resourceDetails.getName(), "1.0"); + ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, resourceDetails.getName(), "1.1"); + } + + // End of validation tests + // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + protected ResourceReqDetails defineUpdatedResourse(String resourceName) { + String description = "updatedDescription"; + ArrayList resourceTags = new ArrayList(); + // Duplicate tags are allowed and should be de-duplicated by server side + resourceTags.add(resourceName); + resourceTags.add("tag1"); + resourceTags.add("tag1"); + resourceTags.add("tag2"); + resourceTags.add("tag2"); + String category = ServiceCategoriesEnum.VOIP.getValue(); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName()); + String vendorName = "updatedOracle"; + String vendorRelease = "3.5"; + String contactId = "jh0001"; + String icon = "myUpdatedICON"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, category, + derivedFrom, vendorName, vendorRelease, contactId, icon); + resourceDetails.addCategoryChain(ResourceCategoryEnum.GENERIC_INFRASTRUCTURE.getCategory(), + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE.getSubCategory()); + + return resourceDetails; + } + + protected ResourceReqDetails defineResourse() { + String resourceName = "cisco4"; + String description = "description"; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(NormativeTypesEnum.ROOT.getNormativeName());// "tosca.nodes.Root"); + String vendorName = "Oracle"; + String vendorRelease = "1.5"; + String contactId = "jh0003"; + String icon = "objectStorage"; + + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, null, + derivedFrom, vendorName, vendorRelease, contactId, icon); + resourceDetails.addCategoryChain(ResourceCategoryEnum.GENERIC_INFRASTRUCTURE.getCategory(), + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE.getSubCategory()); + + return resourceDetails; + } + + protected RestResponse createResource(User sdncModifierDetails, ResourceReqDetails resourceDetails) + throws Exception { + // clean ES DB + DbUtils.cleanAllAudits(); + + // create resource + RestResponse restResponse = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + + // validate response + AssertJUnit.assertNotNull("check response object is not null after create resource", restResponse); + AssertJUnit.assertNotNull("check error code exists in response after create resource", + restResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create resource", 201, + restResponse.getErrorCode().intValue()); + + return restResponse; + } + + protected RestResponse TryUpdateByAnotherVerb(ResourceReqDetails updatedResourceDetails, User sdncModifierDetails, + String uri) throws Exception { + // delete resource + Config config; + RestResponse ResourceResponse; + try { + config = Utils.getConfig(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.UPDATE_RESOURCE_METADATA, config.getCatalogBeHost(), + config.getCatalogBePort(), updatedResourceDetails.getName() + ".0.1"); + + if (uri == "GET") { + ResourceResponse = http.httpSendGet(url, headersMap); + } else if (uri == "POST") { + Gson gson = new Gson(); + String userBodyJson = gson.toJson(updatedResourceDetails); + ResourceResponse = http.httpSendPost(url, userBodyJson, headersMap); + } else if (uri == "DELETE") { + ResourceResponse = http.httpSendDelete(url, headersMap); + } else + return null; + + return ResourceResponse; + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return null; + + } + + protected JSONObject JsonObjectBuilder(ResourceReqDetails resourceDetails) throws JSONException { + // json object: resourceName and icon are must + JSONObject jObject = new JSONObject(); + + List tagsList = Arrays.asList(resourceDetails.getName()); + List derivedFromList = Arrays.asList("[tosca.nodes.Root]"); + + jObject.put("name", resourceDetails.getName()); + jObject.put("description", "updatedDescription"); + jObject.put("tags", tagsList); + jObject.put("category", ServiceCategoriesEnum.VOIP.getValue()); + jObject.put("derivedFrom", derivedFromList); + jObject.put("vendorName", "newOracle"); + jObject.put("vendorRelease", "1.5"); + jObject.put("contactId", "jh0003"); + jObject.put("icon", resourceDetails.getIcon()); + + return jObject; + } + + protected JSONObject RemoveFromJsonObject(JSONObject jObject, String removedPropery) { + jObject.remove(removedPropery); + + return jObject; + } + + // purpose: function for controlling json body fields and validating + // response + protected void UpdateAndValidateWithIncompletedJsonBody(User sdncModifierDetails, JSONObject jsonObject, + String resourceId, String removedField, String errorMessage, List variables) throws Exception { + + JSONObject jObject = new JSONObject(jsonObject, JSONObject.getNames(jsonObject)); + // remove description from jsonObject + jObject = RemoveFromJsonObject(jObject, removedField); + // update with incomplete body. + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(jObject.toString(), + sdncModifierDetails, resourceId); + // validate response + AssertJUnit.assertNotNull("check response object is not null after update resource", updatedRestResponse); + AssertJUnit.assertNotNull("check error code exists in response after update resource", + updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(errorMessage, variables, updatedRestResponse.getResponse()); + + } + + // purpose: function for validating error response + protected void UpdateAndValidate(User sdncModifierDetails, ResourceReqDetails resourceDetails, + String recievedMessage, List variables) throws Exception { + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, "0.1"); + // validate response + AssertJUnit.assertNotNull("check response object is not null after update resource", updatedRestResponse); + AssertJUnit.assertNotNull("check error code exists in response after update resource", + updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(recievedMessage, variables, updatedRestResponse.getResponse()); + + } + + protected void parseResponseAndValidateNonUpdatable(ResourceReqDetails resourceDetails, RestResponse restResponse) + throws Exception { + // parse response to javaObject + Resource updatedResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + AssertJUnit.assertTrue( + !resourceDetails.getIsHighestVersion().equals(updatedResourceRespJavaObject.isHighestVersion())); + AssertJUnit.assertTrue(!resourceDetails.getVersion().equals(updatedResourceRespJavaObject.getName())); + AssertJUnit.assertTrue(!resourceDetails.getIsAbstract().equals(updatedResourceRespJavaObject.isAbstract())); + AssertJUnit.assertTrue( + !resourceDetails.getCreatorUserId().equals(updatedResourceRespJavaObject.getCreatorUserId())); + AssertJUnit.assertTrue( + !resourceDetails.getCreatorFullName().equals(updatedResourceRespJavaObject.getCreatorFullName())); + AssertJUnit.assertTrue( + !resourceDetails.getLastUpdateDate().equals(updatedResourceRespJavaObject.getLastUpdateDate())); + AssertJUnit + .assertTrue(!resourceDetails.getCreationDate().equals(updatedResourceRespJavaObject.getCreationDate())); + AssertJUnit.assertTrue( + !resourceDetails.getLastUpdaterUserId().equals(updatedResourceRespJavaObject.getLastUpdaterUserId())); + AssertJUnit.assertTrue(!resourceDetails.getLastUpdaterFullName() + .equals(updatedResourceRespJavaObject.getLastUpdaterFullName())); + AssertJUnit.assertTrue( + !resourceDetails.getLifecycleState().equals(updatedResourceRespJavaObject.getLifecycleState())); + AssertJUnit.assertTrue(!resourceDetails.getCost().equals(updatedResourceRespJavaObject.getCost())); + AssertJUnit + .assertTrue(!resourceDetails.getLicenseType().equals(updatedResourceRespJavaObject.getLicenseType())); + AssertJUnit.assertTrue(!resourceDetails.getUUID().equals(updatedResourceRespJavaObject.getUUID())); + + } + + protected void parseResponseAndValidate(ResourceReqDetails ResourceDetails, RestResponse restResponse) + throws Exception { + // parse response to javaObject + Resource updatedResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + // validate request vs response + ResourceValidationUtils.validateResourceReqVsResp(ResourceDetails, updatedResourceRespJavaObject); + } + + public ExpectedResourceAuditJavaObject constructFieldsForAuditValidation(ResourceReqDetails resourceDetails, + String resourceVersion) { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + + expectedResourceAuditJavaObject.setAction("Checkout"); + expectedResourceAuditJavaObject.setModifierUid(UserRoleEnum.ADMIN.getUserId()); + expectedResourceAuditJavaObject.setModifierName(UserRoleEnum.ADMIN.getUserName()); + expectedResourceAuditJavaObject.setStatus("200.0"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setResourceName(resourceDetails.getName().toLowerCase()); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setPrevVersion(String.valueOf(Float.parseFloat(resourceVersion) - 0.1f)); + expectedResourceAuditJavaObject.setCurrVersion(resourceVersion); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + + return expectedResourceAuditJavaObject; + + } + + public enum FieldToValidate { + contactId, Tags, VendorName, VendorRelease, Description + } + + @Test + public void UpdateBy_postTest() throws Exception { + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // update resource - without changing resourceName + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + + RestResponse updatedRestResponse = TryUpdateByAnotherVerb(updatedResourceDetails, sdncModifierDetails, "POST"); + + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), Empty_List, + updatedRestResponse.getResponse()); + + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertNotNull("check response object is not null after update resource", getRestResponse); + parseResponseAndValidate(resourceDetails, getRestResponse); + + } + + @Test + public void UpdateBy_getTest() throws Exception { + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // update resource - without changing resourceName + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + RestResponse updatedRestResponse = TryUpdateByAnotherVerb(updatedResourceDetails, sdncModifierDetails, "GET"); + + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), Empty_List, + updatedRestResponse.getResponse()); + + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertNotNull("check response object is not null after update resource", getRestResponse); + parseResponseAndValidate(resourceDetails, getRestResponse); + + } + + @Test + public void UpdateBy_deleteTest() throws Exception { + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // update resource - without changing resourceName + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + RestResponse updatedRestResponse = TryUpdateByAnotherVerb(updatedResourceDetails, sdncModifierDetails, + "DELETE"); + + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), Empty_List, + updatedRestResponse.getResponse()); + + RestResponse getRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId(), ""); + assertNotNull("check response object is not null after update resource", getRestResponse); + parseResponseAndValidate(resourceDetails, getRestResponse); + + } + + // TODO DE + // @Ignore("") + @Test + public void UpdateWithInvaldJsonBodyTest() throws Exception { + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + resourceDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(restResponse)); + String resourceId = resourceDetails.getUniqueId(); + + // update Descirption value + String description = "updatedDescription"; + + // send update with incompleted json, only description string + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(description, sdncModifierDetails, + resourceId); + + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("check error code after update resource", 400, updatedRestResponse.getErrorCode().intValue()); + + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertNotNull("check response object is not null after update resource", getRestResponse); + parseResponseAndValidate(resourceDetails, getRestResponse); + + } + + // @Test + // public void UpdateResourceModifierNotOwnerStateTest() throws Exception { + // + // + // RestResponse restResponse = createResource(sdncModifierDetails, + // resourceDetails); + // String resourceName = resourceDetails.getName(); + // + // // new user parameters + // String userFirstName = "Kot"; + // String userLastName = "Matroskin"; + // String role = "ADMIN"; + // User sdncUserDetails = new User(userFirstName, userLastName, + // httpCspUserId, email, role,null); + // RestResponse deleteUserResponse = userUtils.deleteUser(sdncUserDetails, + // ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)); + // + // RestResponse createUserResponse = UserUtils.createUser(sdncUserDetails, + // ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)); + // + // User updatedSdncModifierDetails = new User(userFirstName, userLastName, + // httpCspUserId, email,role,null); + // ResourceReqDetails updatedResourceDetails = + // defineUpdatedResourse(resourceName); + // RestResponse updatedRestResponse = + // ResourceRestUtils.updateResource(updatedResourceDetails, + // updatedSdncModifierDetails, resourceDetails.getUniqueId(), ""); + // + // // validate response + // assertNotNull("check response object is not null after update resource", + // updatedRestResponse); + // assertNotNull("check error code exists in response after update + // resource", updatedRestResponse.getErrorCode()); + // ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), + // Empty_List, updatedRestResponse.getResponse()); + // + // RestResponse getRestResponse = + // ResourceRestUtils.getResource(sdncModifierDetails, + // resourceDetails.getUniqueId()); + // assertNotNull("check response object is not null after update resource", + // getRestResponse); + // parseResponseAndValidate(resourceDetails, getRestResponse); + // + // + // } + + @Test + public void UpdateResourceNameSensitiveTest() throws Exception { + User sdncModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + String resourceBaseVersion = "0.1"; + String resourceName = "Ab"; + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + // Delete resources + RestResponse response = null; + response = ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, + updatedResourceDetails.getName(), "0.1"); + BaseRestUtils.checkDeleteResponse(response); + response = ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, + updatedResourceDetails.getName(), "0.2"); + BaseRestUtils.checkDeleteResponse(response); + + RestResponse restResponse = createResource(sdncModifierDetails, updatedResourceDetails); + assertEquals("create resource failed", 201, restResponse.getErrorCode().intValue()); + + // check-in Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(updatedResourceDetails, + sdncModifierDetails, resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + // String resourceCertifyVersion = "0.1"; + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(updatedResourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + updatedResourceDetails.setName("ABC_-bt.aT"); + ArrayList resourceTag = new ArrayList(); + resourceTag.add(0, "ABC_-bt.aT"); + updatedResourceDetails.setTags(resourceTag); + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, updatedResourceDetails.getUniqueId(), ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(updatedResourceDetails, updatedRestResponse); + + // Delete resources + response = ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, + updatedResourceDetails.getName(), "0.1"); + BaseRestUtils.checkDeleteResponse(response); + response = ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, + updatedResourceDetails.getName(), "0.2"); + BaseRestUtils.checkDeleteResponse(response); + + } + + @Test + public void UpdateIcon_InegativeFlow() throws Exception { + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + List resourceList = new ArrayList(); + resourceList.add(0, "Resource"); + // check InValid Characters + char[] notValidCharsArray = new char[59]; + notValidCharsArray = getInValidChars(); + // update metadata details + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + RestResponse updatedRestResponse; + + for (int i = 0; i < notValidCharsArray.length; i++) { + // change icon of metadata + updatedResourceDetails.setIcon("MyIcon" + notValidCharsArray[i]); + // PUT request + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId(), ""); + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", + updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_ICON.name(), resourceList, + updatedRestResponse.getResponse()); + assertEquals("Check response code after updating resource icon", 400, + updatedRestResponse.getErrorCode().intValue()); + assertEquals("Check response code after updating resource icon", "Bad Request", + updatedRestResponse.getResponseMessage().toString()); + + } + + // empty icon + String updateIcon = ""; + updatedResourceDetails.setIcon(updateIcon); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId(), ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_ICON.name(), resourceList, + updatedRestResponse.getResponse()); + + // Icon length more then 25 characters + resourceList.add(1, "25"); + updatedResourceDetails.setIcon("1234567890_-qwertyuiopASDNNN"); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId(), ""); + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_ICON_EXCEEDS_LIMIT.name(), resourceList, + updatedRestResponse.getResponse()); + assertEquals("Check response code after create resource", 400, updatedRestResponse.getErrorCode().intValue()); + assertEquals("Check response code after updating resource icon", "Bad Request", + updatedRestResponse.getResponseMessage().toString()); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + } + + @Test + public void UpdateResource_NoTagsEqualToResourceName() throws Exception { + + User adminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + String resourceBaseVersion = "0.1"; + + // create resource + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + ResourceReqDetails updatedResourceDetails = defineResourse(); + updatedResourceDetails.setName("updatedResourceName"); + List tags = updatedResourceDetails.getTags(); + + for (Iterator iter = tags.listIterator(); iter.hasNext();) { + String a = iter.next(); + if (a.equals("updatedResourceName")) { + iter.remove(); + } + } + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + // validate response + List resourceList = new ArrayList(); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_TAGS_NO_COMP_NAME.name(), + resourceList, updatedRestResponse.getResponse()); + assertEquals("Check response code after updating resource icon", 400, + updatedRestResponse.getErrorCode().intValue()); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + } + + @Test + public void UpdateResourceName_negativeFlow() throws Exception { + // The validation are done in Tag's validation + User sdncAdminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + RestResponse updatedRestResponse; + RestResponse restResponse = createResource(sdncAdminModifierDetails, resourceDetails); + assertEquals("create resource failed", 201, restResponse.getErrorCode().intValue()); + String uniqueId = resourceDetails.getUniqueId(); + String resourceName = resourceDetails.getName(); + // check InValid Characters + char[] notValidCharsArray = new char[59]; + notValidCharsArray = getInValidChars(); + ArrayList resource_Name = new ArrayList(); + List resourceList = new ArrayList(); + + ArrayList resourceTags = new ArrayList(); + resourceList.add(0, "Resource"); + + // update metadata details + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + for (int i = 0; i < notValidCharsArray.length; i++, resource_Name.clear()) { + if (i != 1 && i != 46 + && /* + * i != 8 && i != 9 && i != 10 && i != 11 && i != 12 && + */ i != 31) // space ("") and dot(.) + { + // change resourceName parameter + updatedResourceDetails.setName("UpdatedResourceName" + notValidCharsArray[i]); + resource_Name.add("UpdatedResourceName" + notValidCharsArray[i]); + updatedResourceDetails.setTags(resource_Name); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncAdminModifierDetails, uniqueId, ""); + // validate response + // ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_TAG.name(), + // Empty_List, updatedRestResponse.getResponse()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_COMPONENT_NAME.name(), resourceList, + updatedRestResponse.getResponse()); + + } + } + + // resourceName length more then 50 characters + // Duplicate tags are allowed and should be de-duplicated by server side + resource_Name.add(resourceName); + resource_Name.add("tag1"); + resource_Name.add("tag1"); + resource_Name.add("tag2"); + resource_Name.add("tag2"); + + resourceList.add(1, "1024"); + // updatedResourceDetails.setName("123456789012345678901234567890123456789012345678901"); + updatedResourceDetails.setName(new String(new char[1025]).replace("\0", "a")); + // resource_Name.add("123456789012345678901234567890123456789012345678901"); + updatedResourceDetails.setTags(resource_Name); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncAdminModifierDetails, + uniqueId, ""); + // validate response + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_NAME_EXCEEDS_LIMIT.name(), resourceList, + updatedRestResponse.getResponse()); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncAdminModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + // delete resource + RestResponse response = ResourceRestUtils.deleteResourceByNameAndVersion(sdncAdminModifierDetails, + updatedResourceDetails.getName(), "0.1"); + BaseRestUtils.checkDeleteResponse(response); + } + + @Test + public void UpdateResourceInformation_NotCheckedOut() throws Exception { + + String resourceBaseVersion = "0.1"; + List resourceList = new ArrayList(); + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // CheckIn Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); // NOT_CERTIFIED_CHECKIN + assertNotNull("check response object is not null after checkout resource", checkoutResource); + assertNotNull("check error code exists in response after checkIn resource", checkoutResource.getErrorCode()); + assertEquals("Check response code after checkin resource", 200, checkoutResource.getErrorCode().intValue()); + + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), resourceList, + updatedRestResponse.getResponse()); + assertEquals("Check response code after updating resource icon", 409, + updatedRestResponse.getErrorCode().intValue()); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + } + + @Test + public void UpdateResourceInformation_resourceVersion_11() throws Exception { + + User adminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + String resourceBaseVersion = "0.1"; + + // create resource + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // restResponse); + + // Certify Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + String resourceCertifyVersion = "1.0"; + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + // validate response + List resourceList = new ArrayList(); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), resourceList, + updatedRestResponse.getResponse()); + // assertEquals("Check response code after updating resource icon", 409, + // updatedRestResponse.getErrorCode().intValue()); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + } + + @Test + public void UpdateResourceInformation_resourceVersion_02() throws Exception { + + String resourceBaseVersion = "0.1"; + + // create resource + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // restResponse); + + // Certify Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + // String resourceCertifyVersion = "0.1"; + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after updating resource icon", 200, + updatedRestResponse.getErrorCode().intValue()); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(updatedResourceDetails, getResourceRespJavaObject); + + // delete resource + RestResponse response = ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, + updatedResourceDetails.getName(), "0.1"); + BaseRestUtils.checkDeleteResponse(response); + response = ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, + updatedResourceDetails.getName(), "0.2"); + BaseRestUtils.checkDeleteResponse(response); + + } + + @Test + public void UpdateResourceIcon_resourceVersion_11() throws Exception { + // Can be changed only if major version is "0". + + User adminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + String resourceBaseVersion = "0.1"; + + // create resource + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // restResponse); + + // Certify Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + String resourceCertifyVersion = "1.0"; + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceCertifyVersion, LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + // ResourceReqDetails updatedResourceDetails = + // defineUpdatedResourse(resourceName); + ResourceReqDetails updatedResourceDetails = defineResourse(); + // updatedResourceDetails.setVendorName("updatedVandorName"); + updatedResourceDetails.setIcon("updatedIcon"); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + // validate response + List resourceList = new ArrayList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_ICON_CANNOT_BE_CHANGED.name(), resourceList, + updatedRestResponse.getResponse()); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + } + + @Test + public void UpdateResourceVandorName_resourceVersion_11() throws Exception { + // Can be changed only if the major resource version is "0". + User adminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + String resourceBaseVersion = "0.1"; + + // create resource + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // restResponse); + + // Certify Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + String resourceCertifyVersion = "1.0"; + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceCertifyVersion, LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + // ResourceReqDetails updatedResourceDetails = + // defineUpdatedResourse(resourceName); + ResourceReqDetails updatedResourceDetails = defineResourse(); + + updatedResourceDetails.setVendorName("updatedVandorName"); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + // validate response + List resourceList = new ArrayList(); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_VENDOR_NAME_CANNOT_BE_CHANGED.name(), + resourceList, updatedRestResponse.getResponse()); + assertEquals("Check response code after updating resource icon", 400, + updatedRestResponse.getErrorCode().intValue()); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + } + + @Test + public void UpdateResourceName_resourceVersion_11() throws Exception { + // Can be changed only if the major resource version is "0". + User adminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + String resourceBaseVersion = "0.1"; + + // create resource + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("create resource failed", 201, restResponse.getErrorCode().intValue()); + String resourceName = resourceDetails.getName(); + + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // restResponse); + + // Certify Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + String resourceCertifyVersion = "1.0"; + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceCertifyVersion, LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + /* + * //ResourceReqDetails updatedResourceDetails = + * defineUpdatedResourse(resourceName); ResourceReqDetails + * updatedResourceDetails = defineResourse(); + * + * updatedResourceDetails.setResourceName("updatedResourceName"); + * updatedResourceDetails.setIcon("updatedResourceName"); + */ + resourceDetails.setName("updatedResourceName"); + List tagList = new ArrayList(); + tagList.add(0, "updatedResourceName"); + resourceDetails.setTags(tagList); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + // validate response + List resourceList = new ArrayList(); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_NAME_CANNOT_BE_CHANGED.name(), resourceList, + updatedRestResponse.getResponse()); + + } + + @Test + public void UpdateResourceTag_resourceVersion_11() throws Exception { + // Tag Can be updated when major version is "0". + User adminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + String resourceBaseVersion = "0.1"; + + // create resource + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // restResponse); + + // Certify Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + String resourceCertifyVersion = "1.0"; + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceCertifyVersion, LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + // ResourceReqDetails updatedResourceDetails = + // defineUpdatedResourse(resourceName); + ResourceReqDetails updatedResourceDetails = defineResourse(); + // updatedResourceDetails.setVendorName("updatedVandorName"); + + ArrayList resourceTags = new ArrayList(); + resourceTags.add("NewTag"); + resourceTags.add(resourceDetails.getName()); + + updatedResourceDetails.setTags(resourceTags); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertNotNull("check response object is not null after update resource", getRestResponse); + parseResponseAndValidate(updatedResourceDetails, getRestResponse); + + } + + @Test + public void UpdateAllowedParames_resourceVersion_11() throws Exception { + + // Tag, contactId, vendorRelease,tags And description - Can be also + // updated when major version is NOT "0". + User adminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + String resourceBaseVersion = "0.1"; + + // create resource + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // restResponse); + + // Certify Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + String resourceCertifyVersion = "1.0"; + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceCertifyVersion, LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + // ResourceReqDetails updatedResourceDetails = + // defineUpdatedResourse(resourceName); + ResourceReqDetails updatedResourceDetails = defineResourse(); + // updatedResourceDetails.setVendorName("updatedVandorName"); + + // updated allowed parameters when major resource version is NOT "0" + ArrayList resourceTags = new ArrayList(); + resourceTags.add("NewTag"); + resourceTags.add(resourceDetails.getName()); + updatedResourceDetails.setTags(resourceTags); + updatedResourceDetails.setDescription("UpdatedDescription"); + updatedResourceDetails.setVendorRelease("5.1"); + updatedResourceDetails.setContactId("bt750h"); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertNotNull("check response object is not null after update resource", getRestResponse); + parseResponseAndValidate(updatedResourceDetails, getRestResponse); + + } + + @Test + public void UpdateResourceDerivedFrom_resourceVersion_11() throws Exception { + // DerivedFrom parameter - Can be updated when major version is "0". + User adminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + String resourceBaseVersion = "0.1"; + + // create resource + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String resourceName = resourceDetails.getName(); + + // resourceUtils.addResourceMandatoryArtifacts(sdncModifierDetails, + // restResponse); + + // Certify Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, adminModifierDetails, + resourceBaseVersion, LifeCycleStatesEnum.CERTIFY); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + String resourceCertifyVersion = "1.0"; + logger.debug("Changing resource life cycle "); + checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceCertifyVersion, LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after checkout resource", 200, checkoutResource.getErrorCode().intValue()); + + // ResourceReqDetails updatedResourceDetails = + // defineUpdatedResourse(resourceName); + ResourceReqDetails updatedResourceDetails = defineResourse(); + ArrayList drivenFrom = new ArrayList(); + drivenFrom.add(0, "tosca.nodes.Container.Application"); + updatedResourceDetails.setDerivedFrom(drivenFrom); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + // validate response + List resourceList = new ArrayList(); + ResourceRestUtils.checkSuccess(updatedRestResponse); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + } + + @Test + public void UpdateResource_vendorNameValidation() throws Exception { + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + String updatedVendorName = ""; + String uniqueId = resourceDetails.getUniqueId(); + resourceDetails.setVendorName(updatedVendorName); + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, uniqueId, ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + // update resource vendorName metadata: 1 characters + updatedVendorName = " "; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + // update resource vendorName metadata: 25 characters + updatedVendorName = "Verification and validati"; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + // update resource vendorName metadata: 26 characters + updatedVendorName = "Verification and validatii"; + // set vendorName + List myList = new ArrayList(); + myList.add(0, "25"); + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.VENDOR_NAME_EXCEEDS_LIMIT.name(), myList, + updatedRestResponse.getResponse()); + + // update resource VendorRelease metadata: forbidden characters + updatedVendorName = "A1<"; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorName = "A1>"; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorName = "A1:"; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorName = "A1\""; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorName = "A1/"; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorName = "A1\\"; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorName = "A1|"; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorName = "A1?"; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorName = "A1*"; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + // update resource vendorName metadata: null + updatedVendorName = null; + // set vendorName + resourceDetails.setVendorName(updatedVendorName); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_VENDOR_NAME.name(), Empty_List, + updatedRestResponse.getResponse()); + + } + + @Test + public void UpdateResource_vendorReleaseValidation() throws Exception { + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + RestResponse updatedRestResponse; + String uniqueId = resourceDetails.getUniqueId(); + String updatedVendorRelease; + // set VendorRelease + + // update resource VendorRelease metadata: 1 characters + updatedVendorRelease = "1"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + // update resource VendorRelease metadata: 25 characters + updatedVendorRelease = "(!#1.00000000000000000000"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + // update resource VendorRelease metadata: 26 characters + updatedVendorRelease = "(!#1.000000000000000000005";// set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.VENDOR_RELEASE_EXCEEDS_LIMIT.name(), + Arrays.asList("" + ValidationUtils.VENDOR_RELEASE_MAX_LENGTH), updatedRestResponse.getResponse()); + + // UpdateAndValidate(sdncModifierDetails, resourceDetails, + // ActionStatus.VENDOR_RELEASE_EXCEEDS_LIMIT.name(), + // Arrays.asList(""+ValidationUtils.VENDOR_RELEASE_MAX_LENGTH)); + + // update resource VendorRelease metadata: forbidden characters + updatedVendorRelease = "A1<"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorRelease = "A1>"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorRelease = "A1:"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorRelease = "A1\""; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorRelease = "A1/"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorRelease = "A1\\"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorRelease = "A1|"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorRelease = "A1?"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + updatedVendorRelease = "A1*"; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + // update resource VendorRelease metadata: null + updatedVendorRelease = null; + // set VendorRelease + resourceDetails.setVendorRelease(updatedVendorRelease); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_VENDOR_RELEASE.name(), Empty_List, + updatedRestResponse.getResponse()); + + } + + @Test + public void UpdateResource_contactIdValidation() throws Exception { // [a-zA-Z]{2}[0-9]{3}[a-zA-Z0-9]{1} + // (6 + // characters + // now, + // may + // be + // expanded + // up + // to + // 8 + // characters + // in + // the + // future). + // Convert + // Upper + // case + // character + // to + // lower + // case + RestResponse updatedRestResponse; + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + String uniqueId = resourceDetails.getUniqueId(); + + List myList = new ArrayList(); + myList.add(0, "Resource"); + String updatedcontactId = ""; + resourceDetails.setContactId(updatedcontactId); + + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "ab12345"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = " "; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "ab 50h"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "ab123c"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + updatedcontactId = "cd789E"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + + resourceDetails.setContactId(updatedcontactId.toLowerCase()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + updatedcontactId = "ef4567"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + updatedcontactId = "AA012A"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + + resourceDetails.setContactId(updatedcontactId.toLowerCase()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + updatedcontactId = "CD012c"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + + resourceDetails.setContactId(updatedcontactId.toLowerCase()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + updatedcontactId = "EF0123"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + + resourceDetails.setContactId(updatedcontactId.toLowerCase()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + ////////////////////////////// **************////////////////////////////// + List resource = Arrays.asList("Resource"); + updatedcontactId = "01345a"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "0y000B"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "Y1000b"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "abxyzC"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "cdXYZc"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "efXY1D"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "EFabcD"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "EFABCD"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "EFABC1"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "efui1D"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "efui1!"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "ef555!"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = ",f555"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + updatedcontactId = "EF55.5"; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + // update resource contactId metadata: extended character set (128–255) + resourceDetails.setContactId(extendedCharsStringBuilder()); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + // update resource contactId metadata: null + updatedcontactId = null; + resourceDetails.setContactId(updatedcontactId); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_CONTACT.name(), myList, + updatedRestResponse.getResponse()); + + } + + @Test + public void UpdateResource_TagsFieldValidation() throws Exception { + RestResponse updatedRestResponse; + // define and create resource + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + String uniqueId = resourceDetails.getUniqueId(); + + String updatedTagField = ""; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(updatedTagField); + // set description + resourceDetails.setTags(resourceTags); + List variables = Arrays.asList("Resource", "tag"); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FIELD_FORMAT.name(), variables, + updatedRestResponse.getResponse()); + + // update resource tags metadata: empty + resourceTags = new ArrayList(); + // set Tags + resourceDetails.setTags(resourceTags); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_TAGS.name(), Empty_List, + updatedRestResponse.getResponse()); + + // update resource description metadata: 1 characters + updatedTagField = "A"; + resourceTags = new ArrayList(); + resourceTags.add(updatedTagField); + resourceTags.add(resourceDetails.getName()); + // set description + resourceDetails.setTags(resourceTags); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + // OK - tag up to 50 chars + updatedTagField = "The Indian-crested.porcupine_The Indian cresteddds"; + resourceTags.add(updatedTagField); + resourceDetails.setTags(resourceTags); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + // OK - sum is 1024, 50x20+48+20(commas)+6(cisco4 - resource name) + String updatedTagField1 = "The Indian-crested.porcupine_The Indian crestedd01"; + String updatedTagField2 = "The Indian-crested.porcupine_The Indian crestedd02"; + String updatedTagField3 = "The Indian-crested.porcupine_The Indian crestedd03"; + String updatedTagField4 = "The Indian-crested.porcupine_The Indian crestedd04"; + String updatedTagField5 = "The Indian-crested.porcupine_The Indian crestedd05"; + String updatedTagField6 = "The Indian-crested.porcupine_The Indian crestedd06"; + String updatedTagField7 = "The Indian-crested.porcupine_The Indian crestedd07"; + String updatedTagField8 = "The Indian-crested.porcupine_The Indian crestedd08"; + String updatedTagField9 = "The Indian-crested.porcupine_The Indian crestedd09"; + String updatedTagField10 = "The Indian-crested.porcupine_The Indian crestedd10"; + String updatedTagField11 = "The Indian-crested.porcupine_The Indian crestedd11"; + String updatedTagField12 = "The Indian-crested.porcupine_The Indian crestedd12"; + String updatedTagField13 = "The Indian-crested.porcupine_The Indian crestedd13"; + String updatedTagField14 = "The Indian-crested.porcupine_The Indian crestedd14"; + String updatedTagField15 = "The Indian-crested.porcupine_The Indian crestedd15"; + String updatedTagField16 = "The Indian-crested.porcupine_The Indian crestedd16"; + String updatedTagField17 = "The Indian-crested.porcupine_The Indian crestedd17"; + String updatedTagField18 = "The Indian-crested.porcupine_The Indian crestedd18"; + String updatedTagField19 = "The Indian-crested.porcupine_The Indian crestaa"; + + resourceTags = new ArrayList(); + resourceTags.add(updatedTagField); + resourceTags.add(updatedTagField1); + resourceTags.add(updatedTagField2); + resourceTags.add(updatedTagField3); + resourceTags.add(updatedTagField4); + resourceTags.add(updatedTagField5); + resourceTags.add(updatedTagField6); + resourceTags.add(updatedTagField7); + resourceTags.add(updatedTagField8); + resourceTags.add(updatedTagField9); + resourceTags.add(updatedTagField10); + resourceTags.add(updatedTagField11); + resourceTags.add(updatedTagField12); + resourceTags.add(updatedTagField13); + resourceTags.add(updatedTagField14); + resourceTags.add(updatedTagField15); + resourceTags.add(updatedTagField16); + resourceTags.add(updatedTagField17); + resourceTags.add(updatedTagField18); + resourceTags.add(updatedTagField19); + resourceTags.add(resourceDetails.getName()); + // set description + resourceDetails.setTags(resourceTags); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + // Add another tag-exceeds limit + resourceTags.add("d"); + resourceDetails.setTags(resourceTags); + ArrayList myArray = new ArrayList(); + myArray.add(0, "1024"); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_TAGS_EXCEED_LIMIT.name(), myArray, + updatedRestResponse.getResponse()); + + // Tag exceeds limit - 51 + resourceTags = new ArrayList(); + updatedTagField = "The Indian-crested.porcupine_The Indian crestedddsw"; + resourceTags.add(updatedTagField); + resourceTags.add(resourceDetails.getName()); + // set description + resourceDetails.setTags(resourceTags); + myArray.remove(0); + myArray.add(0, "50"); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_SINGLE_TAG_EXCEED_LIMIT.name(), myArray, + updatedRestResponse.getResponse()); + + } + + @Test + public void UpdateResource_DesriptionFieldValidation() throws Exception { + // define and create resource + RestResponse updatedRestResponse; + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + String uniqueId = resourceDetails.getUniqueId(); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + List resource = new ArrayList<>(); + resource.add("Resource"); + // update resource description metadata: 0 characters + String updatedDescription = ""; + // set description + resourceDetails.setDescription(updatedDescription); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name(), resource, + updatedRestResponse.getResponse()); + + // update resource description metadata: null + updatedDescription = null; + // set description + resourceDetails.setDescription(updatedDescription); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name(), resource, + updatedRestResponse.getResponse()); + + // update resource description metadata: 1 characters + updatedDescription = "A"; + // set description + resourceDetails.setDescription(updatedDescription); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + // update resource description metadata: 1024 characters + updatedDescription = "The Indian crested porcupine *{Hystrix indica}*, or Indian porcupine is a member of the Old World porcupines." + + "It is quite an adaptable rodent, found throughout southern Asia and the Middle East." + + "It is tolerant of several different habitats: mountains, tropical and subtropical grasslands, scrublands, and forests." + + "It is a large rodent, growing more than 0.9 m = (3 ft) long and weighing 14.5 kg = (32 lb)! [citation needed] It is covered in multiple layers of quills." + + "The longest quills grow from its shoulders to about a third of the animal's length." + + "Its tail is covered in short, hollow quills that can rattle when threatened." + + "It has broad feet and long claws for digging. When attacked, the Indian crested porcupine raises its quills and rattles the hollow quills on its tail." + + "If the predator persists past these threats, the porcupine launches a backwards assault, hoping to stab its attacker with its quills." + + "It does this so effectively that most brushes between predators and the Indian porcupine end in death or severe injury"; + // set description + resourceDetails.setDescription(updatedDescription); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + parseResponseAndValidate(resourceDetails, updatedRestResponse); + + // update resource description metadata: 1025 characters + updatedDescription = "The Indian crested porcupine *{Hystrix indica}*, or Indian porcupine is a member of the Old World porcupines." + + "It is quite an adaptable rodent, found throughout southern Asia and the Middle East." + + "It is tolerant of several different habitats: mountains, tropical and subtropical grasslands, scrublands, and forests." + + "It is a large rodent, growing more than 0.9 m = (3 ft) long and weighing 14.5 kg = (32 lb)! [citation needed] It is covered in multiple layers of quills." + + "The longest quills grow from its shoulders to about a third of the animal's length." + + "Its tail is covered in short, hollow quills that can rattle when threatened." + + "It has broad feet and long claws for digging. When attacked, the Indian crested porcupine raises its quills and rattles the hollow quills on its tail." + + "If the predator persists past these threats, the porcupine launches a backwards assault, hoping to stab its attacker with its quills." + + "It does this so effectively that most brushes between predators and the Indian porcupine end in death or severe injury."; + // set description + resourceDetails.setDescription(updatedDescription); + resource.add(1, "1024"); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, sdncModifierDetails, uniqueId, + ""); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_DESCRIPTION_EXCEEDS_LIMIT.name(), resource, + updatedRestResponse.getResponse()); + + } + + @Test + public void UpdateResource_TagsFormatValidation() throws Exception { + char[] notValidCharsArray = getTagInValidFormatChars(); + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check recourse created ", 201, restResponse.getErrorCode().intValue()); + String resourceName = resourceDetails.getName(); + + // update tag details + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + ArrayList resourceTags = new ArrayList(); + + String updatedTagField; + RestResponse updatedRestResponse; + List variables = Arrays.asList("Resource", "tag"); + + for (int i = 0; i < notValidCharsArray.length; i++) { + updatedTagField = "UpdatedTag" + notValidCharsArray[i]; + resourceTags = new ArrayList(); + resourceTags.add(updatedTagField); + resourceTags.add(resourceDetails.getName()); + // set description + updatedResourceDetails.setTags(resourceTags); + + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId(), ""); + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", + updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FIELD_FORMAT.name(), variables, + updatedRestResponse.getResponse()); + assertEquals("Check response code after updating resource icon", 400, + updatedRestResponse.getErrorCode().intValue()); + assertEquals("Check response code after updating resource icon", "Bad Request", + updatedRestResponse.getResponseMessage().toString()); + + } + + } + + @Test + public void UpdateResourceCategory_negativeFlow() throws Exception { + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after update resource", 201, restResponse.getErrorCode().intValue()); + Resource resourceBeforeUpdate = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + String uniqueID = resourceDetails.getUniqueId(); + + // Update resource Category Successfully + ResourceReqDetails updatedResourceDetails = resourceDetails; + + updatedResourceDetails.removeAllCategories(); + updatedResourceDetails.addCategoryChain(ServiceCategoriesEnum.MOBILITY.getValue(), + ResourceCategoryEnum.APPLICATION_L4_DATABASE.getSubCategory()); + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + + // validate response + List resourceList = new ArrayList(); + resourceList.add(0, "Resource"); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CATEGORY.name(), resourceList, + updatedRestResponse.getResponse()); + assertEquals("Check response code after updating resource", 400, updatedRestResponse.getErrorCode().intValue()); + + // Updating resource category + updatedResourceDetails = defineUpdateResourceWithNonUpdatableFields(resourceBeforeUpdate); + updatedResourceDetails.addCategory(""); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId(), ""); + // validate response + resourceList = new ArrayList(); + resourceList.add(0, "Resource"); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_CATEGORY.name(), resourceList, + updatedRestResponse.getResponse()); + assertEquals("Check response code after updating resource", 400, updatedRestResponse.getErrorCode().intValue()); + + // Updating resource category + updatedResourceDetails = defineUpdateResourceWithNonUpdatableFields(resourceBeforeUpdate); + updatedResourceDetails.addCategory("XXXXXX"); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId(), ""); + // validate response + resourceList = new ArrayList(); + resourceList.add(0, "Resource"); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_CATEGORY.name(), resourceList, + updatedRestResponse.getResponse()); + assertEquals("Check response code after updating resource", 400, updatedRestResponse.getErrorCode().intValue()); + + // CheckIn Resource + logger.debug("Changing resource life cycle "); + RestResponse checkoutResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); // NOT_CERTIFIED_CHECKIN + assertEquals("Check response code after checkin resource", 200, checkoutResource.getErrorCode().intValue()); + + // Update resource Category + updatedResourceDetails = defineUpdateResourceWithNonUpdatableFields(resourceBeforeUpdate); + updatedResourceDetails.addCategory(ServiceCategoriesEnum.VOIP.getValue()); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncModifierDetails, + resourceDetails.getUniqueId(), ""); + // verify response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), Empty_List, + updatedRestResponse.getResponse()); + assertEquals("Check response code after updating resource", 409, updatedRestResponse.getErrorCode().intValue()); + + // CheckIn Resource + logger.debug("Changing resource life cycle "); + RestResponse checkinResource = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); // NOT_CERTIFIED_CHECKIN + assertNotNull("check response object is not null after checkout resource", checkoutResource); + assertNotNull("check error code exists in response after checkIn resource", checkoutResource.getErrorCode()); + assertEquals("Check response code after checkin resource", 200, checkoutResource.getErrorCode().intValue()); + + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, uniqueID); + assertNotNull("check response object is not null after update resource", getRestResponse); + parseResponseAndValidate(resourceDetails, getRestResponse); + + } + + @Test + public void UpdateResourceCategorySuccessfully() throws Exception { + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after update resource", 201, restResponse.getErrorCode().intValue()); + Resource resourceBeforeUpdate = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + + // Update resource Category Successfully + ResourceReqDetails updatedResourceDetails = resourceDetails; + + updatedResourceDetails.removeAllCategories(); + updatedResourceDetails.addCategoryChain(ResourceCategoryEnum.APPLICATION_L4_DATABASE.getCategory(), + ResourceCategoryEnum.APPLICATION_L4_DATABASE.getSubCategory()); + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncModifierDetails, resourceDetails.getUniqueId(), ""); + + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, updatedRestResponse.getErrorCode().intValue()); + // parseResponseAndValidateNonUpdatable(updatedResourceDetails, + // updatedRestResponse); + parseResponseAndValidate(updatedResourceDetails, updatedRestResponse); + + // validate category updated + assertTrue(updatedResourceDetails.getCategories().get(0).getName() + .equals(ResourceCategoryEnum.APPLICATION_L4_DATABASE.getCategory())); + + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncModifierDetails, + resourceDetails.getUniqueId()); + assertNotNull("check response object is not null after update resource", getRestResponse); + parseResponseAndValidate(updatedResourceDetails, getRestResponse); + + ResourceRestUtils.deleteResourceByNameAndVersion(sdncModifierDetails, updatedResourceDetails.getName(), "0.1"); + } + + // Benny + + @Test + public void Validation_UpdateIcon() throws Exception { + // Fields to update (Forbidden) + String _updatedIcon = "mySecondIcon.Jpg"; + + // administrator permissions + User sdncAdminModifierDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // define and create resource + ResourceRestUtils.deleteResourceByNameAndVersion(sdncAdminModifierDetails, resourceDetails.getName(), "0.1"); + + RestResponse restResponse = createResource(sdncAdminModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + String resourceName = resourceDetails.getName(); + + // update metadata details + ResourceReqDetails updatedResourceDetails = defineUpdatedResourse(resourceName); + // change icon of metadata + updatedResourceDetails.setIcon(_updatedIcon); + // PUT request + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, + sdncAdminModifierDetails, resourceDetails.getUniqueId(), ""); + + // validate response + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_INVALID_ICON.name(), + Arrays.asList("Resource"), updatedRestResponse.getResponse()); + + // empty icon + _updatedIcon = ""; + updatedResourceDetails.setIcon(_updatedIcon); + updatedRestResponse = ResourceRestUtils.updateResourceMetadata(updatedResourceDetails, sdncAdminModifierDetails, + resourceDetails.getUniqueId(), ""); + assertNotNull("check response object is not null after update resource", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_ICON.name(), + Arrays.asList("Resource"), updatedRestResponse.getResponse()); + + // get resource with original name. original metadata should be returned + RestResponse getRestResponse = ResourceRestUtils.getResource(sdncAdminModifierDetails, + resourceDetails.getUniqueId()); + // validate response + assertNotNull("check response object is not null after get resource", getRestResponse); + assertNotNull("check error code exists in response after get resource", getRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", 200, getRestResponse.getErrorCode().intValue()); + + // parse updated response to javaObject + Resource getResourceRespJavaObject = ResponseParser + .convertResourceResponseToJavaObject(getRestResponse.getResponse()); + // validate that metadata was not changed + ResourceValidationUtils.validateResourceReqVsResp(resourceDetails, getResourceRespJavaObject); + + ResourceRestUtils.deleteResourceByNameAndVersion(sdncAdminModifierDetails, updatedResourceDetails.getName(), + "0.1"); + + } + + @Test + public void UpdateResourceTypeSuccess() throws Exception { + // LCS is CheckOut + String newResourceType = ResourceTypeEnum.VL.toString(); + String currentResourceType = resourceDetails.getResourceType(); + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + Resource currentResourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + + resourceDetails.setResourceType(newResourceType); + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, currentResourceJavaObject.getUniqueId(), ""); + assertEquals("Check response code after create resource", 200, updatedRestResponse.getErrorCode().intValue()); + Resource updatedResourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(updatedRestResponse.getResponse()); + // assertTrue("Check resource type after update resource", + // updatedResourceJavaObject.getResourceType().toString().equals(resourceType)); + assertTrue("Check resource type after update resource", + updatedResourceJavaObject.getResourceType().toString().equals(currentResourceType)); + + } + + @Test + public void UpdateResourceTypeAndNameSuccess() throws Exception { + // LCS is CheckOut + String newResourceType = ResourceTypeEnum.VL.toString(); + String currentResourceType = resourceDetails.getResourceType(); + String newResourceName = "new Name"; + + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + Resource currentResourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + + resourceDetails.setResourceType(newResourceType); + resourceDetails.setName(newResourceName); + List tags = resourceDetails.getTags(); + tags.add(newResourceName); + resourceDetails.setTags(tags); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, currentResourceJavaObject.getUniqueId(), ""); + assertEquals("Check response code after create resource", 200, updatedRestResponse.getErrorCode().intValue()); + Resource updatedResourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(updatedRestResponse.getResponse()); + assertTrue("Check resource type after update resource", + updatedResourceJavaObject.getResourceType().toString().equals(currentResourceType)); + assertTrue("Check resource name after update resource", + updatedResourceJavaObject.getName().equals(newResourceName)); + + } + + @Test + public void UpdateResourceTypeAfterResourceCertification() throws Exception { + + String newResourceType = ResourceTypeEnum.VF.toString(); + String currentResourceType = resourceDetails.getResourceType(); + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + Resource currentResourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + + resourceDetails.setResourceType(newResourceType); + restResponse = LifecycleRestUtils.certifyResource(resourceDetails); + assertEquals("Check response code after resource CheckIn", 200, restResponse.getErrorCode().intValue()); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after resource CheckIn", 200, restResponse.getErrorCode().intValue()); + currentResourceJavaObject = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, currentResourceJavaObject.getUniqueId(), ""); + assertEquals("Check response code after create resource", 200, updatedRestResponse.getErrorCode().intValue()); + Resource updatedResourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(updatedRestResponse.getResponse()); + // assertTrue("Check resource type after update resource", + // updatedResourceJavaObject.getResourceType().toString().equals(newResourceType)); + assertTrue("Check resource type after update resource", + updatedResourceJavaObject.getResourceType().toString().equals(currentResourceType)); + + } + + @Test + public void UpdateResourceTypeCheckInLCS() throws Exception { + + String resourceType = ResourceTypeEnum.VL.toString(); + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + Resource currentResourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + + resourceDetails.setResourceType(resourceType); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncModifierDetails, + LifeCycleStatesEnum.CHECKIN); + assertEquals("Check response code after resource CheckIn", 200, restResponse.getErrorCode().intValue()); + + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, currentResourceJavaObject.getUniqueId(), ""); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + + assertNotNull("check response object is not null after create resouce", updatedRestResponse); + assertNotNull("check error code exists in response after create resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), + updatedRestResponse.getErrorCode()); + + List variables = new ArrayList<>(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), variables, + updatedRestResponse.getResponse()); + + } + + @Test + public void UpdateResourceTypeCertifiedLCS() throws Exception { + + String resourceType = ResourceTypeEnum.VL.toString(); + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + Resource currentResourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + + restResponse = LifecycleRestUtils.certifyResource(resourceDetails); + assertEquals("Check response code after resource CheckIn", 200, restResponse.getErrorCode().intValue()); + + resourceDetails.setResourceType(resourceType); + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, currentResourceJavaObject.getUniqueId(), ""); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + + assertNotNull("check response object is not null after create resouce", updatedRestResponse); + assertNotNull("check error code exists in response after create resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), + updatedRestResponse.getErrorCode()); + + List variables = new ArrayList<>(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), variables, + updatedRestResponse.getResponse()); + + } + + @Test + public void UpdateResourceTypeInvalidType() throws Exception { + + String resourceType = "INVALID TYPE"; + RestResponse restResponse = createResource(sdncModifierDetails, resourceDetails); + assertEquals("Check response code after create resource", 201, restResponse.getErrorCode().intValue()); + Resource currentResourceJavaObject = ResponseParser + .convertResourceResponseToJavaObject(restResponse.getResponse()); + + resourceDetails.setResourceType(resourceType); + RestResponse updatedRestResponse = ResourceRestUtils.updateResourceMetadata(resourceDetails, + sdncModifierDetails, currentResourceJavaObject.getUniqueId(), ""); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_CONTENT.name()); + + assertNotNull("check response object is not null after update resouce", updatedRestResponse); + assertNotNull("check error code exists in response after update resource", updatedRestResponse.getErrorCode()); + assertEquals("Check response code after update resource", errorInfo.getCode(), + updatedRestResponse.getErrorCode()); + + List variables = new ArrayList<>(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), variables, + updatedRestResponse.getResponse()); + + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/VFResourceInstanceNameCRUD.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/VFResourceInstanceNameCRUD.java new file mode 100644 index 0000000000..59050103ca --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/VFResourceInstanceNameCRUD.java @@ -0,0 +1,481 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +import fj.data.Either; + +public class VFResourceInstanceNameCRUD extends ComponentBaseTest { + + protected static ServiceReqDetails serviceDetails; + protected static ResourceReqDetails resourceDetailsVFC; + protected static ResourceReqDetails resourceDetailsVL; + protected static ResourceReqDetails resourceDetailsVF; + protected static ResourceReqDetails resourceDetailsCP; + protected static ComponentInstanceReqDetails resourceInstanceReqDetailsVF; + protected static ComponentInstanceReqDetails resourceInstanceReqDetailsVFC; + protected static ComponentInstanceReqDetails resourceInstanceReqDetailsVL; + protected static ComponentInstanceReqDetails resourceInstanceReqDetailsCP; + protected static User sdncDesignerDetails1; + protected static User sdncTesterDeatails1; + protected static User sdncAdminDetails1; + protected static ArtifactReqDetails heatArtifactDetails; + protected static ArtifactReqDetails defaultArtifactDetails; + protected static int maxLength = 50; + protected static Resource resourceVF = null; + + @Rule + public static TestName name = new TestName(); + + public VFResourceInstanceNameCRUD() { + super(name, VFResourceInstanceNameCRUD.class.getName()); + } + + @BeforeMethod + + public void init() throws Exception { + + // serviceDetails = ElementFactory.getDefaultService(); + // resourceDetailsVFC = + // ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VFC.toString(), + // "resourceVFC"); + // resourceDetailsVF = + // ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF.toString(), + // "resourceVF3"); + // resourceDetailsVL = + // ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VL.toString(), + // "resourceVL"); + // resourceDetailsCP = + // ElementFactory.getDefaultResourceByType(ResourceTypeEnum.CP.toString(), + // "resourceCP"); + sdncDesignerDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncTesterDeatails1 = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + sdncAdminDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // heatArtifactDetails = + // ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + + Either resourceDetailsCP_01e = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.CP, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(resourceDetailsCP_01e.left().value(), UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CHECKIN, true); + resourceDetailsCP = new ResourceReqDetails(resourceDetailsCP_01e.left().value()); + Either resourceDetailsVL_01e = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VL, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(resourceDetailsVL_01e.left().value(), UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CHECKIN, true); + resourceDetailsVL = new ResourceReqDetails(resourceDetailsVL_01e.left().value()); + Either resourceDetailsVF_01e = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true); + resourceDetailsVF = new ResourceReqDetails(resourceDetailsVF_01e.left().value()); + Either resourceDetailsVFC_01e = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.changeComponentState(resourceDetailsVFC_01e.left().value(), UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CHECKIN, true); + resourceDetailsVFC = new ResourceReqDetails(resourceDetailsVFC_01e.left().value()); + + resourceInstanceReqDetailsVFC = ElementFactory.getDefaultComponentInstance("VFC", resourceDetailsVFC); + resourceInstanceReqDetailsVF = ElementFactory.getDefaultComponentInstance("VF", resourceDetailsVF); + resourceInstanceReqDetailsVL = ElementFactory.getDefaultComponentInstance("VL", resourceDetailsVL); + resourceInstanceReqDetailsCP = ElementFactory.getDefaultComponentInstance("CP", resourceDetailsCP); + sdncDesignerDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncTesterDeatails1 = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + sdncAdminDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + } + + @Test + public void addResourceInstanceToVF() throws Exception { + + createVFWithCertifiedResourceInstance(resourceDetailsCP, resourceInstanceReqDetailsCP); + // validate RI name + List resourceInstances = resourceVF.getComponentInstances(); + List resourceInstanceListName = new ArrayList(); + for (int i = 0; i < resourceInstances.size(); i++) { + resourceInstanceListName.add(resourceInstances.get(i).getName()); + } + List resourceInstanceExpectedListName = new ArrayList(); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsCP.getName() + " 1"); + String message = "resource instance name"; + Utils.compareArrayLists(resourceInstanceListName, resourceInstanceExpectedListName, message); + + } + + @Test + public void updateResourceInstanceName() throws Exception { + + // update resource instance name + String resourceInstanceUpdatedName = "resource New 2"; + + ResourceReqDetails updatedResourceDetailsVLC = changeResouceName(resourceDetailsVFC, + resourceInstanceUpdatedName); + createVFWithCertifiedResourceInstance(updatedResourceDetailsVLC, resourceInstanceReqDetailsVFC); + + resourceInstanceReqDetailsVFC.setName(resourceInstanceUpdatedName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + resourceInstanceReqDetailsVFC, sdncDesignerDetails1, resourceVF.getUniqueId(), + ComponentTypeEnum.RESOURCE); + assertTrue(updateResourceInstanceResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + + // validate RI name + List resourceInstances = resourceVF.getComponentInstances(); + List resourceInstanceListName = new ArrayList(); + for (int i = 0; i < resourceInstances.size(); i++) { + resourceInstanceListName.add(resourceInstances.get(i).getName()); + } + List resourceInstanceExpectedListName = new ArrayList(); + resourceInstanceExpectedListName.add(resourceInstanceUpdatedName); + String message = "resource instance name"; + Utils.compareArrayLists(resourceInstanceListName, resourceInstanceExpectedListName, message); + + } + + @Test + public void updateResourceInstanceNameToNextGeneratedName() throws Exception { + + // update resource instance name + String resourceInstanceUpdatedName = resourceInstanceReqDetailsCP.getName() + " 2"; + + ResourceReqDetails updatedResourceDetailsVL = changeResouceName(resourceDetailsVL, resourceInstanceUpdatedName); + createVFWithCertifiedResourceInstance(updatedResourceDetailsVL, resourceInstanceReqDetailsVL); + resourceInstanceReqDetailsCP.setName(resourceInstanceUpdatedName); + + // add second resource instance + RestResponse response = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetailsCP, + sdncDesignerDetails1, resourceVF); + assertEquals("Check response code after create RI", 201, response.getErrorCode().intValue()); + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + + // validate RI name + List resourceInstances = resourceVF.getComponentInstances(); + List resourceInstanceListName = new ArrayList(); + for (int i = 0; i < resourceInstances.size(); i++) { + resourceInstanceListName.add(resourceInstances.get(i).getName()); + } + List resourceInstanceExpectedListName = new ArrayList(); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsVL.getName() + " 1"); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsCP.getName() + " 2"); + String message = "resource instance name"; + Utils.compareArrayLists(resourceInstanceListName, resourceInstanceExpectedListName, message); + + } + + @Test + public void normolizeUpdatedResourceInstanceName() throws Exception { + + String resourceInstanceUpdatedName = "resource new - .2"; + String normalizedName = "resourcenew2"; + + ResourceReqDetails updatedResourceDetailsVL = changeResouceName(resourceDetailsVL, resourceInstanceUpdatedName); + + createVFWithCertifiedResourceInstance(updatedResourceDetailsVL, resourceInstanceReqDetailsVL); + // update resource instance name + resourceInstanceReqDetailsCP.setName(resourceInstanceUpdatedName); + + // add second resource instance + RestResponse response = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetailsCP, + sdncDesignerDetails1, resourceVF); + assertEquals("Check response code after create RI", 201, response.getErrorCode().intValue()); + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + + // validate RI name + List resourceInstances = resourceVF.getComponentInstances(); + List resourceInstanceListName = new ArrayList(); + for (int i = 0; i < resourceInstances.size(); i++) { + resourceInstanceListName.add(resourceInstances.get(i).getName()); + } + List resourceInstanceExpectedListName = new ArrayList(); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsVL.getName() + " 1"); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsCP.getName() + " 2"); + String message = "resource instance name"; + Utils.compareArrayLists(resourceInstanceListName, resourceInstanceExpectedListName, message); + + } + + @Test + public void updatedResourceInstanceNameToEmpty() throws Exception { + + createVFWithCertifiedResourceInstance(resourceDetailsVL, resourceInstanceReqDetailsVL); + String resourceInstanceUpdatedName = ""; + String resourceInstancePreviousName = resourceDetailsCP.getName(); + + // add second resource instance + RestResponse response = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetailsCP, + sdncDesignerDetails1, resourceVF); + assertEquals("Check response code after create RI", 201, response.getErrorCode().intValue()); + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + + resourceInstanceReqDetailsCP.setName(resourceInstanceUpdatedName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + resourceInstanceReqDetailsCP, sdncDesignerDetails1, resourceVF.getUniqueId(), + ComponentTypeEnum.RESOURCE); + assertEquals("Check response code after RI update request", 200, + updateResourceInstanceResponse.getErrorCode().intValue()); + // change request + // ErrorInfo errorInfo = + // Utils.parseYaml(ActionStatus.MISSING_COMPONENT_NAME.name()); + // utils.validateResponseCode(updateResourceInstanceResponse, + // errorInfo.getCode(), "update resource instance"); + // + // List variables = Arrays.asList("Resource Instance"); + // ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_COMPONENT_NAME.name(), + // variables, updateResourceInstanceResponse.getResponse()); + + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + + // validate RI name + List resourceInstances = resourceVF.getComponentInstances(); + List resourceInstanceListName = new ArrayList(); + for (int i = 0; i < resourceInstances.size(); i++) { + resourceInstanceListName.add(resourceInstances.get(i).getName()); + } + List resourceInstanceExpectedListName = new ArrayList(); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsVL.getName() + " 1"); + resourceInstanceExpectedListName.add(resourceInstancePreviousName + " 3"); + String message = "resource instance name"; + Utils.compareArrayLists(resourceInstanceListName, resourceInstanceExpectedListName, message); + + } + + @Test + public void updatedResourceNameLengthExceedMaximumCharacters() throws Exception { + + String resourceInstancePreviousName = resourceDetailsCP.getName(); + // update resource instance name + String resourceInstanceUpdatedName = "a"; + for (int i = 0; i < maxLength; i++) { + resourceInstanceUpdatedName += "b"; + } + // ResourceReqDetails updatedResourceDetailsVL = + // changeResouceName(resourceDetailsVL, resourceInstanceUpdatedName); + + createVFWithCertifiedResourceInstance(resourceDetailsVL, resourceInstanceReqDetailsVL); + // add second resource instance + RestResponse response = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetailsCP, + sdncDesignerDetails1, resourceVF); + assertEquals("Check response code after create RI", 201, response.getErrorCode().intValue()); + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + + String prevName = resourceInstanceReqDetailsCP.getName(); + resourceInstanceReqDetailsCP.setName(resourceInstanceUpdatedName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + resourceInstanceReqDetailsCP, sdncDesignerDetails1, resourceVF.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_NAME_EXCEEDS_LIMIT.name()); + // utils.validateResponseCode(updateResourceInstanceResponse, + // errorInfo.getCode(), "update resource instance"); + + List variables = Arrays.asList("Resource Instance", "50"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_NAME_EXCEEDS_LIMIT.name(), variables, + updateResourceInstanceResponse.getResponse()); + + resourceInstanceReqDetailsCP.setName(prevName); + // validate RI name + List resourceInstances = resourceVF.getComponentInstances(); + List resourceInstanceListName = new ArrayList(); + for (int i = 0; i < resourceInstances.size(); i++) { + resourceInstanceListName.add(resourceInstances.get(i).getName()); + } + List resourceInstanceExpectedListName = new ArrayList(); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsVL.getName() + " 1"); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsCP.getName() + " 2"); + String message = "resource instance name"; + Utils.compareArrayLists(resourceInstanceListName, resourceInstanceExpectedListName, message); + + } + + @Test + public void updatedResourceNameWithUnSupportedCharacters() throws Exception { + + createVFWithCertifiedResourceInstance(resourceDetailsVL, resourceInstanceReqDetailsVL); + String resourceInstancePreviousName = resourceDetailsCP.getName(); + // update resource instance name + String resourceInstanceUpdatedName = "a???<>"; + + // add second resource instance + RestResponse response = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetailsCP, + sdncDesignerDetails1, resourceVF); + assertEquals("Check response code after create RI", 201, response.getErrorCode().intValue()); + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + + String prevValue = resourceInstanceReqDetailsCP.getName(); + resourceInstanceReqDetailsCP.setName(resourceInstanceUpdatedName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + resourceInstanceReqDetailsCP, sdncDesignerDetails1, resourceVF.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_COMPONENT_NAME.name()); + // ResourceRestUtils.validateResponseCode(updateResourceInstanceResponse, + // errorInfo.getCode(), "update resource instance"); + + List variables = Arrays.asList("Resource Instance"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_COMPONENT_NAME.name(), variables, + updateResourceInstanceResponse.getResponse()); + + resourceInstanceReqDetailsCP.setName(prevValue); + + // validate RI name + List resourceInstances = resourceVF.getComponentInstances(); + List resourceInstanceListName = new ArrayList(); + for (int i = 0; i < resourceInstances.size(); i++) { + resourceInstanceListName.add(resourceInstances.get(i).getName()); + } + List resourceInstanceExpectedListName = new ArrayList(); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsVL.getName() + " 1"); + resourceInstanceExpectedListName.add(resourceInstanceReqDetailsCP.getName() + " 2"); + String message = "resource instance name"; + Utils.compareArrayLists(resourceInstanceListName, resourceInstanceExpectedListName, message); + + } + + private static ResourceReqDetails changeResouceName(ResourceReqDetails resourceDet, + String resourceInstanceUpdatedName) throws Exception { + + ResourceReqDetails updatedResourceDetails = new ResourceReqDetails(); + updatedResourceDetails = resourceDet; + updatedResourceDetails.setName(resourceInstanceUpdatedName); + List tags = new ArrayList(); + tags.add(resourceInstanceUpdatedName); + updatedResourceDetails.setTags(tags); + Gson gson = new Gson(); + String updatedResourceBodyJson = gson.toJson(updatedResourceDetails); + RestResponse response = LifecycleRestUtils.changeResourceState(resourceDet, sdncDesignerDetails1, + resourceDet.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertTrue("change LS state to CHECKOUT, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + response = ResourceRestUtils.updateResourceMetadata(updatedResourceBodyJson, sdncDesignerDetails1, + updatedResourceDetails.getUniqueId()); + assertEquals("Check response code after updateresource name", 200, response.getErrorCode().intValue()); + response = LifecycleRestUtils.changeResourceState(updatedResourceDetails, sdncDesignerDetails1, + resourceDet.getVersion(), LifeCycleStatesEnum.CHECKIN); + + return updatedResourceDetails; + + } + + // private Component changeResouceName(Resource resourceDet, String + // resourceInstanceUpdatedName) throws Exception{ + // + // User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // Resource updatedResourceDetails = resourceDet; + // RestResponse response = + // LifecycleRestUtils.changeComponentState(updatedResourceDetails, + // defaultUser, LifeCycleStatesEnum.CHECKOUT, "state changed"); + // assertTrue("change LS state to CHECKOUT, returned status:" + + // response.getErrorCode(),response.getErrorCode() == 200); + // updatedResourceDetails.setName(resourceInstanceUpdatedName); + // List tags = new ArrayList(); + // tags.add(resourceInstanceUpdatedName); + // updatedResourceDetails.setTags(tags); + // Gson gson = new Gson(); + // ResourceReqDetails resourceReqDetails = new + // ResourceReqDetails(updatedResourceDetails); + // String updatedResourceBodyJson = gson.toJson(resourceReqDetails); + // response = ResourceRestUtils.updateResource(updatedResourceBodyJson, + // defaultUser, updatedResourceDetails.getUniqueId()); + // assertEquals("Check response code after updateresource name", 200, + // response.getErrorCode().intValue()); + // response = + // LifecycleRestUtils.changeComponentState(updatedResourceDetails, + // defaultUser, LifeCycleStatesEnum.CHECKIN, "state changed"); + // assertEquals("Check response code after updateresource name", 200, + // response.getErrorCode().intValue()); + // + // return updatedResourceDetails; + // + // } + + private void createVFWithCertifiedResourceInstance(ResourceReqDetails resourceDetails, + ComponentInstanceReqDetails resourceInstanceReqDetails) throws Exception { + + RestResponse response = LifecycleRestUtils.changeResourceState(resourceDetails, sdncDesignerDetails1, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after CHECKOUT", 200, response.getErrorCode().intValue()); + + // add heat artifact to resource and certify + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, + resourceDetails.getUniqueId()); + assertTrue("add HEAT artifact to resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + response = LifecycleRestUtils.certifyResource(resourceDetails); + assertEquals("Check response code after CERTIFY request", 200, response.getErrorCode().intValue()); + + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + + resourceInstanceReqDetails.setComponentUid(resourceDetails.getUniqueId()); + response = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, sdncDesignerDetails1, + resourceVF); + assertEquals("Check response code after create RI", 201, response.getErrorCode().intValue()); + + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + } + + protected Resource convertResourceGetResponseToJavaObject(ResourceReqDetails resourceDetails) throws IOException { + RestResponse response = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails1); + assertEquals("Check response code after get resource", 200, response.getErrorCode().intValue()); + return ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ValidateExtendedVfData.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ValidateExtendedVfData.java new file mode 100644 index 0000000000..8a17c3c115 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/ValidateExtendedVfData.java @@ -0,0 +1,319 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.List; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.AssocType; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.lifecycle.LCSbaseTest; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import fj.data.Either; + +public class ValidateExtendedVfData extends ComponentBaseTest { + + protected Resource resourceDetailsVF; + protected Resource resourceDetailsCP_01; + protected Resource resourceDetailsVL_01; + protected Resource resourceDetailsVFCcomp; + + protected User sdncUserDetails; + + @Rule + public static TestName name = new TestName(); + + public ValidateExtendedVfData() { + super(name, ValidateExtendedVfData.class.getName()); + } + + @BeforeMethod + public void create() throws Exception { + + sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + Either resourceDetailsVFe = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true); + resourceDetailsVF = resourceDetailsVFe.left().value(); + Either resourceDetailsCP_01e = AtomicOperationUtils + .createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.CP, NormativeTypesEnum.PORT, + ResourceCategoryEnum.GENERIC_DATABASE, UserRoleEnum.DESIGNER, true); + resourceDetailsCP_01 = resourceDetailsCP_01e.left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsCP_01, UserRoleEnum.DESIGNER, + true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT_VOL, resourceDetailsCP_01, + UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT_VOL, resourceDetailsCP_01, + UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT_NET, resourceDetailsCP_01, + UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, resourceDetailsCP_01, UserRoleEnum.DESIGNER, + true, true); + AtomicOperationUtils.changeComponentState(resourceDetailsCP_01, UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CERTIFY, true); + Either resourceDetailsVL_01e = AtomicOperationUtils + .createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VL, NormativeTypesEnum.NETWORK, + ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, UserRoleEnum.DESIGNER, true); + resourceDetailsVL_01 = resourceDetailsVL_01e.left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVL_01, UserRoleEnum.DESIGNER, + true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT_VOL, resourceDetailsVL_01, + UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT_VOL, resourceDetailsVL_01, + UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT_NET, resourceDetailsVL_01, + UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, resourceDetailsVL_01, UserRoleEnum.DESIGNER, + true, true); + AtomicOperationUtils.changeComponentState(resourceDetailsVL_01, UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CERTIFY, true); + + Either resourceDetailsVFCcompE = AtomicOperationUtils + .createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.COMPUTE, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + resourceDetailsVFCcomp = resourceDetailsVFCcompE.left().value(); + AtomicOperationUtils.changeComponentState(resourceDetailsVFCcomp, UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CERTIFY, true); + + ComponentInstance resourceDetailsCP_01ins = AtomicOperationUtils + .addComponentInstanceToComponentContainer(resourceDetailsCP_01, resourceDetailsVF, + UserRoleEnum.DESIGNER, true) + .left().value(); + ComponentInstance resourceDetailsVL_01ins = AtomicOperationUtils + .addComponentInstanceToComponentContainer(resourceDetailsVL_01, resourceDetailsVF, + UserRoleEnum.DESIGNER, true) + .left().value(); + ComponentInstance resourceDetailsVFCcomp_ins = AtomicOperationUtils + .addComponentInstanceToComponentContainer(resourceDetailsVFCcomp, resourceDetailsVF, + UserRoleEnum.DESIGNER, true) + .left().value(); + + resourceDetailsVF = AtomicOperationUtils.getResourceObject(resourceDetailsVF, UserRoleEnum.DESIGNER); + AtomicOperationUtils.associate2ResourceInstances(resourceDetailsVF, resourceDetailsCP_01ins, + resourceDetailsVL_01ins, AssocType.LINKABLE.getAssocType(), UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.associate2ResourceInstances(resourceDetailsVF, resourceDetailsCP_01ins, + resourceDetailsVFCcomp_ins, AssocType.BINDABLE.getAssocType(), UserRoleEnum.DESIGNER, true); + + } + + @Test + public void getResourceLatestVersion() throws Exception { + + RestResponse response = LifecycleRestUtils.changeComponentState(resourceDetailsVF, sdncUserDetails, + LifeCycleStatesEnum.CHECKIN); + assertTrue("change LC state to CHECKIN, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + // resourceDetailsVF = + // AtomicOperationUtils.getResourceObject(resourceDetailsVF, + // UserRoleEnum.DESIGNER); + RestResponse getResourceLatestVersionResponse = ResourceRestUtils.getResourceLatestVersionList(sdncUserDetails); + assertTrue("response code is not 200, returned :" + getResourceLatestVersionResponse.getErrorCode(), + getResourceLatestVersionResponse.getErrorCode() == 200); + + List resourceList = ResourceRestUtils + .restResponseToResourceObjectList(getResourceLatestVersionResponse.getResponse()); + Resource resource = ResourceRestUtils.getResourceObjectFromResourceListByUid(resourceList, + resourceDetailsVF.getUniqueId()); + + callAllCheckMethods(resource); + } + + @Test + public void getFollowedResources() throws Exception { + + RestResponse response = LifecycleRestUtils.changeComponentState(resourceDetailsVF, sdncUserDetails, + LifeCycleStatesEnum.CHECKIN); + assertTrue("change LC state to CHECKIN, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + // resourceDetailsVF = + // AtomicOperationUtils.getResourceObject(resourceDetailsVF, + // UserRoleEnum.DESIGNER); + resourceDetailsVF = AtomicOperationUtils.getResourceObject(resourceDetailsVF, UserRoleEnum.DESIGNER); + + RestResponse getFollowedResourcesResponse = ResourceRestUtils.getFollowedList(sdncUserDetails); + String json = getFollowedResourcesResponse.getResponse(); + JSONObject jsonResp = (JSONObject) JSONValue.parse(json); + JSONArray resources = (JSONArray) jsonResp.get("resources"); + + List resourceList = ResourceRestUtils.restResponseToResourceObjectList(resources.toString()); + Resource resource = ResourceRestUtils.getResourceObjectFromResourceListByUid(resourceList, + resourceDetailsVF.getUniqueId()); + // TODO if get followed list Api should return full object data? + // callAllCheckMethods(resource); + } + + @Test + public void lifeCycleChekInRequest() throws Exception { + + RestResponse response = LifecycleRestUtils.changeComponentState(resourceDetailsVF, sdncUserDetails, + LifeCycleStatesEnum.CHECKIN); + assertTrue("change LC state to CHECKIN, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + // resourceDetailsVF = + // AtomicOperationUtils.getResourceObject(resourceDetailsVF, + // UserRoleEnum.DESIGNER); + resourceDetailsVF = AtomicOperationUtils.getResourceObject(resourceDetailsVF, UserRoleEnum.DESIGNER); + + Resource resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + callAllCheckMethods(resource); + } + + @Test + public void lifeCycleChekOutRequest() throws Exception { + + RestResponse response = LifecycleRestUtils.changeComponentState(resourceDetailsVF, sdncUserDetails, + LifeCycleStatesEnum.CHECKIN); + assertTrue("change LC state to CHECKIN, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + response = LifecycleRestUtils.changeComponentState(resourceDetailsVF, sdncUserDetails, + LifeCycleStatesEnum.CHECKOUT); + assertTrue("change LC state to CHECKOUT, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + resourceDetailsVF = AtomicOperationUtils.getResourceObject(resourceDetailsVF, UserRoleEnum.DESIGNER); + + Resource resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + callAllCheckMethods(resource); + } + + @Test + public void lifeCycleRequestForCertification() throws Exception { + + RestResponse response = LifecycleRestUtils.changeComponentState(resourceDetailsVF, sdncUserDetails, + LifeCycleStatesEnum.CHECKIN); + assertTrue("change LC state to CHECKIN, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + response = LifecycleRestUtils.changeComponentState(resourceDetailsVF, sdncUserDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertTrue("change LC state to CERTIFICATIONREQUEST, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + resourceDetailsVF = AtomicOperationUtils.getResourceObject(resourceDetailsVF, UserRoleEnum.DESIGNER); + + Resource resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + callAllCheckMethods(resource); + } + + @Test + public void lifeCycleCertificationRequest() throws Exception { + + RestResponse response = AtomicOperationUtils + .changeComponentState(resourceDetailsVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, false) + .getRight(); + assertTrue("change LC state to CERTIFY, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + resourceDetailsVF = AtomicOperationUtils.getResourceObject(resourceDetailsVF, UserRoleEnum.DESIGNER); + + Resource resource = ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + callAllCheckMethods(resource); + } + + @Test + public void checkGetResourceAfterCertificationRequest() throws Exception { + + RestResponse response = AtomicOperationUtils + .changeComponentState(resourceDetailsVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, false) + .getRight(); + assertTrue("change LC state to CERTIFY, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + resourceDetailsVF = AtomicOperationUtils.getResourceObject(resourceDetailsVF, UserRoleEnum.DESIGNER); + + callAllCheckMethods(resourceDetailsVF); + } + + @Test + public void updateResourceMetadata() throws Exception { + + resourceDetailsVF.setDescription("stamStam"); + ResourceReqDetails resourceDetailsVFreqD = new ResourceReqDetails(resourceDetailsVF); + RestResponse updateResourceResponse = ResourceRestUtils.updateResourceMetadata(resourceDetailsVFreqD, + sdncUserDetails, resourceDetailsVF.getUniqueId()); + assertTrue("response code is not 200, returned :" + updateResourceResponse.getErrorCode(), + updateResourceResponse.getErrorCode() == 200); + + Resource resource = ResponseParser.convertResourceResponseToJavaObject(updateResourceResponse.getResponse()); + + callAllCheckMethods(resource); + } + + private void checkResourceInstances(Resource resource) { + assertNotNull("resource component Instances list is null ", resource.getComponentInstances()); + assertTrue("resource component Instances list is empty ", !resource.getComponentInstances().equals("")); + } + + private void checkResourceInstancesProperties(Resource resource) { + assertNotNull("component Instances properies list is null ", resource.getComponentInstancesProperties()); + assertTrue("component Instances properies list is empty ", + !resource.getComponentInstancesProperties().equals("")); + } + + private void checkResourceInstancesRelations(Resource resource) { + assertNotNull("component Instances Relations list is null ", resource.getComponentInstancesRelations()); + assertTrue("component Instances Relations list is empty ", + !resource.getComponentInstancesRelations().equals("")); + } + + private void checkResourceCapabilities(Resource resource) { + assertNotNull("component Instances Capabilities list is null ", resource.getCapabilities()); + assertTrue("component Instances Capabilities list is empty ", !resource.getCapabilities().equals("")); + } + + private void checkResourceRequirements(Resource resource) { + assertNotNull("component Instances Requirements list is null ", resource.getRequirements()); + assertTrue("component Instances Requirements list is empty ", !resource.getRequirements().equals("")); + } + + private void callAllCheckMethods(Resource resource) { + + checkResourceInstances(resource); + checkResourceInstancesProperties(resource); + checkResourceInstancesRelations(resource); + checkResourceCapabilities(resource); + checkResourceRequirements(resource); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/VfComponentInstanceCRUDTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/VfComponentInstanceCRUDTest.java new file mode 100644 index 0000000000..ea8b89200e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/resource/VfComponentInstanceCRUDTest.java @@ -0,0 +1,1792 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.resource; + +import static org.junit.Assert.assertTrue; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_ALREADY_EXISTS; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_COMPONENT_NAME_EXCEEDS_LIMIT; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_DELETE; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_INVALID_CONTENT; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_NOT_FOUND; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.RelationshipImpl; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentInstanceBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.BaseValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class VfComponentInstanceCRUDTest extends ComponentInstanceBaseTest { + + @Rule + public static TestName name = new TestName(); + + public VfComponentInstanceCRUDTest() { + super(name, VfComponentInstanceCRUDTest.class.getName()); + } + + @BeforeMethod + public void before() throws Exception { + init(); + createComponents(); + } + + // CREATE Resource + private void createComponents() throws Exception { + createAtomicResource(resourceDetailsVFC_01); + LifecycleRestUtils.changeResourceState(resourceDetailsVFC_01, sdncAdminDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + createAtomicResource(resourceDetailsVFC_02); + LifecycleRestUtils.changeResourceState(resourceDetailsVFC_02, sdncAdminDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + createAtomicResource(resourceDetailsCP_01); + LifecycleRestUtils.changeResourceState(resourceDetailsCP_01, sdncAdminDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + createAtomicResource(resourceDetailsCP_02); + LifecycleRestUtils.changeResourceState(resourceDetailsCP_02, sdncAdminDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + createAtomicResource(resourceDetailsVL_01); + LifecycleRestUtils.changeResourceState(resourceDetailsVL_01, sdncAdminDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + createAtomicResource(resourceDetailsVL_02); + LifecycleRestUtils.changeResourceState(resourceDetailsVL_02, sdncAdminDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + createVF(resourceDetailsVF_02); + } + + @Test + public void createVfcInstanceByDesigner() throws Exception { + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVFC_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test(enabled = false) // DE189419 + public void createInstanceOfVfToItself() throws Exception { + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVL_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVF_02); + createAtomicResourceInstance = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertTrue(createAtomicResourceInstance.getErrorCode() == STATUS_CODE_NOT_FOUND); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void createVfcInstanceByAdmin() throws Exception { + User user = sdncAdminDetails; + createVF(resourceDetailsVF_01, user); + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_01, + resourceDetailsVFC_01, user); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_01, 1, 0); + } + + @Test + public void createCpInstance() throws Exception { + // Create CP instance + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsCP_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void createVlInstance() throws Exception { + // Create VL instance + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVL_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void updateResourceInstanceNameLessMaxLegth() throws Exception { + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + vfcResourceInstanceReqDetails.setName("xxxxXthisXstringxisx49XcharcatersXlengthXxxxxxxxx"); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + + } + + @Test + public void updateInstanceNameExceedMaxLegth() throws Exception { + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + vfcResourceInstanceReqDetails.setName("xxxxXthisXstringxisx51XcharcatersXlengthXxxxxxxxxxx"); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_COMPONENT_NAME_EXCEEDS_LIMIT, + updateResourceInstanceResponse.getErrorCode().intValue()); + } + + @Test + public void updateResourceInstanceNameHasMaxLegth() throws Exception { + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + vfcResourceInstanceReqDetails.setName("xxxxXthisXstringxisx50XcharcatersXlengthXxxxxxxxxx"); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + } + + @Test + public void resourceInstanceNameIsEmpty() throws Exception { + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + resourceInstanceReqDetails.setName(""); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + String instanceNormalizedName = ResponseParser + .getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), "normalizedName"); + String instanceName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), + "name"); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "1").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance Name ", (resourceDetailsVFC_01.getName() + " 1"), + instanceName); + } + + @Test + public void resourceInstanceNameIsNull() throws Exception { + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + resourceInstanceReqDetails.setName(null); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + String instanceNormalizedName = ResponseParser + .getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), "normalizedName"); + String instanceName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), + "name"); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "1").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance Name ", (resourceDetailsVFC_01.getName() + " 1"), + instanceName); + } + + @Test + public void resourceInstanceNameValidation01() throws Exception { + // 2 Instances + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String instanceNormalizedName = ResponseParser + .getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), "normalizedName"); + String instanceName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), + "name"); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "1").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance Name ", (resourceDetailsVFC_01.getName() + " 1"), + instanceName); + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + instanceNormalizedName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), + "normalizedName"); + instanceName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), "name"); + componentInstance = ResponseParser.parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), + ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "2").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", (resourceDetailsVFC_01.getName() + " 2"), + instanceName); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + } + + @Test + public void resourceInstanceNameValidation02() throws Exception { + + // 2 Instances + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String instanceNormalizedName = ResponseParser + .getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), "normalizedName"); + String instanceName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), + "name"); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "1").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance Name ", (resourceDetailsVFC_01.getName() + " 1"), + instanceName); + resourceInstanceReqDetails = ElementFactory.getComponentResourceInstance(resourceDetailsCP_01); + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + instanceNormalizedName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), + "normalizedName"); + instanceName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), "name"); + componentInstance = ResponseParser.parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), + ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsCP_01.getName() + "2").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", (resourceDetailsCP_01.getName() + " 2"), + instanceName); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + } + + @Test + public void createVfcInstanceByTester() throws Exception { // Response 409 + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncTesterDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + createResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + } + + @Test + public void createVfcInstance_UserIdIsEmpty() throws Exception { + + User sdncUserDetails = new User(); + sdncUserDetails.setUserId(""); + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncUserDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + createResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + } + + @Test + public void createVfcInstance_UserIdIsNonAsdcUser() throws Exception { + + User sdncUserDetails = new User(); + sdncUserDetails.setUserId("bt4567"); + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncUserDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + createResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + } + + @Test + public void createAllAtomicInstances() throws Exception { + + // Add to VF resource VFC, CP and VL instances + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVL_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsCP_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsVFC_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 3, 0); + } + + @Test + public void createDefferentVfcInstances() throws Exception { + + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVFC_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsVFC_02, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + } + + @Test + public void createDefferentCpInstances() throws Exception { + + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsCP_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsCP_02, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + } + + @Test + public void createDefferentVLInstances() throws Exception { + + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVL_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsVL_02, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + } + + @Test + public void createSeveralInstanceOfSameVFC() throws Exception { + + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVFC_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsVFC_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + } + + @Test + public void createSeveralInstanceOfSameVL() throws Exception { + + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVL_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsVL_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + } + + @Test + public void createSeveralInstanceOfSameCP() throws Exception { + + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsCP_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsCP_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + } + + @Test + public void createInstanceOfCpToVfc() throws Exception { // Add to CP to VFC + // (not allowed) + + ComponentInstanceReqDetails resourceInstanceReqDetailsCP = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + ComponentInstanceReqDetails resourceInstanceReqDetailsVFC = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetailsCP, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetailsCP, sdncDesignerDetails, resourceInstanceReqDetailsVFC.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + createResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void createInstanceVfcToCp() throws Exception { // (not allowed) + + ComponentInstanceReqDetails resourceInstanceReqDetailsCP = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + ComponentInstanceReqDetails resourceInstanceReqDetailsVFC = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetailsCP, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetailsVFC, sdncDesignerDetails, resourceInstanceReqDetailsCP.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + createResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void createInstanceVlToVfc() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetailsVL = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + ComponentInstanceReqDetails resourceInstanceReqDetailsVFC = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetailsVFC, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetailsVL, sdncDesignerDetails, resourceInstanceReqDetailsVFC.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + createResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void createInstanceToNonSupportedComponentType() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetailsCP = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetailsCP, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE_INSTANCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_INVALID_CONTENT, + createResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + } + + // ("Create instance without position is allowed") + @Test + public void createInstanceOfVlWithoutPosXAndPosY() throws Exception { // instance + // does + // not + // have + // position + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + resourceInstanceReqDetails.setPosX(""); + resourceInstanceReqDetails.setPosY(""); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + // Create instance without position is allowed") + @Test + public void createInstanceOfVlWithPositionNull() throws Exception { // instance + // does + // not + // have + // position + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + resourceInstanceReqDetails.setPosX(null); + resourceInstanceReqDetails.setPosY(null); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void createResourceInstanceForNonCheckedOutVF() throws Exception { + + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF_02, sdncAdminDetails, + "0.1", LifeCycleStatesEnum.CHECKIN); + resourceDetailsVF_02.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); + AssertJUnit.assertEquals("Check response code after create user", STATUS_CODE_SUCCESS, + checkInResponse.getErrorCode().intValue()); + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + createResourceInstanceResponse.getErrorCode().intValue()); + } + + @Test + public void createResourceInstanceVfCheckedOutByOtherUser() throws Exception { + + // Admin try to add RI to VF which is checked-Out By Designer + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncAdminDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + createResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + } + + @Test + public void createResourceInstanceForNonExistingVF() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, "blablabla", ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + createResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + } + + // Delete + @Test + public void deleteVfcInstanceByDesigner() throws Exception { + + // Create RI + RestResponse createResourceInstanceResponse = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVFC_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String compInstId = ResponseParser.getUniqueIdFromResponse(createResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + // Delete Resource instance + RestResponse deleteResourceInstanceResponse = deleteAtomicInstanceForVF(compInstId, resourceDetailsVF_02, + sdncDesignerDetails); + ResourceRestUtils.checkDeleteResponse(deleteResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + } + + @Test + public void deleteVfcInstanceByAdmin() throws Exception { + createVF(resourceDetailsVF_01, sdncAdminDetails); + RestResponse createResourceInstanceResponse = createAtomicInstanceForVF(resourceDetailsVF_01, + resourceDetailsVL_01, sdncAdminDetails); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String compInstId = ResponseParser.getUniqueIdFromResponse(createResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_01, 1, 0); + // Delete Resource instance + RestResponse deleteResourceInstanceResponse = deleteAtomicInstanceForVF(compInstId, resourceDetailsVF_01, + sdncAdminDetails); + ResourceRestUtils.checkDeleteResponse(deleteResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_01, 0, 0); + } + + @Test + public void deleteCpInstance() throws Exception { + + RestResponse createResourceInstanceResponse = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsCP_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String compInstId = ResponseParser.getUniqueIdFromResponse(createResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + // Delete Resource instance + RestResponse deleteResourceInstanceResponse = deleteAtomicInstanceForVF(compInstId, resourceDetailsVF_02, + sdncDesignerDetails); + ResourceRestUtils.checkDeleteResponse(deleteResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + } + + @Test + public void deleteVlInstance() throws Exception { + + RestResponse createResourceInstanceResponse = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVL_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String compInstId = ResponseParser.getUniqueIdFromResponse(createResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + // Delete Resource instance + RestResponse deleteResourceInstanceResponse = deleteAtomicInstanceForVF(compInstId, resourceDetailsVF_02, + sdncDesignerDetails); + ResourceRestUtils.checkDeleteResponse(deleteResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + } + + @Test + public void deleteOneVlInstance() throws Exception { + + // RI-1 + RestResponse createResourceInstanceResponse = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVL_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String compInstId = ResponseParser.getUniqueIdFromResponse(createResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + // RI-2 + createResourceInstanceResponse = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsVL_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + // Delete Resource instance RI-1 + RestResponse deleteResourceInstanceResponse = deleteAtomicInstanceForVF(compInstId, resourceDetailsVF_02, + sdncDesignerDetails); + ResourceRestUtils.checkDeleteResponse(deleteResourceInstanceResponse); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void deleteVfcInstanceCheckedByOtherUser() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + // Delete Resource instance + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncTesterDetails, resourceDetailsVF_02.getUniqueId(), resourceInstanceReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + deleteResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void deleteInstanceNonSupportedComponentType() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), resourceInstanceReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE_INSTANCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_INVALID_CONTENT, + deleteResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void deleteInstanceFromNonVF() throws Exception { + // RI-1 + + ComponentInstanceReqDetails resourceInstanceVlReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceVlReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance1 = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance1, ComponentTypeEnum.RESOURCE); + // RI-2 + ComponentInstanceReqDetails resourceInstanceCplReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceCplReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance2 = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance2, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + // Delete VL instance from CP instance + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncDesignerDetails, resourceInstanceCplReqDetails.getUniqueId(), + resourceInstanceVlReqDetails.getUniqueId(), ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + deleteResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + } + + @Test + public void deleteNonExistingInstanceFromVF() throws Exception { + + ComponentInstanceReqDetails resourceInstanceVlReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceVlReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance1 = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance1, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + resourceInstanceVlReqDetails.setUniqueId("1234567890"); + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), resourceInstanceVlReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + deleteResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void deleteCpInstanceFromNonCheckOutVF() throws Exception { + + ComponentInstanceReqDetails resourceInstanceCpReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceCpReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance1 = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance1, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF_02, sdncDesignerDetails, + "0.1", LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_SUCCESS, + checkInResponse.getErrorCode().intValue()); + resourceDetailsVF_02.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); + // Delete Resource instance + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), resourceInstanceCpReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + deleteResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void deleteVlInstanceFromNonCheckOutVF() throws Exception { + + ComponentInstanceReqDetails resourceInstanceVlReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceVlReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance1 = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance1, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF_02, sdncDesignerDetails, + "0.1", LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_SUCCESS, + checkInResponse.getErrorCode().intValue()); + resourceDetailsVF_02.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); + // Delete Resource instance + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), resourceInstanceVlReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + deleteResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void deleteVfcInstanceFromNonCheckOutVF() throws Exception { + + ComponentInstanceReqDetails resourceInstanceVfcReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceVfcReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance1 = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance1, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + RestResponse checkInResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF_02, sdncDesignerDetails, + "0.1", LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_SUCCESS, + checkInResponse.getErrorCode().intValue()); + resourceDetailsVF_02.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); + // Delete Resource instance + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), resourceInstanceVfcReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + deleteResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void deleteVlInstance_UserIdIsNonAsdcUser() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + // Delete Resource instance by non-ASDC User + User sdncUserDetails = new User(); + sdncUserDetails.setUserId("bt4567"); + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncUserDetails, resourceDetailsVF_02.getUniqueId(), resourceInstanceReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + deleteResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void deleteAlreadyDeletedInstance() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), resourceInstanceReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_DELETE, + deleteResourceInstanceResponse.getErrorCode().intValue()); + deleteCompInstReqCapFromExpected(componentInstance.getUniqueId()); + getComponentAndValidateRIs(resourceDetailsVF_02, 0, 0); + deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance(sdncDesignerDetails, + resourceDetailsVF_02.getUniqueId(), resourceInstanceReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + deleteResourceInstanceResponse.getErrorCode().intValue()); + } + + @Test + public void reCreateDeletedInstance() throws Exception { + + // 2 Instances + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String instanceNormalizedName = ResponseParser + .getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), "normalizedName"); + String instanceName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), + "name"); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "1").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance Name ", (resourceDetailsVFC_01.getName() + " 1"), + instanceName); + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + instanceNormalizedName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), + "normalizedName"); + instanceName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), "name"); + componentInstance = ResponseParser.parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), + ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "2").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", (resourceDetailsVFC_01.getName() + " 2"), + instanceName); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + // Delete one instance + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance( + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), resourceInstanceReqDetails.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_DELETE, + deleteResourceInstanceResponse.getErrorCode().intValue()); + deleteCompInstReqCapFromExpected(componentInstance.getUniqueId()); + // Create same instance again + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + instanceNormalizedName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), + "normalizedName"); + instanceName = ResponseParser.getValueFromJsonResponse(createResourceInstanceResponse.getResponse(), "name"); + componentInstance = ResponseParser.parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), + ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "3").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance Name ", (resourceDetailsVFC_01.getName() + " 3"), + instanceName); + + } + + // Update + @Test + public void updateVfcInstanceNameByDesigner() throws Exception { + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + vfcResourceInstanceReqDetails.setName("abcd"); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String resourceNameFromJsonResponse = ResponseParser.getNameFromResponse(updateResourceInstanceResponse); + AssertJUnit.assertEquals(resourceNameFromJsonResponse, vfcResourceInstanceReqDetails.getName()); + String riNormalizedName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "normalizedName"); + String riName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "name"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riNormalizedName, "abcd"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riName, "abcd"); + } + + @Test + public void updateVfcInstanceNameByAdmin() throws Exception { + User user = sdncAdminDetails; + createVF(resourceDetailsVF_01, user); + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncAdminDetails, resourceDetailsVF_01.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_01, 1, 0); + vfcResourceInstanceReqDetails.setName("ABCD E"); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncAdminDetails, resourceDetailsVF_01.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String resourceNameFromJsonResponse = ResponseParser.getNameFromResponse(updateResourceInstanceResponse); + AssertJUnit.assertEquals(resourceNameFromJsonResponse, vfcResourceInstanceReqDetails.getName()); + String riNormalizedName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "normalizedName"); + String riName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "name"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riNormalizedName, "abcde"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riName, "ABCD E"); + } + + @Test + public void updateInstanceNameAllowedCharacters() throws Exception { + // Allowed characters: Alphanumeric (a-zA-Z0-9), space (' '), underscore + // ('_'), dash ('-'), dot ('.')) + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + vfcResourceInstanceReqDetails.setName("Abcd_1234567890-qwert-yuiop.zxcvb"); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String resourceNameFromJsonResponse = ResponseParser.getNameFromResponse(updateResourceInstanceResponse); + AssertJUnit.assertEquals(resourceNameFromJsonResponse, vfcResourceInstanceReqDetails.getName()); + String riNormalizedName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "normalizedName"); + String riName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "name"); + // assertEquals("Check if RI normalizedName is correct ", + // riNormalizedName, "abcd_1234567890-qwert-yuiop.zxcv" ); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riName, "Abcd_1234567890-qwert-yuiop.zxcvb"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riNormalizedName, + "abcd1234567890qwertyuiopzxcvb"); + + } + + @Test + public void updateVfcInstanceNameEmpty() throws Exception { + // see US534663 In case a designer removes the current resource instance + // name then BE has to generate again the "default" resource instance + // name + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String newName = ""; + vfcResourceInstanceReqDetails.setName(newName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String instanceNormalizedName = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "normalizedName"); + String instanceName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "name"); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "2").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", (resourceDetailsVFC_01.getName() + " 2"), + instanceName); + } + + @Test + public void updateVfcInstanceNameNull() throws Exception { + // see US534663 In case a designer removes the current resource instance + // name then BE has to generate again the "default" resource instance + // name + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String newName = null; + vfcResourceInstanceReqDetails.setName(newName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + final String updateResponse = updateResourceInstanceResponse.getResponse(); + String instanceNormalizedName = ResponseParser.getValueFromJsonResponse(updateResponse, "normalizedName"); + String instanceName = ResponseParser.getValueFromJsonResponse(updateResponse, "name"); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", + (resourceDetailsVFC_01.getName() + "2").toLowerCase(), instanceNormalizedName); + AssertJUnit.assertEquals("check Resource Instance normalizedName ", (resourceDetailsVFC_01.getName() + " 2"), + instanceName); + } + + @Test + public void updateCpInstanceName() throws Exception { + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + vfcResourceInstanceReqDetails.setName("AbcD"); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String resourceNameFromJsonResponse = ResponseParser.getNameFromResponse(updateResourceInstanceResponse); + AssertJUnit.assertEquals(resourceNameFromJsonResponse, vfcResourceInstanceReqDetails.getName()); + String riNormalizedName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "normalizedName"); + String riName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "name"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riNormalizedName, "abcd"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riName, "AbcD"); + } + + @Test + public void updateVlInstanceName() throws Exception { + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + vfcResourceInstanceReqDetails.setName("ABCD"); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String resourceNameFromJsonResponse = ResponseParser.getNameFromResponse(updateResourceInstanceResponse); + AssertJUnit.assertEquals(resourceNameFromJsonResponse, vfcResourceInstanceReqDetails.getName()); + String riNormalizedName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "normalizedName"); + String riName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "name"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riNormalizedName, "abcd"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riName, "ABCD"); + } + + @Test + public void updateInstanceNameToArleadyExistInstanceName02() throws Exception { + + // Create VFC instance + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance vfcComponentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(vfcComponentInstance, ComponentTypeEnum.RESOURCE); + // Create CP instance + ComponentInstanceReqDetails cpResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + cpResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance cpComponentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(cpComponentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 2, 0); + cpResourceInstanceReqDetails.setName(vfcComponentInstance.getName()); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + cpResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_ALREADY_EXISTS, + updateResourceInstanceResponse.getErrorCode().intValue()); + } + + @Test + public void updateInstanceNameMaxLength() throws Exception { + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String newName = "Qwertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl12345"; + vfcResourceInstanceReqDetails.setName(newName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String resourceNameFromJsonResponse = ResponseParser.getNameFromResponse(updateResourceInstanceResponse); + AssertJUnit.assertEquals(resourceNameFromJsonResponse, vfcResourceInstanceReqDetails.getName()); + String riNormalizedName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "normalizedName"); + String riName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "name"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riNormalizedName, newName.toLowerCase()); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riName, newName); + } + + @Test + public void updateInstanceNameExceedMaxLength() throws Exception { + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String newName = "Qwertyuiop1234567890asdfAhjklzxcvbnmasdfghjkl123456"; + vfcResourceInstanceReqDetails.setName(newName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_COMPONENT_NAME_EXCEEDS_LIMIT, + updateResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void updateCpInstanceCheckedByOtherUser() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String newName = "Qwertyuiop1234567890"; + resourceInstanceReqDetails.setName(newName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + resourceInstanceReqDetails, sdncAdminDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + updateResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void UpdateVfcInstance_UserIdIsNonAsdcUser() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String newName = "Qwertyuiop1234567890"; + resourceInstanceReqDetails.setName(newName); + User nonSdncUserDetails = new User(); + nonSdncUserDetails.setUserId("bt4567"); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + resourceInstanceReqDetails, nonSdncUserDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_RESTRICTED_OPERATION, + updateResourceInstanceResponse.getErrorCode().intValue()); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + } + + @Test + public void UpdateResourceInstanceFormNonExistingVF() throws Exception { + + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + // LifecycleRestUtils.changeResourceState(resourceDetailsVL_01, + // sdncAdminDetails, "0.1", LifeCycleStatesEnum.CHECKIN); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String newName = "Qwertyuiop1234567890"; + resourceInstanceReqDetails.setName(newName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, "blablabla", ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + updateResourceInstanceResponse.getErrorCode().intValue()); + } + + @Test + public void updateNonExistingInstanceFromVF() throws Exception { + + ComponentInstanceReqDetails resourceInstanceVlReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceVlReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance1 = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance1, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + resourceInstanceVlReqDetails.setUniqueId("1234567890"); + // String newName= "Qwertyuiop1234567890"; + // resourceInstanceVlReqDetails.setName(newName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + resourceInstanceVlReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + updateResourceInstanceResponse.getErrorCode().intValue()); + } + + // Update + @Test + public void updateVfcInstanceNameAsVfName() throws Exception { + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + vfcResourceInstanceReqDetails.setName(resourceDetailsVF_02.getName()); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String resourceNameFromJsonResponse = ResponseParser.getNameFromResponse(updateResourceInstanceResponse); + AssertJUnit.assertEquals(resourceNameFromJsonResponse, vfcResourceInstanceReqDetails.getName()); + String riNormalizedName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "normalizedName"); + String riName = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "name"); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riNormalizedName, + resourceDetailsVF_02.getName().toLowerCase()); + AssertJUnit.assertEquals("Check if RI normalizedName is correct ", riName, resourceDetailsVF_02.getName()); + } + + @Test + public void updateInstanceNameInvalidCharacters() throws Exception { + char invalidChars[] = { '~', '!', '$', '%', '^', '*', '(', ')', '"', '{', '}', '[', ']', '?', '>', '<', '/', + '|', '\\', ',' }; + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String newName = "Abcd1"; + String updateName; + for (int i = 0; i < invalidChars.length; i++) { + updateName = newName + invalidChars[i]; + vfcResourceInstanceReqDetails.setName(updateName); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_INVALID_CONTENT, + updateResourceInstanceResponse.getErrorCode().intValue()); + } + } + + // Update Position + @Test + public void updateVfcInstancePosition() throws Exception { + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String updatePosX = "130"; + String updatePosY = "180"; + vfcResourceInstanceReqDetails.setPosX(updatePosX); + vfcResourceInstanceReqDetails.setPosY(updatePosY); + vfcResourceInstanceReqDetails.setName(null); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String posXFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posX"); + String posYFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posY"); + AssertJUnit.assertEquals(posXFromJsonResponse, updatePosX); + AssertJUnit.assertEquals(posYFromJsonResponse, updatePosY); + } + + @Test + public void updateVlInstancePosition() throws Exception { + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVL_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String updatePosX = "130"; + String updatePosY = "180"; + vfcResourceInstanceReqDetails.setPosX(updatePosX); + vfcResourceInstanceReqDetails.setPosY(updatePosY); + vfcResourceInstanceReqDetails.setName(null); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String posXFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posX"); + String posYFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posY"); + AssertJUnit.assertEquals(posXFromJsonResponse, updatePosX); + AssertJUnit.assertEquals(posYFromJsonResponse, updatePosY); + } + + @Test + public void updateCpInstancePosition() throws Exception { + + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String updatePosX = "130"; + String updatePosY = "180"; + vfcResourceInstanceReqDetails.setPosX(updatePosX); + vfcResourceInstanceReqDetails.setPosY(updatePosY); + vfcResourceInstanceReqDetails.setName(null); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String posXFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posX"); + String posYFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posY"); + AssertJUnit.assertEquals(posXFromJsonResponse, updatePosX); + AssertJUnit.assertEquals(posYFromJsonResponse, updatePosY); + } + + @Test + public void updateInstancePositionNegativePosition() throws Exception { + + ComponentInstanceReqDetails cpResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + cpResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, ComponentTypeEnum.RESOURCE); + getComponentAndValidateRIs(resourceDetailsVF_02, 1, 0); + String updatePosX = "-100"; + String updatePosY = "-100"; + cpResourceInstanceReqDetails.setPosX(updatePosX); + cpResourceInstanceReqDetails.setPosY(updatePosY); + cpResourceInstanceReqDetails.setName(null); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + cpResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String posXFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posX"); + String posYFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posY"); + AssertJUnit.assertEquals(posXFromJsonResponse, updatePosX); + AssertJUnit.assertEquals(posYFromJsonResponse, updatePosY); + } + + @Test + public void updateInstancesPositionSameLocationForBothInstances() throws Exception { + + ComponentInstanceReqDetails cpResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + cpResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + ComponentInstanceReqDetails vfcResourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsVFC_01); + createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + String updatePosX = "100"; + String updatePosY = "500"; + vfcResourceInstanceReqDetails.setPosX(updatePosX); + vfcResourceInstanceReqDetails.setPosY(updatePosY); + vfcResourceInstanceReqDetails.setName(null); + cpResourceInstanceReqDetails.setPosX(updatePosX); + cpResourceInstanceReqDetails.setPosY(updatePosY); + cpResourceInstanceReqDetails.setName(null); + RestResponse updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + vfcResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + String posXFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posX"); + String posYFromJsonResponse = ResponseParser + .getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), "posY"); + AssertJUnit.assertEquals(posXFromJsonResponse, updatePosX); + AssertJUnit.assertEquals(posYFromJsonResponse, updatePosY); + updateResourceInstanceResponse = ComponentInstanceRestUtils.updateComponentInstance( + cpResourceInstanceReqDetails, sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), + ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(updateResourceInstanceResponse); + posXFromJsonResponse = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "posX"); + posYFromJsonResponse = ResponseParser.getValueFromJsonResponse(updateResourceInstanceResponse.getResponse(), + "posY"); + AssertJUnit.assertEquals(posXFromJsonResponse, updatePosX); + AssertJUnit.assertEquals(posYFromJsonResponse, updatePosY); + } + + @Test + public void createAllAtomicInstancesTestGetReqCapAPI_suc() throws Exception { + + // Add to VF resource VFC, CP and VL instances + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVL_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsCP_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsVFC_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + + getVfResourceReqCapUsingAPI(3, 0, sdncDesignerDetails); + + } + + // END of Update + + @Test + public void createAllAtomicInstancesTestGetReqCapAPIfailed() throws Exception { + + // Add to VF resource VFC, CP and VL instances + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsVL_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsCP_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsVFC_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + resourceDetailsVF_02.setUniqueId("dummy"); + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncAdminDetails, + resourceDetailsVF_02); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, + getResourceResponse.getErrorCode().intValue()); + + } + + @Test + public void associateInVF() throws Exception { + + ResourceReqDetails resourceDetailsReq = ElementFactory.getDefaultResourceByType("SoftCompRouter", + NormativeTypesEnum.SOFTWARE_COMPONENT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, + sdncDesignerDetails.getUserId(), ResourceTypeEnum.VFC); // resourceType + // = VFC + ResourceReqDetails resourceDetailsCap = ElementFactory.getDefaultResourceByType("MyComput", + NormativeTypesEnum.COMPUTE, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.VFC); // resourceType = VFC + createAtomicResource(resourceDetailsReq); + LifecycleRestUtils.changeResourceState(resourceDetailsReq, sdncAdminDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + createAtomicResource(resourceDetailsCap); + LifecycleRestUtils.changeResourceState(resourceDetailsCap, sdncAdminDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + + RestResponse riReqR = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsReq, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(riReqR); + RestResponse riCapR = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsCap, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(riCapR); + + ComponentInstance riReq = ResponseParser.parseToObject(riReqR.getResponse(), ComponentInstance.class); + ComponentInstance riCap = ResponseParser.parseToObject(riCapR.getResponse(), ComponentInstance.class); + + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + resourceDetailsVF_02); + + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + + List capList = capReqDef.getCapabilities().get("tosca.capabilities.Container"); + List reqList = capReqDef.getRequirements().get("tosca.capabilities.Container"); + + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + requirementDef.setFromNode(riReq.getUniqueId()); + requirementDef.setToNode(riCap.getUniqueId()); + + RequirementAndRelationshipPair pair = new RequirementAndRelationshipPair(); + pair.setRequirementOwnerId(riReq.getUniqueId()); + pair.setCapabilityOwnerId(riCap.getUniqueId()); + pair.setRequirement("host"); + RelationshipImpl relationship = new RelationshipImpl(); + relationship.setType("tosca.capabilities.Container"); + pair.setRelationships(relationship); + pair.setCapabilityUid(capList.get(0).getUniqueId()); + pair.setRequirementUid(reqList.get(0).getUniqueId()); + List relationships = new ArrayList<>(); + relationships.add(pair); + requirementDef.setRelationships(relationships); + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_SUCCESS, + associateInstances.getErrorCode().intValue()); + + getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + resourceDetailsVF_02); + capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + + List list = capReqDef.getRequirements().get("tosca.capabilities.Container"); + AssertJUnit.assertEquals("Check requirement", null, list); + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, + sdncDesignerDetails, resourceDetailsVF_02.getUniqueId(), ComponentTypeEnum.RESOURCE); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_SUCCESS, + dissociateInstances.getErrorCode().intValue()); + + getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + resourceDetailsVF_02); + capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + + list = capReqDef.getRequirements().get("tosca.capabilities.Container"); + AssertJUnit.assertEquals("Check requirement", 1, list.size()); + + } + + @Test + public void testUnsatisfiedCpReqInVF() throws Exception { + + // Certify all the needed atomic resources + RestResponse response = LifecycleRestUtils.certifyResource(resourceDetailsVFC_02); + ResourceRestUtils.checkSuccess(response); + response = LifecycleRestUtils.certifyResource(resourceDetailsCP_01); + ResourceRestUtils.checkSuccess(response); + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails, + resourceDetailsVF_02.getUniqueId()); + ResourceRestUtils.checkSuccess(response); + + RestResponse createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, + resourceDetailsCP_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + String compInstName = ResponseParser.getNameFromResponse(createAtomicResourceInstance); + String cpCompInstId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstance); + + RestResponse submitForTesting = LifecycleRestUtils.changeResourceState(resourceDetailsVF_02, + sdncDesignerDetails, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + String[] variables = new String[] { resourceDetailsVF_02.getName(), "VF", "CP (Connection Point)", compInstName, + "requirement", "tosca.capabilities.network.Bindable", "fulfilled" }; + BaseValidationUtils.checkErrorResponse(submitForTesting, + ActionStatus.REQ_CAP_NOT_SATISFIED_BEFORE_CERTIFICATION, variables); + + createAtomicResourceInstance = createAtomicInstanceForVF(resourceDetailsVF_02, resourceDetailsVFC_02, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + String computeCompInstId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstance); + fulfillCpRequirement(resourceDetailsVF_02, cpCompInstId, computeCompInstId, computeCompInstId, + sdncDesignerDetails, ComponentTypeEnum.RESOURCE); + + submitForTesting = LifecycleRestUtils.changeResourceState(resourceDetailsVF_02, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + BaseValidationUtils.checkSuccess(submitForTesting); + } + + private void getVfResourceReqCapUsingAPI(int numberOfRIs, int numberOfRelations, User user) + throws IOException, Exception { + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncAdminDetails, + resourceDetailsVF_02); + AssertJUnit.assertEquals("Check response code ", STATUS_CODE_SUCCESS, + getResourceResponse.getErrorCode().intValue()); + // ResourceValidationUtils.validateResp(getResourceResponse, + // resourceRespJavaObject); + // int numberOfActualRIs = resource.getComponentInstances()!=null ? + // resource.getComponentInstances().size() : 0; + // int numberOfActualRelations = + // resource.getComponentInstancesRelations()!=null ? + // resource.getComponentInstancesRelations().size() : 0; + // assertEquals("Check number of RIs meet the expected number", + // numberOfRIs ,numberOfActualRIs); + // assertEquals("Check number of RI relations meet the expected number", + // numberOfRelations ,numberOfActualRelations); + + //// get VF actual Capabilities and Requirements and validate according + //// to expected + Resource vfResource = ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), + Resource.class); + verifyReqCap(vfResource); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ChangeServiceDistributionStatusApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ChangeServiceDistributionStatusApiTest.java new file mode 100644 index 0000000000..3d338534d1 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ChangeServiceDistributionStatusApiTest.java @@ -0,0 +1,1012 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.service; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ServiceValidationUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import fj.data.Either; + +public class ChangeServiceDistributionStatusApiTest extends ComponentBaseTest { + + protected ResourceReqDetails resourceDetails; + protected ServiceReqDetails serviceDetails; + protected User sdncDesignerDetails; + protected User sdncAdminDetails; + protected User sdncGovernorDeatails; + protected User sdncTesterDetails; + protected User sdncOpsDetails; + protected ComponentInstanceReqDetails resourceInstanceReqDetails; + protected Component resourceDetailsVFCcomp; + protected Component serviceDetailsCompp; + + private String userRemarks = "commentTest"; + + private List variablesAsList; + + @Rule + public static TestName name = new TestName(); + + public ChangeServiceDistributionStatusApiTest() throws Exception { + super(name, ChangeServiceDistributionStatusApiTest.class.getName()); + + } + + @BeforeMethod + public void init() throws Exception { + + variablesAsList = new ArrayList(); + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncAdminDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncGovernorDeatails = ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR); + sdncTesterDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + sdncOpsDetails = ElementFactory.getDefaultUser(UserRoleEnum.OPS); + resourceDetailsVFCcomp = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVFCcomp, UserRoleEnum.DESIGNER, + true, true); + + AtomicOperationUtils.changeComponentState(resourceDetailsVFCcomp, UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CERTIFY, true); + Service serviceServ = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVFCcomp, serviceServ, + UserRoleEnum.DESIGNER, true); + + serviceDetails = new ServiceReqDetails(serviceServ); + + } + + // -----------------------------------------------T E S T + // S--------------------------------------------// + + @Test + public void approveNotCertifiedService_checkout() throws Exception { + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 403, serviceDetails.getVersion()); + + variablesAsList = Arrays.asList(serviceDetails.getVersion(), serviceDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name(), + variablesAsList, changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + validateAudit("DApprove", LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + "403", ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, sdncAdminDetails); + } + + @Test + public void approveNotCertifiedService_checkedin() throws Exception { + RestResponse checkinResp = LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals(200, checkinResp.getErrorCode().intValue()); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 403, serviceDetails.getVersion()); + + variablesAsList = Arrays.asList(serviceDetails.getVersion(), serviceDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name(), + variablesAsList, changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + validateAudit("DApprove", LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + "403", ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, sdncAdminDetails); + } + + @Test + public void approveNotCertifiedService_inProgress() throws Exception { + RestResponse certReqResp = LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(200, certReqResp.getErrorCode().intValue()); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 403, serviceDetails.getVersion()); + + variablesAsList = Arrays.asList(serviceDetails.getVersion(), serviceDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name(), + variablesAsList, changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name()); + // String auditAction="DApprove"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(serviceDetails, + // version, sdncAdminDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.READY_FOR_CERTIFICATION.name()); + // expectedResourceAuditJavaObject.setDprevStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setStatus("403"); + // expectedResourceAuditJavaObject.setDesc(String.format(errorInfo.getMessageId() + // + ": " + errorInfo.getMessage(), version, + // serviceDetails.getServiceName())); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DApprove", LifecycleStateEnum.READY_FOR_CERTIFICATION, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + "403", ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, sdncAdminDetails); + + } + + @Test + public void approveNotCertifiedService_readyForCer() throws Exception { + approveNotCertifiedService_inProgress(); + DbUtils.deleteFromEsDbByPattern("_all"); + + RestResponse startCertResp = LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(200, startCertResp.getErrorCode().intValue()); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 403, serviceDetails.getVersion()); + + variablesAsList = Arrays.asList(serviceDetails.getVersion(), serviceDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name(), + variablesAsList, changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name()); + // String auditAction="DApprove"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(serviceDetails, + // version, sdncAdminDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setDprevStatus(""); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setStatus("403"); + // expectedResourceAuditJavaObject.setDesc(String.format(errorInfo.getMessageId() + // + ": " + errorInfo.getMessage(), version, + // serviceDetails.getServiceName())); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DApprove", LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + "403", ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, sdncAdminDetails); + } + + @Test + public void rejectNotCertifiedService_checkeout() throws Exception { + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncAdminDetails, 403, serviceDetails.getVersion()); + + variablesAsList = Arrays.asList(serviceDetails.getVersion(), serviceDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name(), + variablesAsList, changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name()); + // String auditAction="DReject"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(serviceDetails, + // version, sdncAdminDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name()); + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setDprevStatus(""); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setStatus("403"); + // expectedResourceAuditJavaObject.setDesc(String.format(errorInfo.getMessageId() + // + ": " + errorInfo.getMessage(), version, + // serviceDetails.getServiceName())); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DReject", LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + "403", ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, sdncAdminDetails); + } + + @Test + public void rejectNotCertifiedService_checkedin() throws Exception { + RestResponse startCertResp = LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertEquals(200, startCertResp.getErrorCode().intValue()); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncAdminDetails, 403, serviceDetails.getVersion()); + + variablesAsList = Arrays.asList(serviceDetails.getVersion(), serviceDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name(), + variablesAsList, changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name()); + // String auditAction="DReject"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(serviceDetails, + // version, sdncAdminDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.name()); + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setDprevStatus(""); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setStatus("403"); + // expectedResourceAuditJavaObject.setDesc(String.format(errorInfo.getMessageId() + // + ": " + errorInfo.getMessage(), version, + // serviceDetails.getServiceName())); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DReject", LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + "403", ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, sdncAdminDetails); + } + + @Test + public void rejectNotCertifiedService_inProgress() throws Exception { + RestResponse startCertResp = LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(200, startCertResp.getErrorCode().intValue()); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncAdminDetails, 403, serviceDetails.getVersion()); + + variablesAsList = Arrays.asList(serviceDetails.getVersion(), serviceDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name(), + variablesAsList, changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name()); + // String auditAction="DReject"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(serviceDetails, + // version, sdncAdminDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.READY_FOR_CERTIFICATION.name()); + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setDprevStatus(""); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setStatus("403"); + // expectedResourceAuditJavaObject.setDesc(String.format(errorInfo.getMessageId() + // + ": " + errorInfo.getMessage(), version, + // serviceDetails.getServiceName())); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DReject", LifecycleStateEnum.READY_FOR_CERTIFICATION, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + "403", ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, sdncAdminDetails); + } + + @Test + public void rejectNotCertifiedService_readyForCer() throws Exception { + rejectNotCertifiedService_inProgress(); + DbUtils.deleteFromEsDbByPattern("_all"); + + RestResponse startCertResp = LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(200, startCertResp.getErrorCode().intValue()); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncAdminDetails, 403, serviceDetails.getVersion()); + + variablesAsList = Arrays.asList(serviceDetails.getVersion(), serviceDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name(), + variablesAsList, changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION.name()); + // String auditAction="DReject"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(serviceDetails, + // version, sdncAdminDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setDprevStatus(""); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setStatus("403"); + // expectedResourceAuditJavaObject.setDesc(String.format(errorInfo.getMessageId() + // + ": " + errorInfo.getMessage(), version, + // serviceDetails.getServiceName())); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DReject", LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + "403", ActionStatus.SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, sdncAdminDetails); + + } + + @Test + public void approveCertifiedService_bysdncGovernorDeatails() throws Exception { + + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncGovernorDeatails, 200, certifyService.getVersion()); + getDistrubtionStatusValue(changeDistStatusAndValidate, DistributionStatusEnum.DISTRIBUTION_APPROVED); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_APPROVED); + + validateAudit("DApprove", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_APPROVED, null, null, sdncGovernorDeatails); + } + + @Test + public void approveCertifiedService_bysdncAdminDetails() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 200, certifyService.getVersion()); + getDistrubtionStatusValue(changeDistStatusAndValidate, DistributionStatusEnum.DISTRIBUTION_APPROVED); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_APPROVED); + + validateAudit("DApprove", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_APPROVED, null, null, sdncAdminDetails); + } + + @Test + public void approveCertifiedService_byDesigner() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncDesignerDetails, 409, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.RESTRICTED_OPERATION.name()); + // String auditAction="DApprove"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(certifyService, + // certifyService.getVersion(), sdncDesignerDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.name()); + // expectedResourceAuditJavaObject.setDprevStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setStatus("409"); + // expectedResourceAuditJavaObject.setDesc(errorInfo.getMessageId() + ": + // " + errorInfo.getMessage()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DApprove", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, "409", ActionStatus.RESTRICTED_OPERATION, + sdncDesignerDetails); + } + + @Test + public void approveCertifiedService_byTester() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncTesterDetails, 409, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.RESTRICTED_OPERATION.name()); + // String auditAction="DApprove"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(certifyService, + // certifyService.getVersion(), sdncTesterDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.name()); + // expectedResourceAuditJavaObject.setDprevStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setStatus("409"); + // expectedResourceAuditJavaObject.setDesc(errorInfo.getMessageId() + ": + // " + errorInfo.getMessage()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DApprove", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, "409", ActionStatus.RESTRICTED_OPERATION, + sdncTesterDetails); + } + + @Test + public void approveCertifiedService_byOps() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncOpsDetails, 409, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + validateAudit("DApprove", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, "409", ActionStatus.RESTRICTED_OPERATION, + sdncOpsDetails); + + } + + @Test + public void rejectCertifiedService_bysdncGovernorDeatails() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncGovernorDeatails, 200, certifyService.getVersion()); + getDistrubtionStatusValue(changeDistStatusAndValidate, DistributionStatusEnum.DISTRIBUTION_REJECTED); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_REJECTED); + + // String auditAction="DReject"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(certifyService, + // certifyService.getVersion(), sdncGovernorDeatails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.name()); + // expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); + // expectedResourceAuditJavaObject.setDprevStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_REJECTED.name()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DReject", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_REJECTED, null, null, sdncGovernorDeatails); + + } + + @Test + public void rejectCertifiedService_bysdncAdminDetails() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncAdminDetails, 200, certifyService.getVersion()); + getDistrubtionStatusValue(changeDistStatusAndValidate, DistributionStatusEnum.DISTRIBUTION_REJECTED); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_REJECTED); + + // String auditAction="DReject"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(certifyService, + // certifyService.getVersion(), sdncAdminDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.name()); + // expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); + // expectedResourceAuditJavaObject.setDprevStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_REJECTED.name()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DReject", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_REJECTED, null, null, sdncAdminDetails); + } + + @Test + public void rejectCertifiedService_byDesigner() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncDesignerDetails, 409, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.RESTRICTED_OPERATION.name()); + // String auditAction="DReject"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(certifyService, + // certifyService.getVersion(), sdncDesignerDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.name()); + // expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); + // expectedResourceAuditJavaObject.setDprevStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setStatus("409"); + // expectedResourceAuditJavaObject.setDesc(errorInfo.getMessageId() + ": + // " + errorInfo.getMessage()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DReject", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, "409", ActionStatus.RESTRICTED_OPERATION, + sdncDesignerDetails); + } + + @Test + public void rejectCertifiedService_byTester() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncTesterDetails, 409, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.RESTRICTED_OPERATION.name()); + // String auditAction="DReject"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(certifyService, + // certifyService.getVersion(), sdncTesterDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.name()); + // expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); + // expectedResourceAuditJavaObject.setDprevStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setStatus("409"); + // expectedResourceAuditJavaObject.setDesc(errorInfo.getMessageId() + ": + // " + errorInfo.getMessage()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DReject", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, "409", ActionStatus.RESTRICTED_OPERATION, + sdncTesterDetails); + } + + @Test + public void rejectCertifiedService_byOps() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncOpsDetails, 409, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + // ErrorInfo errorInfo = + // utils.parseYaml(ActionStatus.RESTRICTED_OPERATION.name()); + // String auditAction="DReject"; + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(certifyService, + // certifyService.getVersion(), sdncOpsDetails); + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setResourceType("Service"); + // expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.name()); + // expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.name()); + // expectedResourceAuditJavaObject.setDprevStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setDcurrStatus(DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED.name()); + // expectedResourceAuditJavaObject.setStatus("409"); + // expectedResourceAuditJavaObject.setDesc(errorInfo.getMessageId() + ": + // " + errorInfo.getMessage()); + // expectedResourceAuditJavaObject.setComment(userRemarks); + // expectedResourceAuditJavaObject.setPrevVersion("0.1"); + // + // AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, + // auditAction); + + validateAudit("DReject", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, "409", ActionStatus.RESTRICTED_OPERATION, + sdncOpsDetails); + } + + @Test + public void approveServiceNotFound() throws Exception { + String previuosId = serviceDetails.getUniqueId(); + serviceDetails.setUniqueId("dummyId"); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 404, serviceDetails.getVersion()); + serviceDetails.setUniqueId(previuosId); + + variablesAsList = Arrays.asList("dummyId"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_FOUND.name(), variablesAsList, + changeDistStatusAndValidate.getResponse()); + + } + + @Test + public void rejectServiceNotFound() throws Exception { + String previuosId = serviceDetails.getUniqueId(); + serviceDetails.setUniqueId("dummyId"); + + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncAdminDetails, 404, serviceDetails.getVersion()); + serviceDetails.setUniqueId(previuosId); + + variablesAsList = Arrays.asList("dummyId"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_FOUND.name(), variablesAsList, + changeDistStatusAndValidate.getResponse()); + + } + + @Test + public void rejectService_emptyComment() throws Exception { + userRemarks = ""; + + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncAdminDetails, 400, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + } + + @Test + public void rejectService_nullComment() throws Exception { + userRemarks = null; + + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncAdminDetails, 400, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + } + + @Test + public void rejectService_spaceComment() throws Exception { + userRemarks = " "; + + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncAdminDetails, 400, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + } + + @Test + public void approveService_emptyComment() throws Exception { + userRemarks = ""; + + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 400, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + } + + @Test + public void approveService_nullComment() throws Exception { + userRemarks = null; + + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 400, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + } + + @Test + public void approveService_spaceComment() throws Exception { + userRemarks = " "; + + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse changeDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 400, certifyService.getVersion()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), new ArrayList(), + changeDistStatusAndValidate.getResponse()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED); + + } + + @Test + public void distributionStatusChange_approve_Reject_AprroveBysdncAdminDetails() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + + RestResponse approveDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncGovernorDeatails, 200, certifyService.getVersion()); + getDistrubtionStatusValue(approveDistStatusAndValidate, DistributionStatusEnum.DISTRIBUTION_APPROVED); + + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse rejectDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_REJECTED, sdncGovernorDeatails, 200, certifyService.getVersion()); + getDistrubtionStatusValue(rejectDistStatusAndValidate, DistributionStatusEnum.DISTRIBUTION_REJECTED); + + validateAudit("DReject", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_APPROVED, + DistributionStatusEnum.DISTRIBUTION_REJECTED, null, null, sdncGovernorDeatails); + + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse secondApproveDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncAdminDetails, 200, certifyService.getVersion()); + getDistrubtionStatusValue(secondApproveDistStatusAndValidate, DistributionStatusEnum.DISTRIBUTION_APPROVED); + + validateAudit("DApprove", LifecycleStateEnum.CERTIFIED, DistributionStatusEnum.DISTRIBUTION_REJECTED, + DistributionStatusEnum.DISTRIBUTION_APPROVED, null, null, sdncAdminDetails); + + } + + @Test + public void distributeNotCertifiedServiceTest() throws Exception { + RestResponse approveDistStatusAndValidate = changeDistStatusAndValidate(DistributionStatusEnum.DISTRIBUTED, + sdncGovernorDeatails, 200, serviceDetails.getVersion()); + + RestResponse getService = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTED); + + } + + @Test + public void distributeCertifiedServiceTest() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse approveDistStatusAndValidate = changeDistStatusAndValidate(DistributionStatusEnum.DISTRIBUTED, + sdncGovernorDeatails, 200, certifyService.getVersion()); + + RestResponse getService = ServiceRestUtils.getService(certifyService, sdncDesignerDetails); + getDistrubtionStatusValue(getService, DistributionStatusEnum.DISTRIBUTED); + + } + + @Test + public void approveCheckedoutCertifiedServiceTest() throws Exception { + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + RestResponse approveDistStatusAndValidate = changeDistStatusAndValidate( + DistributionStatusEnum.DISTRIBUTION_APPROVED, sdncGovernorDeatails, 200, certifyService.getVersion()); + getDistrubtionStatusValue(approveDistStatusAndValidate, DistributionStatusEnum.DISTRIBUTION_APPROVED); + + RestResponse checkoutResp = LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals(200, checkoutResp.getErrorCode().intValue()); + // Utils r = new Utils(); + + String distributionStatus = ResponseParser.getValueFromJsonResponse(checkoutResp.getResponse(), + "distributionStatus"); + // Utils r1 = new Utils(); + String lifecycleState = ResponseParser.getValueFromJsonResponse(checkoutResp.getResponse(), "lifecycleState"); + + assertTrue("NOT_CERTIFIED_CHECKOUT".equals(lifecycleState)); + assertTrue("DISTRIBUTION_NOT_APPROVED".equals(distributionStatus)); + } + + private RestResponse changeDistStatusAndValidate(DistributionStatusEnum distStatus, User user, int errorCode, + String serviceVersion) throws Exception { + RestResponse distributionResponse = LifecycleRestUtils.changeDistributionStatus(serviceDetails, serviceVersion, + user, userRemarks, distStatus); + assertNotNull(distributionResponse); + assertNotNull(distributionResponse.getErrorCode()); + assertEquals(errorCode, distributionResponse.getErrorCode().intValue()); + + if (userRemarks == " " || userRemarks == null) { + userRemarks = ""; + } + + return distributionResponse; + } + + private void getDistrubtionStatusValue(RestResponse response, DistributionStatusEnum expectedDistributionValue) + throws Exception { + String actualDistributionValue = ResponseParser.getValueFromJsonResponse(response.getResponse(), + "distributionStatus"); + assertEquals(expectedDistributionValue.name(), actualDistributionValue); + } + + private void validateAudit(String Action, LifecycleStateEnum currState, DistributionStatusEnum dPrevStatus, + DistributionStatusEnum dCurrStatus, String status, ActionStatus errorInfoFromFile, User user) + throws Exception { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceDetails.getVersion(), user); + expectedResourceAuditJavaObject.setAction(Action); + expectedResourceAuditJavaObject.setResourceType("Service"); + expectedResourceAuditJavaObject.setCurrState(currState.name()); + expectedResourceAuditJavaObject.setDprevStatus(dPrevStatus.name()); + expectedResourceAuditJavaObject.setDcurrStatus(dCurrStatus.name()); + expectedResourceAuditJavaObject.setComment(userRemarks); + expectedResourceAuditJavaObject.setDesc("OK"); + + if (errorInfoFromFile != null) { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(errorInfoFromFile.name()); + expectedResourceAuditJavaObject + .setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variablesAsList)); + } + + if (status != null) + expectedResourceAuditJavaObject.setStatus(status); + + if (currState != LifecycleStateEnum.CERTIFIED) { + expectedResourceAuditJavaObject.setModifierName(""); + } + + AuditValidationUtils.validateAuditDistribution(expectedResourceAuditJavaObject, Action); + } + + // private ServiceReqDetails certifyService() throws Exception + // { + // ServiceReqDetails certifyService = + // LifecycleRestUtils.certifyService(serviceDetails, + // serviceDetails.getVersion(), sdncAdminDetails); + //// version = certifyService.getVersion(); + // + // return certifyService; + // } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/CreateServiceMetadataApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/CreateServiceMetadataApiTest.java new file mode 100644 index 0000000000..8e95a6d02c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/CreateServiceMetadataApiTest.java @@ -0,0 +1,1304 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.service; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.json.JSONObject; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ServiceValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class CreateServiceMetadataApiTest extends ComponentBaseTest { + private static Logger logger = LoggerFactory.getLogger(CreateServiceMetadataApiTest.class.getName()); + + String serviceBaseVersion = "0.1"; + + @Rule + public static TestName name = new TestName(); + + public CreateServiceMetadataApiTest() { + super(name, CreateServiceMetadataApiTest.class.getName()); + } + + @Test + public void createDefaultService() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // String creator = + // ElementFactory.getDefaultUser(UserRoleEnum.ADMIN).getUserId(); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", 201, restResponse.getErrorCode().intValue()); + + // validate create service response vs actual + + Service service = ResponseParser.convertServiceResponseToJavaObject(restResponse.getResponse()); + ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, service, sdncUserDetails, + (LifecycleStateEnum) null); + + // validate get service response vs actual + restResponse = ServiceRestUtils.getService(serviceDetails, sdncUserDetails); + service = ResponseParser.convertServiceResponseToJavaObject(restResponse.getResponse()); + ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, service, sdncUserDetails, + (LifecycleStateEnum) null); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createDefaultServiceUserDesigner() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", 201, restResponse.getErrorCode().intValue()); + + // validate create service response vs actual + + Service service = ResponseParser.convertServiceResponseToJavaObject(restResponse.getResponse()); + ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, service, sdncUserDetails, + (LifecycleStateEnum) null); + + // validate get service response vs actual + restResponse = ServiceRestUtils.getService(serviceDetails, sdncUserDetails); + service = ResponseParser.convertServiceResponseToJavaObject(restResponse.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createServiceUserNotFound() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncUserDetails.setUserId("no1234"); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), variables, + restResponse.getResponse()); + + // validate audit + + sdncUserDetails.setFirstName(""); + sdncUserDetails.setLastName(""); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setModifierName(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createServiceUserNotAllowed() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), variables, + restResponse.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createServiceEmptyName() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + String serviceName = ""; + serviceDetails.setName(serviceName); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_COMPONENT_NAME.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList("Service"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_COMPONENT_NAME.name(), variables, + restResponse.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createServiceEmptyCategory() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + String category = ""; + + serviceDetails.setCategories(null); + // serviceDetails.addCategory(category); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_CATEGORY.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList("Service"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_CATEGORY.name(), variables, + restResponse.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createServiceEmptyTag() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ArrayList tags = new ArrayList(); + tags.add(""); + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + serviceDetails.setTags(tags); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_FIELD_FORMAT.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList("Service", "tag"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FIELD_FORMAT.name(), variables, + restResponse.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createServiceEmptyDescription() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + String description = ""; + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + serviceDetails.setDescription(description); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList("Service"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name(), variables, + restResponse.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createServiceEmptyTags() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ArrayList tags = new ArrayList(); + tags.add(""); + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + serviceDetails.setTags(tags); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_FIELD_FORMAT.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList("Service", "tag"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FIELD_FORMAT.name(), variables, + restResponse.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createServiceByPutHttpMethod() throws Exception { + + String method = "PUT"; + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + + RestResponse restResponse = ServiceRestUtils.createServiceByHttpMethod(serviceDetails, sdncUserDetails, method, + Urls.CREATE_SERVICE); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.NOT_ALLOWED.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), variables, + restResponse.getResponse()); + + // //validate audit + // + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // resourceUtils.constructFieldsForAuditValidation(serviceDetails, + // serviceBaseVersion, sdncUserDetails); + // + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + // + // String auditDesc = + // AuditValidationUtils.buildAuditDescription(errorInfo, variables); + // expectedResourceAuditJavaObject.setDesc(auditDesc); + // + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction); + + } + + @Test + public void createServiceByDeleteHttpMethod() throws Exception { + + String method = "DELETE"; + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + + RestResponse restResponse = ServiceRestUtils.createServiceByHttpMethod(serviceDetails, sdncUserDetails, method, + Urls.CREATE_SERVICE); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.NOT_ALLOWED.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.NOT_ALLOWED.name(), variables, + restResponse.getResponse()); + + // //validate audit + // + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // resourceUtils.constructFieldsForAuditValidation(serviceDetails, + // serviceBaseVersion, sdncUserDetails); + // + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setAction(auditAction); + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + // + // String auditDesc = + // AuditValidationUtils.buildAuditDescription(errorInfo, variables); + // expectedResourceAuditJavaObject.setDesc(auditDesc); + // + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction); + + } + + @Test + public void createServiceTagLengthExceedLimit() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + StringBuffer tagBuffer = new StringBuffer(); + for (int i = 0; i < 1025; i++) { + tagBuffer.append("a"); + } + ArrayList tags = new ArrayList(); + tags.add(tagBuffer.toString()); + serviceDetails.setTags(tags); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_SINGLE_TAG_EXCEED_LIMIT.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList("50"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_SINGLE_TAG_EXCEED_LIMIT.name(), variables, + restResponse.getResponse()); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setDesc(errorInfo.getAuditDesc("50")); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + /* + * ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + * ServiceValidationUtils.constructFieldsForAuditValidation( + * serviceDetails, serviceBaseVersion, sdncUserDetails); + * + * String auditAction="Create"; + * expectedResourceAuditJavaObject.setAction(auditAction); + * expectedResourceAuditJavaObject.setPrevState(""); + * expectedResourceAuditJavaObject.setPrevVersion(""); + * expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum. + * NOT_CERTIFIED_CHECKOUT).toString()); + * expectedResourceAuditJavaObject.setStatus(errorInfo.getCode(). + * toString()); expectedResourceAuditJavaObject.setDesc(auditDesc); + * + * AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + * auditAction, null); + */ + + } + + @Test + public void createServiceAlreadyExistException() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // create service with the same name + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_NAME_ALREADY_EXIST.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + + List variables = Arrays.asList("Service", serviceDetails.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_NAME_ALREADY_EXIST.name(), variables, + restResponse.getResponse()); + + // validate audit + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void createServiceWrongContactId() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + serviceDetails.setContactId("123as"); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.COMPONENT_INVALID_CONTACT.name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + } + + @Test + public void createServiceProjectName() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + serviceDetails.setProjectCode("12345"); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + Integer expectedCode = 201; + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", expectedCode, restResponse.getErrorCode()); + Service service = ResponseParser.convertServiceResponseToJavaObject(restResponse.getResponse()); + + assertEquals("12345", service.getProjectCode()); + } + + @Test + public void createAndGetByNameAndVersion() throws Exception { + + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + // create + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + assertEquals("Check response code after create service", 201, restResponse.getErrorCode().intValue()); + + // get + restResponse = ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, serviceDetails.getName(), + serviceBaseVersion); + assertEquals("Check response code after get service", 200, restResponse.getErrorCode().intValue()); + + Service service = ResponseParser.convertServiceResponseToJavaObject(restResponse.getResponse()); + String uniqueId = service.getUniqueId(); + serviceDetails.setUniqueId(uniqueId); + ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, service, sdncUserDetails, + (LifecycleStateEnum) null); + } + + //// US553874 + + @JsonIgnore + @Test + public void createServiceIsVNF_isFalse() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after updating Interface Artifact", 201, + restResponse.getErrorCode().intValue()); + + // get service and verify that service created with isVNF defined in + // serviceDetails + RestResponse serviceByNameAndVersion = ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + serviceDetails.getName(), serviceBaseVersion); + Service serviceObject = ResponseParser + .convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, serviceObject, sdncUserDetails, + LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + @JsonIgnore + @Test + public void createServiceIsVNF_isTrue() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after updating Interface Artifact", 201, + restResponse.getErrorCode().intValue()); + + // get service and verify that service created with isVNF defined in + // serviceDetails + RestResponse serviceByNameAndVersion = ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + serviceDetails.getName(), serviceBaseVersion); + Service serviceObject = ResponseParser + .convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, serviceObject, sdncUserDetails, + LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + + // validate audit + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + @JsonIgnore + @Test(enabled = false) + public void createServiceIsVNF_isNull() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + // clean audit DB before service creation + DbUtils.cleanAllAudits(); + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + assertNotNull("check response object is not null after create service", restResponse); + assertEquals("Check response code after updating Interface Artifact", 400, + restResponse.getErrorCode().intValue()); + List variables = Arrays.asList("VNF Service Indicator"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_DATA.name(), variables, + restResponse.getResponse()); + + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setDesc(errorInfo.getAuditDesc("VNF Service Indicator")); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + } + + @JsonIgnore + @Test(enabled = false) + public void createServiceEmptyIsVNF() throws Exception { + + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + + DbUtils.cleanAllAudits(); + + // send create service toward BE + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", restResponse.getErrorCode(), + restResponse.getErrorCode()); + + // validate create service response vs actual + List variables = Arrays.asList("VNF Service Indicator"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_DATA.name(), variables, + restResponse.getResponse()); + + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, serviceBaseVersion, sdncUserDetails); + + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + private RestResponse createServiceWithMissingAttribute(String serviceDetails, User sdncModifierDetails) + throws Exception { + + Config config = Utils.getConfig(); + + Map headersMap = ServiceRestUtils.prepareHeadersMap(sdncModifierDetails, false); + headersMap.put(HttpHeaderEnum.CACHE_CONTROL.getValue(), "no-cache"); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.CREATE_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort()); + // TODO: ADD AUTHENTICATION IN REQUEST + logger.debug(url); + logger.debug("Send POST request to create service: {}", url); + logger.debug("Service body: {}", serviceDetails); + logger.debug("Service headers: {}", headersMap); + RestResponse sendCreateUserRequest = http.httpSendPost(url, serviceDetails, headersMap); + + return sendCreateUserRequest; + + } + + @JsonIgnore + @Test(enabled = false) + public void createServiceVersion_isVNFDoesNotExistInJson() throws Exception { + + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + // clean audit DB before updating service + DbUtils.cleanAllAudits(); + + // remove isVNF from json sent to create service + JSONObject jObject = new JSONObject(serviceDetails); + jObject.remove("VNF"); + + // send create service toward BE + RestResponse restResponse = createServiceWithMissingAttribute(jObject.toString(), sdncUserDetails); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after updating Interface Artifact", 400, + restResponse.getErrorCode().intValue()); + List variables = new ArrayList(); + variables.add("VNF Service Indicator"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_DATA.name(), variables, + restResponse.getResponse()); + + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ServiceValidationUtils + .constructFieldsForAuditValidation(serviceDetails, "0.1", sdncUserDetails); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setDesc(errorInfo.getAuditDesc("VNF Service Indicator")); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, null, false); + + } + + @Test + public void checkInvariantUuidIsImmutable() throws Exception { + // choose the user to create service + User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + Component resourceDetailsVFCcomp = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.ADMIN, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVFCcomp, UserRoleEnum.ADMIN, + true, true); + AtomicOperationUtils.changeComponentState(resourceDetailsVFCcomp, UserRoleEnum.ADMIN, + LifeCycleStatesEnum.CERTIFY, true); + + // fill new service details + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + String invariantUuidDefinedByUser = "!!!!!!!!!!!!!!!!!!!!!!!!"; + serviceDetails.setInvariantUUID(invariantUuidDefinedByUser); + + // create service + RestResponse restResponseCreation = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + BaseRestUtils.checkStatusCode(restResponseCreation, "create request failed", false, 201); + Service service = ResponseParser.convertServiceResponseToJavaObject(restResponseCreation.getResponse()); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVFCcomp, service, + UserRoleEnum.ADMIN, true); + + String invariantUUIDcreation = service.getInvariantUUID(); + + // validate get service response vs actual + RestResponse restResponseGetting = ServiceRestUtils.getService(serviceDetails, sdncUserDetails); + BaseRestUtils.checkSuccess(restResponseGetting); + service = ResponseParser.convertServiceResponseToJavaObject(restResponseGetting.getResponse()); + String invariantUUIDgetting = service.getInvariantUUID(); + + assertEquals(invariantUUIDcreation, invariantUUIDgetting); + + // Update service with new invariant UUID + RestResponse restResponseUpdate = ServiceRestUtils.updateService(serviceDetails, sdncUserDetails); + BaseRestUtils.checkSuccess(restResponseUpdate); + Service updatedService = ResponseParser.convertServiceResponseToJavaObject(restResponseUpdate.getResponse()); + String invariantUUIDupdating = updatedService.getInvariantUUID(); + assertEquals(invariantUUIDcreation, invariantUUIDupdating); + + // Do checkin + RestResponse restResponseCheckin = LifecycleRestUtils.changeServiceState(serviceDetails, sdncUserDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.CHECKIN); + BaseRestUtils.checkSuccess(restResponseCheckin); + Service checkinService = ResponseParser.convertServiceResponseToJavaObject(restResponseCheckin.getResponse()); + String invariantUUIDcheckin = checkinService.getInvariantUUID(); + String version = checkinService.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDcheckin); + assertEquals(version, "0.1"); + + // Do checkout + RestResponse restResponseCheckout = LifecycleRestUtils.changeServiceState(serviceDetails, sdncUserDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + BaseRestUtils.checkSuccess(restResponseCheckout); + Service checkoutService = ResponseParser.convertServiceResponseToJavaObject(restResponseCheckout.getResponse()); + String invariantUUIDcheckout = checkoutService.getInvariantUUID(); + version = checkoutService.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDcheckout); + assertEquals(version, "0.2"); + + // do certification request + RestResponse restResponseCertificationRequest = LifecycleRestUtils.changeServiceState(serviceDetails, + sdncUserDetails, serviceDetails.getVersion(), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + BaseRestUtils.checkSuccess(restResponseCertificationRequest); + Service certificationRequestService = ResponseParser + .convertServiceResponseToJavaObject(restResponseCertificationRequest.getResponse()); + String invariantUUIDcertificationRequest = certificationRequestService.getInvariantUUID(); + version = certificationRequestService.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDcertificationRequest); + assertEquals(version, "0.2"); + + // start certification + RestResponse restResponseStartCertification = LifecycleRestUtils.changeServiceState(serviceDetails, + sdncUserDetails, serviceDetails.getVersion(), LifeCycleStatesEnum.STARTCERTIFICATION); + BaseRestUtils.checkSuccess(restResponseStartCertification); + Service startCertificationRequestService = ResponseParser + .convertServiceResponseToJavaObject(restResponseStartCertification.getResponse()); + String invariantUUIDStartCertification = startCertificationRequestService.getInvariantUUID(); + version = startCertificationRequestService.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDStartCertification); + assertEquals(version, "0.2"); + + // certify + RestResponse restResponseCertify = LifecycleRestUtils.changeServiceState(serviceDetails, sdncUserDetails, + serviceDetails.getVersion(), LifeCycleStatesEnum.CERTIFY); + BaseRestUtils.checkSuccess(restResponseCertify); + Service certifyService = ResponseParser.convertServiceResponseToJavaObject(restResponseCertify.getResponse()); + String invariantUUIDcertify = certifyService.getInvariantUUID(); + version = certifyService.getVersion(); + assertEquals(invariantUUIDcreation, invariantUUIDcertify); + assertEquals(version, "1.0"); + + } + + // US672129 Benny + private void getServiceValidateInvariantUuid(String serviceUniqueId, String invariantUUIDcreation) + throws Exception { + RestResponse getService = ServiceRestUtils.getService(serviceUniqueId, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, getService.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(getService)); + } + + @Test // invariantUUID generated when the component is created and never + // changed + public void serviceInvariantUuid() throws Exception { + User designerUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + User testerUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + User pmUser = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1); + Component resourceDetailsVFCcomp = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVFCcomp, UserRoleEnum.DESIGNER, + true, true); + AtomicOperationUtils.changeComponentState(resourceDetailsVFCcomp, UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CERTIFY, true); + // create service + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + serviceDetails.setInvariantUUID("123456"); + RestResponse restResponse = ServiceRestUtils.createService(serviceDetails, designerUser); + assertEquals("Check response code after create resource", BaseRestUtils.STATUS_CODE_CREATED, + restResponse.getErrorCode().intValue()); + Service service = ResponseParser.parseToObjectUsingMapper(restResponse.getResponse(), Service.class); + // invariantUUID generated when the component is created and never + // changed + String invariantUUIDcreation = ResponseParser.getInvariantUuid(restResponse); + // Add VF instance to service + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVFCcomp, service, + UserRoleEnum.DESIGNER, true); + // get resource and verify InvariantUuid is not changed + getServiceValidateInvariantUuid(service.getUniqueId(), invariantUUIDcreation); + + // Update service with new invariant UUID + restResponse = ServiceRestUtils.updateService(serviceDetails, designerUser); + assertEquals("Check response code after create resource", BaseRestUtils.STATUS_CODE_SUCCESS, + restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // Checkin + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, LifeCycleStatesEnum.CHECKIN); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // Checkout + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, + LifeCycleStatesEnum.CHECKOUT); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // certification request + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // start certification + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, testerUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // certify + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, testerUser, LifeCycleStatesEnum.CERTIFY); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // update resource + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, + LifeCycleStatesEnum.CHECKOUT); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + serviceDetails.setDescription("updatedDescription"); + restResponse = ServiceRestUtils.updateService(serviceDetails, designerUser); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // certification request + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // Checkout + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, + LifeCycleStatesEnum.CHECKOUT); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // certification request + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // start certification + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, testerUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // cancel certification + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, testerUser, + LifeCycleStatesEnum.CANCELCERTIFICATION); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // start certification + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, testerUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // failure + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, testerUser, + LifeCycleStatesEnum.FAILCERTIFICATION); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // Checkout + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, + LifeCycleStatesEnum.CHECKOUT); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // Checkin + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, LifeCycleStatesEnum.CHECKIN); + assertEquals(BaseRestUtils.STATUS_CODE_SUCCESS, restResponse.getErrorCode().intValue()); + assertEquals(invariantUUIDcreation, ResponseParser.getInvariantUuid(restResponse)); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + // create instance + ProductReqDetails productDetails = ElementFactory.getDefaultProduct(); + RestResponse createProductResponse = ProductRestUtils.createProduct(productDetails, pmUser); + assertEquals(BaseRestUtils.STATUS_CODE_CREATED, createProductResponse.getErrorCode().intValue()); + ComponentInstanceReqDetails serviceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(serviceDetails); + RestResponse createServiceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + serviceInstanceReqDetails, pmUser, productDetails.getUniqueId(), ComponentTypeEnum.PRODUCT); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_CREATED, + createServiceInstanceResponse.getErrorCode().intValue()); + getServiceValidateInvariantUuid(serviceDetails.getUniqueId(), invariantUUIDcreation); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetAllServiceVersions.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetAllServiceVersions.java new file mode 100644 index 0000000000..3460cd6e04 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetAllServiceVersions.java @@ -0,0 +1,351 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.service; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.cassandra.transport.Event.SchemaChange.Target; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.lifecycle.LCSbaseTest; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class GetAllServiceVersions extends ComponentBaseTest { + protected ResourceReqDetails resourceDetails; + protected ServiceReqDetails serviceDetails; + protected User sdncDesignerDetails; + protected User sdncDesignerDetails2; + protected User sdncAdminDetails; + protected User sdncGovernorDeatails; + protected User sdncTesterDetails; + protected User sdncOpsDetails; + protected ComponentInstanceReqDetails resourceInstanceReqDetails; + protected Component resourceDetailsVFCcomp; + protected Service serviceServ; + + @Rule + public static TestName name = new TestName(); + + public GetAllServiceVersions() { + super(name, GetAllServiceVersions.class.getName()); + ; + } + + @BeforeMethod + public void setUp() throws Exception { + + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncDesignerDetails2 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2); + sdncAdminDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncGovernorDeatails = ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR); + sdncTesterDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + sdncOpsDetails = ElementFactory.getDefaultUser(UserRoleEnum.OPS); + resourceDetailsVFCcomp = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVFCcomp, UserRoleEnum.DESIGNER, + true, true); + + AtomicOperationUtils.changeComponentState(resourceDetailsVFCcomp, UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CERTIFY, true); + serviceServ = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVFCcomp, serviceServ, + UserRoleEnum.DESIGNER, true); + + serviceDetails = new ServiceReqDetails(serviceServ); + + } + + @Test + public void GetAllServiceVersions_Version05() throws Exception { + + Map origVersionsMap = new HashMap(); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + for (int x = 0; x < 4; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + + } + // validate get response + RestResponse serviceGetResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + Service res = ResponseParser.convertServiceResponseToJavaObject(serviceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + + } + + @Test + public void GetAllServiceVersions_Version01() throws Exception { + + Map origVersionsMap = new HashMap(); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + + RestResponse serviceGetResponse = ServiceRestUtils.getService(serviceDetails, sdncDesignerDetails); + Service res = ResponseParser.convertServiceResponseToJavaObject(serviceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + } + + @Test + public void GetAllServiceVersions_Version15() throws Exception { + // addMandatoryArtifactsToService(); + Map origVersionsMap = new HashMap(); + for (int x = 0; x < 4; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + } + + RestResponse changeServiceState = LCSbaseTest.certifyService(serviceDetails, sdncDesignerDetails); + // serviceServ.setUniqueId(serviceDetails.getUniqueId()); + // RestResponse changeServiceState = + // AtomicOperationUtils.changeComponentState(serviceServ, + // UserRoleEnum.ADMIN, LifeCycleStatesEnum.CERTIFY, false).getRight(); + + assertTrue("certify service request returned status:" + changeServiceState.getErrorCode(), + changeServiceState.getErrorCode() == 200); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + + for (int x = 0; x < 5; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + + } + + // validate get response + RestResponse serviceGetResponse = ServiceRestUtils.getService(serviceDetails, sdncAdminDetails); + Service res = ResponseParser.convertServiceResponseToJavaObject(serviceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + } + + @Test + public void GetAllServiceVersions_Version25() throws Exception { + // addMandatoryArtifactsToService(); + Map origVersionsMap = new HashMap(); + for (int x = 0; x < 4; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + } + + // getting to version 1.0 + RestResponse changeServiceState = LCSbaseTest.certifyService(serviceDetails, sdncDesignerDetails); + assertTrue("certify service request returned status:" + changeServiceState.getErrorCode(), + changeServiceState.getErrorCode() == 200); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + + // getting to version 1.5 + for (int x = 0; x < 5; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + } + + // getting to version 2.0 + changeServiceState = LCSbaseTest.certifyService(serviceDetails, sdncDesignerDetails); + assertTrue("certify service request returned status:" + changeServiceState.getErrorCode(), + changeServiceState.getErrorCode() == 200); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + + // getting to version 2.5 + for (int x = 0; x < 5; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + } + + // validate get response + RestResponse serviceGetResponse = ServiceRestUtils.getService(serviceDetails, sdncAdminDetails); + Service res = ResponseParser.convertServiceResponseToJavaObject(serviceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + } + + @Test + public void GetAllServiceVersions_ReadyForCertification_version05() throws Exception { + // addMandatoryArtifactsToService(); + Map origVersionsMap = new HashMap(); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + for (int x = 0; x < 4; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + } + + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + + // validate get response + RestResponse serviceGetResponse = ServiceRestUtils.getService(serviceDetails, sdncAdminDetails); + Service res = ResponseParser.convertServiceResponseToJavaObject(serviceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + } + + @Test + public void GetAllServiceVersions_CertifactionInProgress_version05() throws Exception { + // addMandatoryArtifactsToService(); + Map origVersionsMap = new HashMap(); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + for (int x = 0; x < 4; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + } + + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncAdminDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.STARTCERTIFICATION); + + // validate get response + RestResponse serviceGetResponse = ServiceRestUtils.getService(serviceDetails, sdncAdminDetails); + Service res = ResponseParser.convertServiceResponseToJavaObject(serviceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + } + + @Test + public void GetAllServiceVersions_Certified_version10() throws Exception { + // addMandatoryArtifactsToService(); + Map origVersionsMap = new HashMap(); + // get to version 0.5 + for (int x = 0; x < 4; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + + } + + // get version 1.0 + RestResponse changeServiceState = LCSbaseTest.certifyService(serviceDetails, sdncDesignerDetails); + assertTrue("certify service request returned status:" + changeServiceState.getErrorCode(), + changeServiceState.getErrorCode() == 200); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + + // validate get response + RestResponse serviceGetResponse = ServiceRestUtils.getService(serviceDetails, sdncAdminDetails); + Service res = ResponseParser.convertServiceResponseToJavaObject(serviceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + } + + @Test + public void GetAllServiceVersions_Certified_version20() throws Exception { + // addMandatoryArtifactsToService(); + Map origVersionsMap = new HashMap(); + // get to version 0.5 + for (int x = 0; x < 4; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + } + + // get version 1.0 + RestResponse changeServiceState = LCSbaseTest.certifyService(serviceDetails, sdncDesignerDetails); + assertTrue("certify service request returned status:" + changeServiceState.getErrorCode(), + changeServiceState.getErrorCode() == 200); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + + // get version 1.5 + for (int x = 0; x < 4; x++) { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + } + + // get version 2.0 + changeServiceState = LCSbaseTest.certifyService(serviceDetails, sdncDesignerDetails); + assertTrue("certify service request returned status:" + changeServiceState.getErrorCode(), + changeServiceState.getErrorCode() == 200); + origVersionsMap.put(serviceDetails.getVersion(), serviceDetails.getUniqueId()); + + // validate get response + RestResponse serviceGetResponse = ServiceRestUtils.getService(serviceDetails, sdncAdminDetails); + Service res = ResponseParser.convertServiceResponseToJavaObject(serviceGetResponse.getResponse()); + Map getVersionsMap = res.getAllVersions(); + assertTrue(origVersionsMap.equals(getVersionsMap)); + } + + @Test + public void GetAllServiceVersions_ServiceNotFound() throws Exception { + + RestResponse serviceGetResponse = ServiceRestUtils.getService("123456789", sdncAdminDetails); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.SERVICE_NOT_FOUND.name()); + assertEquals("Check response code after get service without cache", errorInfo.getCode(), + serviceGetResponse.getErrorCode()); + + List variables = Arrays.asList("123456789"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_FOUND.name(), variables, + serviceGetResponse.getResponse()); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetComponentAuditApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetComponentAuditApiTest.java new file mode 100644 index 0000000000..5642ce4745 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetComponentAuditApiTest.java @@ -0,0 +1,371 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.service; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.http.HttpStatus; +import org.apache.log4j.lf5.util.ResourceUtils; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.general.FileUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.datastructure.Wrapper; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import fj.data.Either; + +public class GetComponentAuditApiTest extends ComponentBaseTest { + + public static final String SERVICES_API = "services"; + public static final String RESOURCES_API = "resources"; + + protected User sdncAdminUser; + protected User sdncDesignerUser; + protected User sdncTesterUser; + + @Rule + public static TestName name = new TestName(); + + public GetComponentAuditApiTest() { + super(name, GetComponentAuditApiTest.class.getName()); + } + + // in case tests fail, run this method as test to create mapping in ES + public void updateElasticSearchMapping() throws IOException { + Either fileContentUTF8 = FileUtils + .getFileContentUTF8("src\\test\\resources\\CI\\other\\mapping.json"); + AssertJUnit.assertTrue(fileContentUTF8.isLeft()); + + final String ES_TEMPLATE_URL = "http://%s:%s/_template/audit_template"; + String url = String.format(ES_TEMPLATE_URL, config.getEsHost(), config.getEsPort()); + + RestResponse sendHttpPost = new HttpRequest().sendHttpPost(url, fileContentUTF8.left().value(), null); + AssertJUnit.assertTrue(sendHttpPost.getErrorCode() == HttpStatus.SC_OK); + } + + @BeforeMethod + public void init() { + sdncAdminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncDesignerUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncTesterUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + ; + + } + + @Test + public void testServiceAuditCertifiedVersion() throws Exception { + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + Wrapper versionZeroOneIDWrapper = new Wrapper(), + versionZeroTwoIDWrapper = new Wrapper(); + + createBasicServiceForAudit(versionZeroOneIDWrapper, versionZeroTwoIDWrapper, serviceDetails, true); + // First Certification + + LifecycleRestUtils.certifyService(serviceDetails); + // LCSbaseTest.certifyService(serviceDetails); + AssertJUnit.assertTrue(serviceDetails.getVersion().equals("1.0")); + + // Second Certification + increaseServiceVersion(serviceDetails, "1.1"); + increaseServiceVersion(serviceDetails, "1.2"); + increaseServiceVersion(serviceDetails, "1.3"); + increaseServiceVersion(serviceDetails, "1.4"); + LifecycleRestUtils.certifyService(serviceDetails); + AssertJUnit.assertTrue(serviceDetails.getVersion().equals("2.0")); + String certifiedId = serviceDetails.getUniqueId(); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerUser, LifeCycleStatesEnum.CHECKOUT); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerUser, LifeCycleStatesEnum.CHECKIN); + + JsonElement element = getAuditJson(SERVICES_API, certifiedId); + // audits kept: 5*check ins + 4*check outs + 2*artifact payload + // updates(tosca) + certification request + certification start + + // certification success + // + 3 A&AI(ArtifactDelete, ArtifactUpload, ArtifactUpdate) + List actions = new ArrayList<>(); + JsonArray jsonArray = element.getAsJsonArray(); + for( int i =0 ; i < jsonArray.size(); i++){ + actions.add(jsonArray.get(i).getAsJsonObject().get(AuditingFieldsKeysEnum.AUDIT_ACTION.getDisplayName()).getAsString()); + } + long checkinCount = actions.stream().filter( e -> e.equals(AuditingActionEnum.CHECKIN_RESOURCE.getName())).count(); + assertTrue(checkinCount == 5); + + long checkOutCount = actions.stream().filter( e -> e.equals(AuditingActionEnum.CHECKOUT_RESOURCE.getName())).count(); + assertTrue(checkOutCount == 4); + + long certificationRequestCount = actions.stream().filter( e -> e.equals(AuditingActionEnum.CERTIFICATION_REQUEST_RESOURCE.getName())).count(); + assertTrue(certificationRequestCount == 1); + + long certificationStartCount = actions.stream().filter( e -> e.equals(AuditingActionEnum.START_CERTIFICATION_RESOURCE.getName())).count(); + assertTrue(certificationStartCount == 1); + + long certificationSuccessCount = actions.stream().filter( e -> e.equals(AuditingActionEnum.CERTIFICATION_SUCCESS_RESOURCE.getName())).count(); + assertTrue(certificationSuccessCount == 1); + + + } + + protected void certifyResource(ResourceReqDetails defaultResource) throws IOException { + RestResponse response = LifecycleRestUtils.changeResourceState(defaultResource, sdncDesignerUser, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + response = LifecycleRestUtils.changeResourceState(defaultResource, sdncTesterUser, + LifeCycleStatesEnum.STARTCERTIFICATION); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + response = LifecycleRestUtils.changeResourceState(defaultResource, sdncTesterUser, LifeCycleStatesEnum.CERTIFY); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + } + + protected JsonElement getAuditJson(String componentType, String componentId) throws IOException { + Map headers = new HashMap() { + { + put(Constants.USER_ID_HEADER, UserRoleEnum.ADMIN.getUserId()); + } + }; + String url = String.format(Urls.GET_COMPONENT_AUDIT_RECORDS, config.getCatalogBeHost(), + config.getCatalogBePort(), componentType, componentId); + + RestResponse httpSendGet = new HttpRequest().httpSendGet(url, headers); + AssertJUnit.assertTrue(httpSendGet.getErrorCode() == HttpStatus.SC_OK); + JsonElement element = ResponseParser.parseToObject(httpSendGet.getResponse(), JsonElement.class); + AssertJUnit.assertTrue(element.isJsonArray()); + return element; + } + + protected void createBasicServiceForAudit(Wrapper versionZeroOneIDWrapper, + Wrapper versionZeroTwoIDWrapper, ServiceReqDetails serviceDetails, Boolean withResInst) + throws Exception { + + User designerUser = sdncDesignerUser; + + RestResponse response = ServiceRestUtils.createService(serviceDetails, designerUser); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_CREATED); + versionZeroOneIDWrapper.setInnerElement(serviceDetails.getUniqueId()); + + if (withResInst) { + Resource resourceObj = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceObj, UserRoleEnum.DESIGNER, true, + true); + AtomicOperationUtils.changeComponentState(resourceObj, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, + true); + ResourceReqDetails resource = new ResourceReqDetails(resourceObj); + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory.getDefaultComponentInstance(); + resourceInstanceReqDetails.setComponentUid(resource.getUniqueId()); + ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, sdncDesignerUser, + serviceDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + + // ServiceUtils.createCertResourceWithDeploymentArt(serviceDetails, + // "myResource"); + } + + response = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + AssertJUnit.assertTrue(serviceDetails.getVersion().equals("0.1")); + + response = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, LifeCycleStatesEnum.CHECKOUT); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + // ServiceUtils.addServiceDeploymentArtifact(serviceDetails.getUniqueId(), + // designerUser); + versionZeroTwoIDWrapper.setInnerElement(serviceDetails.getUniqueId()); + AssertJUnit.assertTrue(serviceDetails.getVersion().equals("0.2")); + response = LifecycleRestUtils.changeServiceState(serviceDetails, designerUser, LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + + increaseServiceVersion(serviceDetails, "0.3"); + + increaseServiceVersion(serviceDetails, "0.4"); + + increaseServiceVersion(serviceDetails, "0.5"); + + } + + protected void increaseServiceVersion(ServiceReqDetails serviceDetails, String excpectedVersion) throws Exception { + RestResponse response = LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerUser, + LifeCycleStatesEnum.CHECKOUT); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + AssertJUnit.assertTrue(serviceDetails.getVersion().equals(excpectedVersion)); + response = LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerUser, LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + } + + protected void createBasicResourceForAudit(Wrapper versionOnePointTwoIDWrapper, + ResourceReqDetails defaultResource) throws Exception { + + RestResponse response = ResourceRestUtils.createResource(defaultResource, sdncDesignerUser); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_CREATED); + + // ArtifactDefinition artifactDef = new + // ArtifactUtils().constructDefaultArtifactInfo(); + // response = resourceUtils.add_artifact(defaultResource, + // sdncDesignerUser, defaultResource.getVersion(), artifactDef); + // assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerUser, + defaultResource.getUniqueId()); + AssertJUnit.assertTrue("add HEAT artifact to resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + response = LifecycleRestUtils.changeResourceState(defaultResource, sdncDesignerUser, + LifeCycleStatesEnum.CHECKIN); + + increaseResourceVersion(defaultResource, "0.2"); + + increaseResourceVersion(defaultResource, "0.3"); + + increaseResourceVersion(defaultResource, "0.4"); + + increaseResourceVersion(defaultResource, "0.5"); + + certifyResource(defaultResource); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + AssertJUnit.assertTrue(defaultResource.getVersion().equals("1.0")); + + increaseResourceVersion(defaultResource, "1.1"); + + increaseResourceVersion(defaultResource, "1.2"); + versionOnePointTwoIDWrapper.setInnerElement(defaultResource.getUniqueId()); + + increaseResourceVersion(defaultResource, "1.3"); + + increaseResourceVersion(defaultResource, "1.4"); + + } + + protected void increaseResourceVersion(ResourceReqDetails defaultResource, String expectedVersion) + throws IOException { + RestResponse response = LifecycleRestUtils.changeResourceState(defaultResource, sdncDesignerUser, + LifeCycleStatesEnum.CHECKOUT); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + AssertJUnit.assertTrue(defaultResource.getVersion().equals(expectedVersion)); + response = LifecycleRestUtils.changeResourceState(defaultResource, sdncDesignerUser, + LifeCycleStatesEnum.CHECKIN); + AssertJUnit.assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + } + + @Test + public void testServiceAuditLastUncertifiedVersion() throws Exception { + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + Wrapper versionZeroOneIDWrapper = new Wrapper(), + versionZeroTwoIDWrapper = new Wrapper(); + + createBasicServiceForAudit(versionZeroOneIDWrapper, versionZeroTwoIDWrapper, serviceDetails, false); + + JsonElement element = getAuditJson(SERVICES_API, versionZeroTwoIDWrapper.getInnerElement()); + + assertTrue(element.getAsJsonArray().size() == 3); + + } + + @Test + public void testServiceAuditFirstUncertifiedVersion() throws Exception { + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + Wrapper versionZeroOneIDWrapper = new Wrapper(), + versionZeroTwoIDWrapper = new Wrapper(); + + createBasicServiceForAudit(versionZeroOneIDWrapper, versionZeroTwoIDWrapper, serviceDetails, false); + + JsonElement element = getAuditJson(SERVICES_API, versionZeroOneIDWrapper.getInnerElement()); + + assertTrue(element.getAsJsonArray().size() == 3); + + } + + @Test + public void testResourceAuditUncertifiedVersion() throws Exception { + + ResourceReqDetails defaultResource = ElementFactory.getDefaultResource(); + Wrapper versionOnePointTwoIDWrapper = new Wrapper(); + + createBasicResourceForAudit(versionOnePointTwoIDWrapper, defaultResource); + + JsonElement element = getAuditJson(RESOURCES_API, versionOnePointTwoIDWrapper.getInnerElement()); + + assertTrue(element.getAsJsonArray().size() == 3); + + } + + @Test + public void testResourceAuditCertifiedVersion() throws Exception { + + ResourceReqDetails defaultResource = ElementFactory.getDefaultResource(); + Wrapper versionOnePointTwoIDWrapper = new Wrapper(); + + createBasicResourceForAudit(versionOnePointTwoIDWrapper, defaultResource); + + certifyResource(defaultResource); + assertTrue(defaultResource.getVersion().equals("2.0")); + String certifiedId = defaultResource.getUniqueId(); + + increaseResourceVersion(defaultResource, "2.1"); + + increaseResourceVersion(defaultResource, "2.2"); + + JsonElement element = getAuditJson(RESOURCES_API, certifiedId); + + assertTrue(element.getAsJsonArray().size() == 13); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetServiceLatestVersionTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetServiceLatestVersionTest.java new file mode 100644 index 0000000000..55ecf694ee --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/GetServiceLatestVersionTest.java @@ -0,0 +1,685 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.service; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_RESTRICTED_OPERATION; +import static org.testng.AssertJUnit.assertNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentInstanceBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +public class GetServiceLatestVersionTest extends ComponentInstanceBaseTest { + + protected ArtifactReqDetails heatArtifactDetails; + + @Rule + public static TestName name = new TestName(); + + public GetServiceLatestVersionTest() { + super(name, GetServiceLatestVersionTest.class.getName()); + } + + @BeforeMethod + public void before() throws Exception { + initMembers(); + createAtomicResource(resourceDetailsVFC_01); + changeResourceStateToCertified(resourceDetailsVFC_01); + createAtomicResource(resourceDetailsCP_01); + changeResourceStateToCertified(resourceDetailsCP_01); + createAtomicResource(resourceDetailsVL_01); + changeResourceStateToCertified(resourceDetailsVL_01); + createVF(resourceDetailsVF_01); + certifyVf(resourceDetailsVF_01); + createService(serviceDetails_01); + createService(serviceDetails_02); + createService(serviceDetails_03); + createProduct(productDetails_01); + createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF_01, sdncDesignerDetails); // create + // certified + // VF + // instance + // in + // service + /* + * RestResponse restResponse = + * LifecycleRestUtils.changeServiceState(serviceDetails_01, + * sdncDesignerDetails, LifeCycleStates.CHECKIN); + * ResourceRestUtils.checkSuccess(restResponse); + */ + } + + public void initMembers() throws Exception { + heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + sdncPsDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1); + sdncPmDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1); + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncAdminDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncTesterDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + resourceDetailsVFC_01 = ElementFactory.getDefaultResourceByType("VFC100", NormativeTypesEnum.COMPUTE, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.VFC.toString()); // resourceType = VFC + resourceDetailsVF_01 = ElementFactory.getDefaultResourceByType("VF100", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.VF.toString()); + resourceDetailsCP_01 = ElementFactory.getDefaultResourceByType("CP100", NormativeTypesEnum.PORT, + ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.CP.toString()); + resourceDetailsVL_01 = ElementFactory.getDefaultResourceByType("VL100", NormativeTypesEnum.NETWORK, + ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.VL.toString()); + serviceDetails_01 = ElementFactory.getDefaultService("newtestservice1", ServiceCategoriesEnum.MOBILITY, + sdncDesignerDetails.getUserId()); + serviceDetails_02 = ElementFactory.getDefaultService("newtestservice2", ServiceCategoriesEnum.MOBILITY, + sdncDesignerDetails.getUserId()); + serviceDetails_03 = ElementFactory.getDefaultService("newtestservice3", ServiceCategoriesEnum.MOBILITY, + sdncDesignerDetails.getUserId()); + productDetails_01 = ElementFactory.getDefaultProduct("product01"); + } + + @Test + public void getServicesLatestVersionServiceInCheckOutState() throws Exception { + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncPsDetails1); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertNull("No Service returned, one service in checkout state 0.1", servcieFromList); + } + + @Test + public void getServicesLatestVersionServiceInCheckInState() throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncPsDetails1); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("0.1")); + } + + @Test + public void getServicesLatestVersionByPm() throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncPmDetails1); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("0.1")); + } + + @Test + public void getServicesLatestVersionByAdmin() throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncAdminDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("0.1")); + } + + @Test + public void getServicesLatestVersionService02CheckOutState() throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + String serviceUniqueID = ResponseParser.getUniqueIdFromResponse(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ResourceRestUtils.checkSuccess(restResponse); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceUniqueID); + assertTrue(servcieFromList.getVersion().equals("0.1")); + servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertNull(servcieFromList); + } + + @Test + public void getServicesLatestVersionService02CheckInState() throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("0.2")); + } + + @Test + public void getServicesLatestVersionServiceWaitingForCertification() throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + ResourceRestUtils.checkSuccess(restResponse); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("0.2")); + } + + @Test + public void getServicesLatestVersionServiceCertificationInProgress() throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncTesterDetails, + LifeCycleStatesEnum.STARTCERTIFICATION); + ResourceRestUtils.checkSuccess(restResponse); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("0.2")); + } + + @Test + public void getServicesLatestVersionServiceCertificationFail() throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncTesterDetails, + LifeCycleStatesEnum.STARTCERTIFICATION); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncTesterDetails, + LifeCycleStatesEnum.FAILCERTIFICATION); + ResourceRestUtils.checkSuccess(restResponse); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("0.2")); + } + + @Test + public void getServicesLatestVersionServiceCertifed() throws Exception { + certifyService(serviceDetails_01); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("1.0")); + } + + @Test + public void getLatestVersionServiceHasSeveralCertifedVersion_01() throws Exception { + RestResponse certifyServiceResponse; + String serviceUniqueIdFromResponse = null; + int numberOfCertifiedService = 3; + for (int i = 0; i < numberOfCertifiedService; i++) { + certifyServiceResponse = certifyService(serviceDetails_01); + ServiceRestUtils.checkSuccess(certifyServiceResponse); + if (i == (numberOfCertifiedService - 1)) { + serviceUniqueIdFromResponse = ResponseParser.getUniqueIdFromResponse(certifyServiceResponse); + } + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + } + // We have service with following versions : 1.0, 2.0 ,3.0 and + // 3.1(checkedOut) + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceUniqueIdFromResponse); + assertTrue(servcieFromList.getVersion().equals("3.0")); + } + + @Test + public void getLatestVersionServiceHasSeveralCertifedVersions02() throws Exception { + RestResponse certifyServiceResponse; + certifyServiceResponse = certifyService(serviceDetails_01); + ServiceRestUtils.checkSuccess(certifyServiceResponse); + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + certifyServiceResponse = certifyService(serviceDetails_01); + ServiceRestUtils.checkSuccess(certifyServiceResponse); + // We have service with following versions : 1.0, 2.0 + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("2.0")); + } + + @Test + public void getLatestVersionServiceCertifedWasCheckedOutAndCheckedin() throws Exception { + RestResponse certifyServiceResponse; + int numberOfCertifiedService = 3; + for (int i = 0; i < numberOfCertifiedService; i++) { + certifyServiceResponse = certifyService(serviceDetails_01); + ServiceRestUtils.checkSuccess(certifyServiceResponse); + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + } + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); + // We have service with following versions : 1.0, 2.0 and 2.1(checkedIn) + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("3.1")); + } + + @Test + public void getLatestVersionServiceCheckOutCertifedService() throws Exception { + RestResponse restResponse; + String serviceUniqueIdFromResponse = null; + RestResponse certifyServiceResponse = certifyService(serviceDetails_01); + ServiceRestUtils.checkSuccess(certifyServiceResponse); + for (int i = 0; i < 11; i++) { + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); + if (i == (10)) { + serviceUniqueIdFromResponse = ResponseParser.getUniqueIdFromResponse(restResponse); + } + } + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + // We have service with following versions : 1.0 and 1.11(Check-out) + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceUniqueIdFromResponse); + assertTrue(servcieFromList.getVersion().equals("1.11")); + } + + @Test + public void getLatestVersionServiceCheckOutCheckInCertifedService() throws Exception { + RestResponse restResponse; + String serviceUniqueIdFromResponse = null; + RestResponse certifyServiceResponse = certifyService(serviceDetails_01); + ServiceRestUtils.checkSuccess(certifyServiceResponse); + for (int i = 0; i < 12; i++) { + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); + if (i == (11)) { + serviceUniqueIdFromResponse = ResponseParser.getUniqueIdFromResponse(restResponse); + } + } + // We have service with following versions : 1.0 and 1.11(Check-out) + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceUniqueIdFromResponse); + assertTrue(servcieFromList.getVersion().equals("1.12")); + } + + @Test + public void getLatestVersionServiceCertifedCheckedOutAndInWaitingForCertificationState() throws Exception { + certifyService(serviceDetails_01); // 1.0 + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + ServiceRestUtils.checkSuccess(restResponse); + // We have service with following versions : 1.0 and 1.1(Waiting For + // Certification) + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("1.1")); + } + + @Test + public void getLatestVersionServiceCertifedCheckedOutAndInCertificationInProgressState() throws Exception { + certifyService(serviceDetails_01); // 1.0 + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncTesterDetails, + LifeCycleStatesEnum.STARTCERTIFICATION); + ServiceRestUtils.checkSuccess(restResponse); + // We have service with following versions : 1.0 and 1.1(Certification + // In Progress) + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("1.1")); + } + + // DE190818 + @Test(enabled = false) + public void getLatestVersionByNonAsdcUser() throws Exception { + User nonAsdcUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + nonAsdcUser.setUserId("gg750g"); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(nonAsdcUser); + assertTrue(getServicesLatestVersion.getErrorCode() == STATUS_CODE_RESTRICTED_OPERATION); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + getServicesLatestVersion.getResponse()); + } + + // DE190818 + @Test(enabled = false) + public void getLatestVersionUserIdIsEmpty() throws Exception { + User nonAsdcUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + nonAsdcUser.setUserId(""); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(nonAsdcUser); + assertTrue(getServicesLatestVersion.getErrorCode() == STATUS_CODE_RESTRICTED_OPERATION); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_OPERATION.name(), new ArrayList(), + getServicesLatestVersion.getResponse()); + } + + @Test + public void getServicesLatestVersionByTester() throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncTesterDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 1); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_01.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("0.1")); + } + + @Test + public void getLatestVersionSeveralServicesInDifferentVersion() throws Exception { + RestResponse restResponse = certifyService(serviceDetails_01); // 1.0 + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = certifyService(serviceDetails_01); + ServiceRestUtils.checkSuccess(restResponse); + String service1_UniqueIdFromResponse = ResponseParser.getUniqueIdFromResponse(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); // serviceDetails_01 + // version is 2.1 + // (check-out) + + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_02, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_02, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_02, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); // serviceDetails_02 + // version 0.2 + // (Check-in) + + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_03, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); + String service3_UniqueIdFromResponse = ResponseParser.getUniqueIdFromResponse(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails_03, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); // serviceDetails_03 + // version 0.2 + // (Check-out) + + RestResponse getServicesLatestVersion = ServiceRestUtils.getServiceLatestVersionList(sdncDesignerDetails); + ServiceRestUtils.checkSuccess(getServicesLatestVersion); + List serviceList = restResponseToResourceObjectList(getServicesLatestVersion); + assertTrue(serviceList.size() == 3); + Service servcieFromList = getResourceObjectFromResourceListByUid(serviceList, service1_UniqueIdFromResponse); + assertTrue(servcieFromList.getVersion().equals("2.0")); + servcieFromList = getResourceObjectFromResourceListByUid(serviceList, serviceDetails_02.getUniqueId()); + assertTrue(servcieFromList.getVersion().equals("0.2")); + servcieFromList = getResourceObjectFromResourceListByUid(serviceList, service3_UniqueIdFromResponse); + assertTrue(servcieFromList.getVersion().equals("0.1")); + } + + /////////////////////////////////////////////////////////////// + private RestResponse certifyService(ServiceReqDetails serviceDetails) throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKOUT); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, sdncTesterDetails, + LifeCycleStatesEnum.STARTCERTIFICATION); + ServiceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeServiceState(serviceDetails, sdncTesterDetails, + LifeCycleStatesEnum.CERTIFY); + ServiceRestUtils.checkSuccess(restResponse); + return restResponse; + } + + protected List restResponseToResourceObjectList(RestResponse restResponse) { + JsonElement jelement = new JsonParser().parse(restResponse.getResponse()); + JsonArray jsonArray = jelement.getAsJsonArray(); + List restResponseArray = new ArrayList<>(); + Service service = null; + for (int i = 0; i < jsonArray.size(); i++) { + String serviceString = (String) jsonArray.get(i).toString(); + service = ResponseParser.convertServiceResponseToJavaObject(serviceString); + restResponseArray.add(service); + } + return restResponseArray; + } + + protected Service getResourceObjectFromResourceListByUid(List serviceList, String uid) { + if (serviceList != null && serviceList.size() > 0) { + for (Service service : serviceList) { + if (service.getUniqueId().equals(uid)) + return service; + } + } else + return null; + return null; + } + + private RestResponse changeResourceStateToCertified(ResourceReqDetails resourceDetails) throws Exception { + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + if (restResponse.getErrorCode() == 200) { + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncTesterDetails, + LifeCycleStatesEnum.STARTCERTIFICATION); + } else + return restResponse; + if (restResponse.getErrorCode() == 200) { + restResponse = LifecycleRestUtils.changeResourceState(resourceDetails, sdncTesterDetails, + LifeCycleStatesEnum.CERTIFY); + if (restResponse.getErrorCode() == 200) { + String newVersion = ResponseParser.getVersionFromResponse(restResponse); + resourceDetails.setVersion(newVersion); + resourceDetails.setLifecycleState(LifecycleStateEnum.CERTIFIED); + resourceDetails.setLastUpdaterUserId(sdncTesterDetails.getUserId()); + resourceDetails.setLastUpdaterFullName(sdncTesterDetails.getFullName()); + String uniqueIdFromRresponse = ResponseParser.getValueFromJsonResponse(restResponse.getResponse(), + "uniqueId"); + resourceDetails.setUniqueId(uniqueIdFromRresponse); + } + } + return restResponse; + } + + // private void certifyVf(ResourceReqDetails resource) throws Exception { + // RestResponse createAtomicResourceInstance = + // createAtomicInstanceForVFDuringSetup(resource, resourceDetailsVFC_01, + // sdncDesignerDetails); + // ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + // createAtomicResourceInstance = + // createAtomicInstanceForVFDuringSetup(resource, resourceDetailsCP_01, + // sdncDesignerDetails); + // ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + // createAtomicResourceInstance = + // createAtomicInstanceForVFDuringSetup(resource, resourceDetailsVL_01, + // sdncDesignerDetails); + // ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + // //createVFInstanceDuringSetup(service, resource, sdncDesignerDetails); + // RestResponse response = + // ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, + // sdncDesignerDetails, resource.getUniqueId()); + // ResourceRestUtils.checkSuccess(response); + // RestResponse changeResourceStateToCertified = + // changeResourceStateToCertified(resource); + // ResourceRestUtils.checkSuccess(changeResourceStateToCertified); + // } + + private void certifyVf(ResourceReqDetails resource) throws Exception { + RestResponse createAtomicResourceInstance = createAtomicInstanceForVFDuringSetup(resource, resourceDetailsCP_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + String cpCompInstId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstance); + + createAtomicResourceInstance = createAtomicInstanceForVFDuringSetup(resource, resourceDetailsVFC_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + String computeCompInstId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstance); + + createAtomicResourceInstance = createAtomicInstanceForVFDuringSetup(resource, resourceDetailsVL_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + String vlCompInstId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstance); + + // Fixing Vl/Cp req/cap + ComponentTypeEnum containerCompType = ComponentTypeEnum.RESOURCE; + User user = sdncDesignerDetails; + fulfillCpRequirement(resource, cpCompInstId, computeCompInstId, computeCompInstId, user, containerCompType); + consumeVlCapability(resource, cpCompInstId, vlCompInstId, cpCompInstId, user, containerCompType); + + RestResponse response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, + sdncDesignerDetails, resource.getUniqueId()); + ResourceRestUtils.checkSuccess(response); + RestResponse changeResourceStateToCertified = changeResourceStateToCertified(resource); + ResourceRestUtils.checkSuccess(changeResourceStateToCertified); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ReqCapOccurrencesTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ReqCapOccurrencesTest.java new file mode 100644 index 0000000000..c21deafcd8 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ReqCapOccurrencesTest.java @@ -0,0 +1,1191 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.service; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; + +import org.apache.http.client.ClientProtocolException; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.RelationshipImpl; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentInstanceBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.general.ImportUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class ReqCapOccurrencesTest extends ComponentInstanceBaseTest { + + private ImportReqDetails importReqDetails1; // atomic resource + private ImportReqDetails importReqDetails2; + private ImportReqDetails importReqDetails3; + private ImportReqDetails importReqDetails4; + private Resource resourceVFC1; + private Resource resourceVFC2; + private Resource resourceVFC3; + private Resource resourceVFC4; + private ResourceReqDetails resourceDetailsVF100; + private ResourceReqDetails resourceDetailsVF200; + private Resource resourceVF100; + private Resource resourceVF200; + protected String testResourcesPath; + + protected final String importYmlWithReq11 = "softwareComponentReq11.yml"; + protected final String importYmlWithReq12 = "softwareComponentReq12.yml"; + protected final String importYmlWithCap11 = "computeCap11.yml"; + protected final String importYmlWithCap1Unbounded = "computeCap1UNBOUNDED.yml"; + protected final String capabilitiesAndRequirementsType = "tosca.capabilities.Container"; + + public ReqCapOccurrencesTest() { + super(new TestName(), ReqCapOccurrencesTest.class.getSimpleName()); + } + + @BeforeMethod + public void before() throws Exception { + // Do not use call init() from ComponentInstanceBaseTest + expectedContainerCapabilities = new LinkedHashMap>(); + expectedContainerRequirements = new LinkedHashMap>(); + removedRequirements = new HashMap<>(); + expectedContInstReqCap = new HashMap<>(); + + RestResponse importResourceResponse; + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncAdminDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // import yml file location + String sourceDir = config.getResourceConfigDir(); + final String workDir = "importToscaResourceByCreateUrl"; + testResourcesPath = sourceDir + File.separator + workDir; + ///// Create atomic resources ///////////////////////// + // import VFC1 with Requirements : MIN=1 MAX=2 + ///// (tosca.capabilities.Container) + importReqDetails1 = ElementFactory.getDefaultImportResource("VFC1"); + importResourceResponse = importedResource(importReqDetails1, importYmlWithReq12); + // resourceVFC1 = + // ResponseParser.convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + RestResponse restResponse = LifecycleRestUtils.changeResourceState(importReqDetails1, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + resourceVFC1 = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + // import VFC2 with Capabilities : MIN 1 MAX UNBOUNDED + // (tosca.capabilities.Container) + importReqDetails2 = ElementFactory.getDefaultImportResource("VFC2"); + importResourceResponse = importedResource(importReqDetails2, importYmlWithCap1Unbounded); + // resourceVFC2 = + // ResponseParser.convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + restResponse = LifecycleRestUtils.changeResourceState(importReqDetails2, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + resourceVFC2 = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + // import VFC3 with Capabilities : MIN 1 MAX 1 + // (tosca.capabilities.Container) + importReqDetails3 = ElementFactory.getDefaultImportResource("VFC3"); + importResourceResponse = importedResource(importReqDetails3, importYmlWithCap11); + // resourceVFC3 = + // ResponseParser.convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + restResponse = LifecycleRestUtils.changeResourceState(importReqDetails3, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + resourceVFC3 = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + // import VFC4 with Requirements : MIN 1 MAX 1 + // (tosca.capabilities.Container) + importReqDetails4 = ElementFactory.getDefaultImportResource("VFC4"); + importResourceResponse = importedResource(importReqDetails4, importYmlWithReq11); + // resourceVFC4 = + // ResponseParser.convertResourceResponseToJavaObject(importResourceResponse.getResponse()); + restResponse = LifecycleRestUtils.changeResourceState(importReqDetails4, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + resourceVFC4 = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + + // create VF100 + resourceDetailsVF100 = ElementFactory.getDefaultResourceByType("VF1000", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.VF.toString()); + RestResponse createResourceVF100 = ResourceRestUtils.createResource(resourceDetailsVF100, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createResourceVF100); + // create VF200 + resourceDetailsVF200 = ElementFactory.getDefaultResourceByType("VF2000", NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, sdncDesignerDetails.getUserId(), + ResourceTypeEnum.VF.toString()); + RestResponse createResourceVF200 = ResourceRestUtils.createResource(resourceDetailsVF200, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createResourceVF200); + // Create Service + serviceDetails_01 = ElementFactory.getDefaultService("newtestservice1", ServiceCategoriesEnum.MOBILITY, + sdncDesignerDetails.getUserId()); + RestResponse createServiceRestResponse = ServiceRestUtils.createService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createServiceRestResponse); + + } + + // US628514 Capability/Requirement "Occurrences" attribute in CREATE/DELETE + // Relation APIs + // Container = SERVICE , Container instance = VF + @Test + public void capAndReqOccurrencesInServiceAndHisInstancesNoAssociation() throws Exception, Exception { + RestResponse getResourseRestResponse; + // Add instance of VFC1 (Req MIN=1 MAX=2) to VF1000 + ComponentInstance componentInstanceReq = createComponentInstance(importReqDetails1, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceReq); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Add instance of VFC21 (Cap MIN=1 MAX=UNBOUNDED) to VF2000 + ComponentInstance componentInstanceCap = createComponentInstance(importReqDetails2, sdncDesignerDetails, + resourceDetailsVF200); + assertNotNull(componentInstanceCap); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF200.getUniqueId()); + resourceVF200 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Check-In both VFs + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF100, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF200, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + // Create VF instances + RestResponse createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF100, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF200, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + // get service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + // Verify Container requirements and Capabilities + String containerMinReq = "1"; + String containerMaxReq = "2"; + String containerMinCap = "1"; + String containerMaxCap = "UNBOUNDED"; + verifyContainerCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, containerMinReq, + containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, + resourceVF200, resourceVF100); + } + + @Test + public void serviceInstanceAssociationReqMaxOccurrencesNotReached() throws Exception, Exception { + RestResponse getResourseRestResponse; + // Add instance of VFC1 (Req MIN=1 MAX=2) to VF1000 + ComponentInstance componentInstanceReq = createComponentInstance(importReqDetails1, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceReq); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Add instance of VFC2 (Cap MIN=1 MAX=UNBOUNDED) to VF2000 + ComponentInstance componentInstanceCap = createComponentInstance(importReqDetails2, sdncDesignerDetails, + resourceDetailsVF200); + assertNotNull(componentInstanceCap); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF200.getUniqueId()); + resourceVF200 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Check-In both VFs + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF100, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF200, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + // Create VF instances + RestResponse createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF100, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String fromCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF200, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String toCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // associate 2 VFs + String capType = capabilitiesAndRequirementsType; + String reqName = "host"; + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + RequirementCapabilityRelDef requirementDef = getReqCapRelation(fromCompInstId, toCompInstId, capType, reqName, + capList, reqList, componentInstanceReq.getUniqueId(), componentInstanceCap.getUniqueId()); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(associateInstances); + // get service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "1"; + String containerMinCap = "0"; + String containerMaxCap = "UNBOUNDED"; + verifyContainerCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, containerMinReq, + containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, + resourceVF200, resourceVF100); + } + + @Test + public void serviceInstanceAssociationReqMaxOccurrencesIsReached() throws Exception, Exception { + RestResponse getResourseRestResponse; + // Add instance of VFC4 (Req MIN=1 MAX=1) to VF1000 + ComponentInstance componentInstanceReq = createComponentInstance(importReqDetails4, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceReq); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Add instance of VFC2 (Cap MIN=1 MAX=UNBOUNDED) to VF2000 + ComponentInstance componentInstanceCap = createComponentInstance(importReqDetails2, sdncDesignerDetails, + resourceDetailsVF200); + assertNotNull(componentInstanceCap); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF200.getUniqueId()); + resourceVF200 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Check-In both VFs + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF100, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF200, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + // Create VF instances + RestResponse createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF100, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String fromCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF200, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String toCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // associate 2 VFs + String capType = capabilitiesAndRequirementsType; + String reqName = "host"; + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + RequirementCapabilityRelDef requirementDef = getReqCapRelation(fromCompInstId, toCompInstId, capType, reqName, + capList, reqList, componentInstanceReq.getUniqueId(), componentInstanceCap.getUniqueId()); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(associateInstances); + // get service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "0"; + String containerMinCap = "0"; + String containerMaxCap = "UNBOUNDED"; + verifyContainerCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, containerMinReq, + containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, + resourceVF200, resourceVF100); + } + + @Test + public void associateServiceInstanceWhenReqMaxOccurrencesAlreadyReached() throws Exception, Exception { + RestResponse getResourseRestResponse; + // Add instance of VFC4 (Req MIN=1 MAX=1) to VF1000 + ComponentInstance componentInstanceReq = createComponentInstance(importReqDetails4, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceReq); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Add instance of VFC2 (Cap MIN=1 MAX=UNBOUNDED) to VF2.00 + ComponentInstance componentInstanceCap = createComponentInstance(importReqDetails2, sdncDesignerDetails, + resourceDetailsVF200); + assertNotNull(componentInstanceCap); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF200.getUniqueId()); + resourceVF200 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Check-In both VFs + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF100, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF200, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + // Create VF instances + RestResponse createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF100, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String vf1Name = ResponseParser.getValueFromJsonResponse(createVFInstResp.getResponse(), "name"); + String fromCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF200, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String vf2Name = ResponseParser.getValueFromJsonResponse(createVFInstResp.getResponse(), "name"); + String toCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // associate 2 VFs + String capType = capabilitiesAndRequirementsType; + String reqName = "host"; + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + RequirementCapabilityRelDef requirementDef = getReqCapRelation(fromCompInstId, toCompInstId, capType, reqName, + capList, reqList, componentInstanceReq.getUniqueId(), componentInstanceCap.getUniqueId()); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(associateInstances); + // associate same instances again - when requirement Max Occurrences + // reached + associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, sdncDesignerDetails, + serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_NOT_FOUND, + associateInstances.getErrorCode().intValue()); + ArrayList varibales = new ArrayList(); + varibales.add(vf1Name); + varibales.add(vf2Name); + varibales.add("host"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_INSTANCE_MATCH_NOT_FOUND.name(), varibales, + associateInstances.getResponse()); + // get service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "0"; + String containerMinCap = "0"; + String containerMaxCap = "UNBOUNDED"; + verifyContainerCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, containerMinReq, + containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, + resourceVF200, resourceVF100); + } + + @Test + public void serviceInstanceAssociationCapMaxOccurrencesIsReached() throws Exception, Exception { + RestResponse getResourseRestResponse; + // Add instance of VFC1 (Req MIN=1 MAX=2) to VF1000 + ComponentInstance componentInstanceReq = createComponentInstance(importReqDetails1, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceReq); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Add instance of VFC3 (Cap MIN=1 MAX=1) to VF2000 + ComponentInstance componentInstanceCap = createComponentInstance(importReqDetails3, sdncDesignerDetails, + resourceDetailsVF200); + assertNotNull(componentInstanceCap); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF200.getUniqueId()); + resourceVF200 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Check-In both VFs + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF100, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF200, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + // Create VF instances + RestResponse createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF100, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String fromCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF200, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String toCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // associate 2 VFs + String capType = capabilitiesAndRequirementsType; + String reqName = "host"; + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + RequirementCapabilityRelDef requirementDef = getReqCapRelation(fromCompInstId, toCompInstId, capType, reqName, + capList, reqList, componentInstanceReq.getUniqueId(), componentInstanceCap.getUniqueId()); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(associateInstances); + // get service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "1"; + String containerMinCap = "0"; + String containerMaxCap = "0"; + verifyContainerCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, containerMinReq, + containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, + resourceVF200, resourceVF100); + } + + @Test + public void associationServiceInstanceWhenCapMaxOccurrencesAlreadyReached() throws Exception, Exception { + RestResponse getResourseRestResponse; + // Add instance of VFC1 (Req MIN=1 MAX=2) to VF1000 + ComponentInstance componentInstanceReq = createComponentInstance(importReqDetails1, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceReq); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Add instance of VFC3 (Cap MIN=1 MAX=1) to VF2000 + ComponentInstance componentInstanceCap = createComponentInstance(importReqDetails3, sdncDesignerDetails, + resourceDetailsVF200); + assertNotNull(componentInstanceCap); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF200.getUniqueId()); + resourceVF200 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Check-In both VFs + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF100, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF200, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + // Create VF instances + RestResponse createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF100, + sdncDesignerDetails); + // RestResponse createVFInstResp = createVFInstance(serviceDetails_01, + // resourceDetailsVF100, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String vf1Name = ResponseParser.getValueFromJsonResponse(createVFInstResp.getResponse(), "name"); + String fromCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF200, sdncDesignerDetails); + // createVFInstResp = createVFInstance(serviceDetails_01, + // resourceDetailsVF200, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String vf2Name = ResponseParser.getValueFromJsonResponse(createVFInstResp.getResponse(), "name"); + String toCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // associate 2 VFs + String capType = capabilitiesAndRequirementsType; + String reqName = "host"; + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + RequirementCapabilityRelDef requirementDef = getReqCapRelation(fromCompInstId, toCompInstId, capType, reqName, + capList, reqList, componentInstanceReq.getUniqueId(), componentInstanceCap.getUniqueId()); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(associateInstances); + // get service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "1"; + String containerMinCap = "0"; + String containerMaxCap = "0"; + verifyContainerCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, containerMinReq, + containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, + resourceVF200, resourceVF100); + // associate same instances again - when requirement Max Occurrences + // reached + associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, sdncDesignerDetails, + serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_NOT_FOUND, + associateInstances.getErrorCode().intValue()); + ArrayList varibales = new ArrayList(); + varibales.add(vf1Name); + varibales.add(vf2Name); + varibales.add("host"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND.name(), + varibales, associateInstances.getResponse()); + } + + @Test + public void associationAndDisassociateServiceInstancesWhenReqMaxOccurrencesAlreadyReached() + throws Exception, Exception { + RestResponse getResourseRestResponse; + // Add instance of VFC4 (Req MIN=1 MAX=1) to VF1000 + ComponentInstance componentInstanceReq = createComponentInstance(importReqDetails4, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceReq); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Add instance of VFC3 (Cap MIN=1 MAX=1) to VF2000 + ComponentInstance componentInstanceCap = createComponentInstance(importReqDetails3, sdncDesignerDetails, + resourceDetailsVF200); + assertNotNull(componentInstanceCap); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF200.getUniqueId()); + resourceVF200 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Check-In both VFs + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF100, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF200, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + // Create VF instances + RestResponse createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF100, + sdncDesignerDetails); + // RestResponse createVFInstResp = createVFInstance(serviceDetails_01, + // resourceDetailsVF100, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String fromCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF200, sdncDesignerDetails); + // createVFInstResp = createVFInstance(serviceDetails_01, + // resourceDetailsVF200, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String toCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // associate 2 VF Instances + String capType = capabilitiesAndRequirementsType; + String reqName = "host"; + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + RequirementCapabilityRelDef requirementDef = getReqCapRelation(fromCompInstId, toCompInstId, capType, reqName, + capList, reqList, componentInstanceReq.getUniqueId(), componentInstanceCap.getUniqueId()); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(associateInstances); + // get service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "0"; + String containerMinCap = "0"; + String containerMaxCap = "0"; + verifyContainerCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, containerMinReq, + containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, + resourceVF200, resourceVF100); + // Disassociate 2 VF Instances + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, + dissociateInstances.getErrorCode().intValue()); + assertTrue(getComponentInstancesRelations(resourceDetailsVF100.getUniqueId()).isEmpty()); + // get service and verify Occurrences in container and container + // instance requirements and Capabilities + getServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getServiceResponse); + service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + containerMinReq = "1"; + containerMaxReq = "1"; + containerMinCap = "1"; + containerMaxCap = "1"; + verifyContainerCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, containerMinReq, + containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, + resourceVF200, resourceVF100); + } + + @Test(enabled = false) + public void aaaa() throws Exception, Exception { + RestResponse getResourseRestResponse; + // Add instance of VFC1 (Req MIN=1 MAX=2) to VF1000 + ComponentInstance componentInstanceReq = createComponentInstance(importReqDetails1, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceReq); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Add instance of VFC3 (Cap MIN=1 MAX=1) to VF2000 + ComponentInstance componentInstanceCap = createComponentInstance(importReqDetails3, sdncDesignerDetails, + resourceDetailsVF200); + assertNotNull(componentInstanceCap); + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF200.getUniqueId()); + resourceVF200 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Check-In both VFs + RestResponse restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF100, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + restResponse = LifecycleRestUtils.changeResourceState(resourceDetailsVF200, sdncDesignerDetails, + LifeCycleStatesEnum.CHECKIN); + ResourceRestUtils.checkSuccess(restResponse); + // Create VF instances + // RestResponse createVFInstResp = + // createVFInstanceDuringSetup(serviceDetails_01, resourceDetailsVF100, + // sdncDesignerDetails); + RestResponse createVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF100, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String vf1Name = ResponseParser.getValueFromJsonResponse(createVFInstResp.getResponse(), "name"); + String fromCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // createVFInstResp = createVFInstanceDuringSetup(serviceDetails_01, + // resourceDetailsVF200, sdncDesignerDetails); + createVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF200, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String vf2Name = ResponseParser.getValueFromJsonResponse(createVFInstResp.getResponse(), "name"); + String toCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // associate 2 VFs + String capType = capabilitiesAndRequirementsType; + String reqName = "host"; + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + RequirementCapabilityRelDef requirementDef = getReqCapRelation(fromCompInstId, toCompInstId, capType, reqName, + capList, reqList, componentInstanceReq.getUniqueId(), componentInstanceCap.getUniqueId()); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(associateInstances); + getComponentAndValidateRIs(serviceDetails_01, 2, 1); + // get service + RestResponse getServiceResponse = ServiceRestUtils.getService(serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getServiceResponse); + Service service = ResponseParser.parseToObjectUsingMapper(getServiceResponse.getResponse(), Service.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "1"; + String containerMinCap = "0"; + String containerMaxCap = "0"; + verifyContainerCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, containerMinReq, + containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(service, capabilitiesAndRequirementsType, + resourceVF200, resourceVF100); + // associate same instances again - when requirement Max Occurrences + // reached + associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, sdncDesignerDetails, + serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_NOT_FOUND, + associateInstances.getErrorCode().intValue()); + ArrayList varibales = new ArrayList(); + varibales.add(vf1Name); + varibales.add(vf2Name); + varibales.add("host"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND.name(), + varibales, associateInstances.getResponse()); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // US628514 Capability/Requirement "Occurrences" attribute in CREATE/DELETE + ////////////////////////////////////////////////////////////////////////////////////////////////// Relation + ////////////////////////////////////////////////////////////////////////////////////////////////// APIs + // Container = VF , Container instance = VFC + @Test + public void capAndReqOccurrencesInVfAndHisInstancesNoAssociation() throws Exception, Exception { + // Add VFC1 and VFC2 instances in VF + ComponentInstance createComponentInstance1 = createComponentInstance(importReqDetails1, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(createComponentInstance1); + ComponentInstance createComponentInstance2 = createComponentInstance(importReqDetails2, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(createComponentInstance2); + // GET resource + RestResponse getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Verify Container requirements and Capabilities + String containerMinReq = "1"; + String containerMaxReq = "2"; + String containerMinCap = "1"; + String containerMaxCap = "UNBOUNDED"; + verifyContainerCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + containerMinReq, containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + resourceVFC2, resourceVFC1); + } + + @Test + public void vfInstanceAssociationReqMaxOccurrencesNotReached() throws Exception, Exception { + // Add VFC1 (with Requirements: tosca.capabilities.Container, MIN=1 + // MAX=2) instance to VF + ComponentInstance componentInstanceWithReq = createComponentInstance(importReqDetails1, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithReq); + // Add VFC2 (with Capabilities: tosca.capabilities.Container, MIN=1, + // MAX=UNBOUNDED ) instance to VF + ComponentInstance componentInstanceWithCap = createComponentInstance(importReqDetails2, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithCap); + // associate Instances + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(resourceDetailsVF100); + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(componentInstanceWithReq, + componentInstanceWithCap, capReqDefBeforeAssociate); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, resourceDetailsVF100.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF100.getUniqueId())); + // GET resource + RestResponse getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "1"; + String containerMinCap = "0"; + String containerMaxCap = "UNBOUNDED"; + verifyContainerCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + containerMinReq, containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + resourceVFC2, resourceVFC1); + + } + + @Test + public void vfInstanceAssociationReqMaxOccurrencesIsReached() throws Exception, Exception { + // Add VFC4 (with Requirements: tosca.capabilities.Container, MIN=1 + // MAX=1) instance to VF + ComponentInstance componentInstanceWithReq = createComponentInstance(importReqDetails4, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithReq); + // Add VFC2 (with Capabilities: tosca.capabilities.Container, MIN=1, + // MAX=UNBOUNDED ) instance to VF + ComponentInstance componentInstanceWithCap = createComponentInstance(importReqDetails2, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithCap); + // associate Instances + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(resourceDetailsVF100); + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(componentInstanceWithReq, + componentInstanceWithCap, capReqDefBeforeAssociate); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, resourceDetailsVF100.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF100.getUniqueId())); + // GET resource + RestResponse getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "0"; + String containerMinCap = "0"; + String containerMaxCap = "UNBOUNDED"; + verifyContainerCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + containerMinReq, containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + resourceVFC2, resourceVFC4); + } + + @Test + public void associateVfInstanceWhenReqMaxOccurrencesAlreadyReached() throws Exception, Exception { + // Add VFC4 (with Requirements: tosca.capabilities.Container, MIN=1 + // MAX=1) instance to VF + ComponentInstance componentInstanceWithReq = createComponentInstance(importReqDetails4, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithReq); + // Add VFC2 (with Capabilities: tosca.capabilities.Container, MIN=1, + // MAX=UNBOUNDED ) instance to VF + ComponentInstance componentInstanceWithCap = createComponentInstance(importReqDetails2, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithCap); + // associate Instances + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(resourceDetailsVF100); + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(componentInstanceWithReq, + componentInstanceWithCap, capReqDefBeforeAssociate); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, resourceDetailsVF100.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF100.getUniqueId())); + // GET resource + RestResponse getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "0"; + String containerMinCap = "0"; + String containerMaxCap = "UNBOUNDED"; + verifyContainerCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + containerMinReq, containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + resourceVFC2, resourceVFC4); + // associate same instances again - when requirement Max Occurrences + // reached + associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, sdncDesignerDetails, + resourceDetailsVF100.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_NOT_FOUND, + associateInstances.getErrorCode().intValue()); + ArrayList varibales = new ArrayList(); + varibales.add(componentInstanceWithReq.getName()); + varibales.add(componentInstanceWithCap.getName()); + varibales.add("host"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_INSTANCE_MATCH_NOT_FOUND.name(), varibales, + associateInstances.getResponse()); + + } + + @Test + public void vfInstanceAssociationCapMaxOccurrencesIsReached() throws Exception, Exception { + // Add VFC1 (with Requirements: tosca.capabilities.Container, MIN=1 + // MAX=2) instance to VF + ComponentInstance componentInstanceWithReq = createComponentInstance(importReqDetails1, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithReq); + // Add VFC3 (with Capabilities: tosca.capabilities.Container, MIN=1 + // MAX=1 ) instance to VF + ComponentInstance componentInstanceWithCap = createComponentInstance(importReqDetails3, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithCap); + // associate Instances + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(resourceDetailsVF100); + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(componentInstanceWithReq, + componentInstanceWithCap, capReqDefBeforeAssociate); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, resourceDetailsVF100.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF100.getUniqueId())); + // GET resource + RestResponse getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "1"; + String containerMinCap = "0"; + String containerMaxCap = "0"; + verifyContainerCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + containerMinReq, containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + resourceVFC3, resourceVFC1); + } + + @Test + public void associationVfInstanceWhenCapMaxOccurrencesAlreadyReached() throws Exception, Exception { + // Add VFC1 (with Requirements: tosca.capabilities.Container, MIN=1 + // MAX=2) instance to VF + ComponentInstance componentInstanceWithReq = createComponentInstance(importReqDetails1, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithReq); + // Add VFC3 (with Capabilities: tosca.capabilities.Container, MIN=1 + // MAX=1 ) instance to VF + ComponentInstance componentInstanceWithCap = createComponentInstance(importReqDetails3, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithCap); + // associate Instances + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(resourceDetailsVF100); + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(componentInstanceWithReq, + componentInstanceWithCap, capReqDefBeforeAssociate); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, resourceDetailsVF100.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", STATUS_CODE_SUCCESS, associateInstances.getErrorCode().intValue()); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF100.getUniqueId())); + // GET resource + RestResponse getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "1"; + String containerMinCap = "0"; + String containerMaxCap = "0"; + verifyContainerCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + containerMinReq, containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + resourceVFC3, resourceVFC1); + // associate same instances again - when requirement Max Occurrences + // reached + associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, sdncDesignerDetails, + resourceDetailsVF100.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_NOT_FOUND, + associateInstances.getErrorCode().intValue()); + ArrayList varibales = new ArrayList(); + varibales.add(componentInstanceWithReq.getName()); + varibales.add(componentInstanceWithCap.getName()); + varibales.add("host"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND.name(), + varibales, associateInstances.getResponse()); + } + + @Test + public void associationAndDisassociateVfInstancesWhenReqMaxOccurrencesAlreadyReached() throws Exception, Exception { + // Add VFC4 (with Requirements: tosca.capabilities.Container, MIN=1 + // MAX=1) instance to VF + ComponentInstance componentInstanceWithReq = createComponentInstance(importReqDetails4, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithReq); + // Add VFC3 (with Capabilities: tosca.capabilities.Container, MIN=1 + // MAX=1 ) instance to VF + ComponentInstance componentInstanceWithCap = createComponentInstance(importReqDetails3, sdncDesignerDetails, + resourceDetailsVF100); + assertNotNull(componentInstanceWithCap); + // associate Instances + CapReqDef capReqDefBeforeAssociate = getResourceReqCap(resourceDetailsVF100); + RequirementCapabilityRelDef requirementDef = setRelationshipBetweenInstances(componentInstanceWithReq, + componentInstanceWithCap, capReqDefBeforeAssociate); + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, resourceDetailsVF100.getUniqueId(), ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkSuccess(associateInstances); + assertTrue(checkRealtionship(requirementDef.getFromNode(), requirementDef.getToNode(), + resourceDetailsVF100.getUniqueId())); + // GET resource + RestResponse getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Verify Container requirements and Capabilities + String containerMinReq = "0"; + String containerMaxReq = "0"; + String containerMinCap = "0"; + String containerMaxCap = "0"; + verifyContainerCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + containerMinReq, containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + resourceVFC3, resourceVFC4); + // Disassociate 2 Instances + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, + sdncDesignerDetails, resourceDetailsVF100.getUniqueId(), ComponentTypeEnum.RESOURCE); + assertEquals("Check response code ", BaseRestUtils.STATUS_CODE_SUCCESS, + dissociateInstances.getErrorCode().intValue()); + assertTrue(getComponentInstancesRelations(resourceDetailsVF100.getUniqueId()).isEmpty()); + // GET resource + getResourseRestResponse = ResourceRestUtils.getResource(sdncDesignerDetails, + resourceDetailsVF100.getUniqueId()); + resourceVF100 = ResponseParser.parseToObjectUsingMapper(getResourseRestResponse.getResponse(), Resource.class); + // Verify Container requirements and Capabilities + containerMinReq = "1"; + containerMaxReq = "1"; + containerMinCap = "1"; + containerMaxCap = "1"; + verifyContainerCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + containerMinReq, containerMaxReq, containerMinCap, containerMaxCap); + verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(resourceVF100, capabilitiesAndRequirementsType, + resourceVFC3, resourceVFC4); + } + + /////////////////////////////////////// + + private boolean checkRealtionship(String fromNode, String toNode, String resourceUniqueId) throws Exception { + List componentInstancesRelations = getComponentInstancesRelations( + resourceUniqueId); + RequirementCapabilityRelDef requirementCapabilityRelDef = componentInstancesRelations.get(0); + boolean fromNodeCheck = requirementCapabilityRelDef.getFromNode().equals(fromNode); + boolean toNodeCheck = requirementCapabilityRelDef.getToNode().equals(toNode); + + return fromNodeCheck && toNodeCheck; + } + + private List getComponentInstancesRelations(String resourceUniqueId) + throws ClientProtocolException, IOException { + Resource resource = getVfAsResourceObject(resourceUniqueId); + List componenRelationInstances = resource.getComponentInstancesRelations(); + + return componenRelationInstances; + } + + private Resource getVfAsResourceObject(String resourceUniqueId) throws ClientProtocolException, IOException { + RestResponse getResource = ResourceRestUtils.getResource(resourceUniqueId); + Resource resource = ResponseParser.parseToObjectUsingMapper(getResource.getResponse(), Resource.class); + return resource; + } + + private RequirementCapabilityRelDef setRelationshipBetweenInstances(ComponentInstance riReq, + ComponentInstance riCap, CapReqDef capReqDef) throws Exception { + + String capbilityUid = capReqDef.getCapabilities().get("tosca.capabilities.Container").get(0).getUniqueId(); + String requirementUid = capReqDef.getRequirements().get("tosca.capabilities.Container").get(0).getUniqueId(); + + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + requirementDef.setFromNode(riReq.getUniqueId()); + requirementDef.setToNode(riCap.getUniqueId()); + + RequirementAndRelationshipPair pair = new RequirementAndRelationshipPair(); + pair.setRequirementOwnerId(riReq.getUniqueId()); + pair.setCapabilityOwnerId(riCap.getUniqueId()); + pair.setRequirement("host"); + RelationshipImpl relationship = new RelationshipImpl(); + relationship.setType("tosca.capabilities.Container"); + pair.setRelationships(relationship); + pair.setCapabilityUid(capbilityUid); + pair.setRequirementUid(requirementUid); + List relationships = new ArrayList<>(); + relationships.add(pair); + requirementDef.setRelationships(relationships); + return requirementDef; + } + + private CapReqDef getResourceReqCap(ResourceReqDetails res) throws IOException { + RestResponse getResourceBeforeAssociate = ComponentRestUtils + .getComponentRequirmentsCapabilities(sdncDesignerDetails, resourceDetailsVF100); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceBeforeAssociate.getResponse(), CapReqDef.class); + return capReqDef; + } + + private RestResponse importedResource(ImportReqDetails importReqDetails, String ymlFile) throws Exception { + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, testResourcesPath, + ymlFile); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, + sdncDesignerDetails, null); + assertEquals("Check response code after importing resource", BaseRestUtils.STATUS_CODE_CREATED, + importResourceResponse.getErrorCode().intValue()); + return importResourceResponse; + } + + private ComponentInstance createComponentInstance(ResourceReqDetails res, User user, ResourceReqDetails vf) + throws Exception { + RestResponse response = ResourceRestUtils.createResourceInstance(res, user, vf.getUniqueId()); + ResourceRestUtils.checkCreateResponse(response); + ComponentInstance compInstance = ResponseParser.parseToObject(response.getResponse(), ComponentInstance.class); + return compInstance; + } + + private void verifyContainerCapabilitiesAndRequirementsOccurrences(Component component, + String CapabilitiesAndRequirementsType, String minReqOccurrences, String maxReqOccurrences, + String minCapabilities, String maxCapabilities) throws Exception { + boolean isRequirementAppear = false; + boolean isCapabilityAppear = false; + List requirements; + List capabilities; + requirements = component.getRequirements().get(CapabilitiesAndRequirementsType); + if (maxReqOccurrences == "0") { + assertTrue(requirements == null); + } // if container MAX requirement = 0 + if (maxReqOccurrences != "0") { + assertNotNull(requirements); + for (RequirementDefinition req : requirements) { + switch (req.getName()) { + case "host": + assertTrue("Check Min Requirement Occurrences ", req.getMinOccurrences().equals(minReqOccurrences)); + assertTrue("Check Max Requirement Occurrences ", req.getMaxOccurrences().equals(maxReqOccurrences)); + isRequirementAppear = true; + break; + } + assertTrue(isRequirementAppear); + isRequirementAppear = false; + } + } + // Container Capabilities + capabilities = component.getCapabilities().get(CapabilitiesAndRequirementsType); + if (maxCapabilities == "0") {// if container MAX capabilities = 0 + assertTrue(capabilities == null); + } + if (maxCapabilities != "0") { + assertNotNull(capabilities); + for (CapabilityDefinition cap : capabilities) { + switch (cap.getName()) { + case "host": + assertTrue("Check Min capability Occurrences ", cap.getMinOccurrences().equals(minCapabilities)); + assertTrue("Check Max capability Occurrences ", cap.getMaxOccurrences().equals(maxCapabilities)); + isCapabilityAppear = true; + break; + } + assertTrue(isCapabilityAppear); + isCapabilityAppear = false; + } + } + + } + + private void verifyContainerInstanceCapabilitiesAndRequirementsOccurrences(Component component, + String CapabilitiesAndRequirementsType, Resource vfWithCapabilities, Resource vfWithRequirements) + throws Exception { + boolean isCapReqAppear = false; + List listOfComponentInstances = component.getComponentInstances(); + + for (ComponentInstance instance : listOfComponentInstances) { + if (instance.getComponentUid().equals(vfWithCapabilities.getUniqueId())) { + List capFromResource = vfWithCapabilities.getCapabilities() + .get(CapabilitiesAndRequirementsType); + List capFromInstance = instance.getCapabilities() + .get(CapabilitiesAndRequirementsType); + for (CapabilityDefinition resourceCap : capFromResource) + for (CapabilityDefinition instanceReq : capFromInstance) { + if (resourceCap.getUniqueId().equals(instanceReq.getUniqueId())) { + assertTrue("Check Min capability Occurrences ", + resourceCap.getMinOccurrences().equals(instanceReq.getMinOccurrences())); + assertTrue("Check Max capability Occurrences ", + resourceCap.getMaxOccurrences().equals(instanceReq.getMaxOccurrences())); + isCapReqAppear = true; + break; + } + + } + } + + if (instance.getComponentUid().equals(vfWithRequirements.getUniqueId())) { + List reqFromAtomicResource = vfWithRequirements.getRequirements() + .get(CapabilitiesAndRequirementsType); + List reqFromInstance = instance.getRequirements() + .get(CapabilitiesAndRequirementsType); + for (RequirementDefinition resourceReq : reqFromAtomicResource) + for (RequirementDefinition instanceReq : reqFromInstance) { + if (resourceReq.getUniqueId().equals(instanceReq.getUniqueId())) { + assertTrue("Check Min Requirement Occurrences ", + resourceReq.getMinOccurrences().equals(instanceReq.getMinOccurrences())); + assertTrue("Check Max Requirement Occurrences ", + resourceReq.getMaxOccurrences().equals(instanceReq.getMaxOccurrences())); + isCapReqAppear = true; + break; + } + } + } + assertTrue(isCapReqAppear); + isCapReqAppear = false; + } + + } + + private RequirementCapabilityRelDef getReqCapRelation(String reqCompInstId, String capCompInstId, String capType, + String reqName, List capList, List reqList, + String vfc1UniqueId, String vfc2UniqueId) { + return ElementFactory.getReqCapRelation(reqCompInstId, capCompInstId, vfc1UniqueId, vfc2UniqueId, capType, + reqName, capList, reqList); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ServiceComponentInstanceCRUDTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ServiceComponentInstanceCRUDTest.java new file mode 100644 index 0000000000..7181549a27 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/ServiceComponentInstanceCRUDTest.java @@ -0,0 +1,1627 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.service; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.codehaus.jettison.json.JSONException; +import org.json.JSONArray; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentInstanceBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.BaseValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class ServiceComponentInstanceCRUDTest extends ComponentInstanceBaseTest { + private static Logger log = LoggerFactory.getLogger(ServiceComponentInstanceCRUDTest.class.getName()); + private static final String SPACE_STRING = " "; + private static String REQUIREMENT_NAME = "host"; + private static String CAPABILITY_TYPE = "tosca.capabilities.Container"; + + private String reqOwnerId; + private String capOwnerId; + + public ServiceComponentInstanceCRUDTest() { + super(new TestName(), ServiceComponentInstanceCRUDTest.class.getSimpleName()); + } + + @BeforeMethod(alwaysRun = true) + public void before() throws Exception { + init(); + createComponents(); + } + + private void createComponents() throws Exception { + createAtomicResource(resourceDetailsVFC_01); + createAtomicResource(resourceDetailsVFC_02); + createAtomicResource(resourceDetailsCP_01); + createAtomicResource(resourceDetailsVL_01); + createAtomicResource(resourceDetailsVL_02); + createVF(resourceDetailsVF_01); + createVF(resourceDetailsVF_02); + createService(serviceDetails_01); + certifyResource(resourceDetailsVFC_01); + certifyResource(resourceDetailsVFC_02); + RestResponse createAtomicResourceInstance = createAtomicInstanceForVFDuringSetup(resourceDetailsVF_01, + resourceDetailsVFC_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + reqOwnerId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstance); + createAtomicResourceInstance = createAtomicInstanceForVFDuringSetup(resourceDetailsVF_02, resourceDetailsVFC_02, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + capOwnerId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstance);// should + // be + // updated + // to + // getUniqueIdOfFirstInstance + // in + // service + // context + } + + private void certifyResource(ResourceReqDetails resource) throws Exception { + changeResourceLifecycleState(resource, sdncDesignerDetails.getUserId(), + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + changeResourceLifecycleState(resource, sdncTesterDetails.getUserId(), LifeCycleStatesEnum.STARTCERTIFICATION); + changeResourceLifecycleState(resource, sdncTesterDetails.getUserId(), LifeCycleStatesEnum.CERTIFY); + } + + private void changeResourceLifecycleState(ResourceReqDetails resourceDetails, String userUserId, + LifeCycleStatesEnum lifeCycleStates) throws Exception { + RestResponse response = LifecycleRestUtils.changeResourceState(resourceDetails, userUserId, lifeCycleStates); + LifecycleRestUtils.checkLCS_Response(response); + } + + private void changeServiceLifecycleState(ServiceReqDetails serviceDetails, User user, + LifeCycleStatesEnum lifeCycleStates) throws Exception { + RestResponse response = LifecycleRestUtils.changeServiceState(serviceDetails, user, lifeCycleStates); + LifecycleRestUtils.checkLCS_Response(response); + } + + private void createVFInstanceFailWithoutChangeState(ActionStatus actionStatus, List variables, + ResourceReqDetails vfResource, User user, int errorCode) throws Exception { + RestResponse createVFInstanceSuccessfullyWithoutChangeStateResp = createVFInstance(serviceDetails_01, + vfResource, user); + checkErrorMessage(actionStatus, variables, errorCode, createVFInstanceSuccessfullyWithoutChangeStateResp); + } + + private void createVFInstanceFail(ActionStatus actionStatus, List variables, ResourceReqDetails vfResource, + User user, int errorCode) throws Exception, FileNotFoundException, JSONException { + RestResponse createVFInstResp = createCheckedinVFInstance(serviceDetails_01, vfResource, user); + checkErrorMessage(actionStatus, variables, errorCode, createVFInstResp); + } + + private void deleteVFInstanceFail(ActionStatus actionStatus, List variables, ResourceReqDetails vfResource, + User user, int errorCode) throws Exception, FileNotFoundException, JSONException { + RestResponse deleteVFInstResp = deleteVFInstance(vfResource.getUniqueId(), serviceDetails_01, user); + checkErrorMessage(actionStatus, variables, errorCode, deleteVFInstResp); + } + + private void createAtomicResourceInstanceFailWithoutChangeState(ActionStatus actionStatus, List variables, + ResourceReqDetails atomicResource, User user, int errorCode) + throws Exception, FileNotFoundException, JSONException { + RestResponse createAtomicInstResp = createAtomicInstanceForService(serviceDetails_01, atomicResource, user); + checkErrorMessage(actionStatus, variables, errorCode, createAtomicInstResp); + } + + private void createAtomicResourceInstanceFail(ActionStatus actionStatus, List variables, + ResourceReqDetails atomicResource, User user, int errorCode) + throws Exception, FileNotFoundException, JSONException { + RestResponse createAtomicInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, atomicResource, + user); + checkErrorMessage(actionStatus, variables, errorCode, createAtomicInstResp); + } + + private void deleteAtomicResourceInstanceFail(ActionStatus actionStatus, List variables, + ResourceReqDetails atomicResource, User user, int errorCode) + throws Exception, FileNotFoundException, JSONException { + RestResponse deleteAtomicInstResp = deleteAtomicInstanceForService(atomicResource.getUniqueId(), + serviceDetails_01, user); + checkErrorMessage(actionStatus, variables, errorCode, deleteAtomicInstResp); + } + + private void checkErrorMessage(ActionStatus actionStatus, List variables, int errorCode, + RestResponse response) throws Exception { + + log.debug(response.getResponse()); + AssertJUnit.assertEquals(errorCode, response.getErrorCode().intValue()); + ErrorValidationUtils.checkBodyResponseOnError(actionStatus.name(), variables, response.getResponse()); + } + + private RestResponse createCheckedinVFInstance(ServiceReqDetails containerDetails, + ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + changeResourceLifecycleState(compInstOriginDetails, compInstOriginDetails.getCreatorUserId(), + LifeCycleStatesEnum.CHECKIN); + return createVFInstance(containerDetails, compInstOriginDetails, modifier); + } + + private RestResponse createCheckedinAtomicInstanceForService(ServiceReqDetails containerDetails, + ResourceReqDetails compInstOriginDetails, User modifier) throws Exception { + changeResourceLifecycleState(compInstOriginDetails, compInstOriginDetails.getCreatorUserId(), + LifeCycleStatesEnum.CHECKIN); + return createAtomicInstanceForService(containerDetails, compInstOriginDetails, modifier); + } + + private void createVFInstanceAndAtomicResourceInstanceWithoutCheckin(ResourceReqDetails vf, + ResourceReqDetails atomicResource, User user) throws Exception { + RestResponse createVFInstance = createVFInstance(serviceDetails_01, vf, user); + ResourceRestUtils.checkCreateResponse(createVFInstance); + RestResponse atomicInstanceForService = createAtomicInstanceForService(serviceDetails_01, atomicResource, user); + ResourceRestUtils.checkCreateResponse(atomicInstanceForService); + } + + private void createVFInstanceAndAtomicResourceInstanceSuccessully(ResourceReqDetails vf, + ResourceReqDetails atomicResource) throws Exception, IOException { + createVFInstanceAndAtomicResourceInstanceSuccessully(vf, atomicResource, sdncDesignerDetails); + } + + private void createVFInstanceAndAtomicResourceInstanceSuccessully(ResourceReqDetails vf, + ResourceReqDetails atomicResource, User user) throws Exception, IOException { + changeResourceLifecycleState(vf, vf.getCreatorUserId(), LifeCycleStatesEnum.CHECKIN); + changeResourceLifecycleState(atomicResource, atomicResource.getCreatorUserId(), LifeCycleStatesEnum.CHECKIN); + createVFInstanceAndAtomicResourceInstanceWithoutCheckin(vf, atomicResource, user); + } + + @Test + public void createVFInstanceSuccessfullyTest() throws Exception { + RestResponse createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void createVFAndAtomicInstanceTest() throws Exception { + RestResponse createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, resourceDetailsCP_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, resourceDetailsVL_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, resourceDetailsVL_02, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + getComponentAndValidateRIs(serviceDetails_01, 4, 0); + } + + @Test + public void deleteAtomicInstanceTest() throws Exception { + RestResponse createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + // 1 rel + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, resourceDetailsCP_01, + sdncDesignerDetails); + // 2 rel + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, resourceDetailsVL_01, + sdncDesignerDetails); + // 3 rel + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, resourceDetailsVL_02, + sdncDesignerDetails); + // 4 rel + ResourceRestUtils.checkCreateResponse(createVFInstResp); + // To delete + String compInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // 3 rel + createVFInstResp = deleteAtomicInstanceForService(compInstId, serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkDeleteResponse(createVFInstResp); + getComponentAndValidateRIs(serviceDetails_01, 3, 0); + } + + @Test + public void deleteVFInstanceTest() throws Exception { + RestResponse createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + // 1 rel + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, sdncDesignerDetails); + String compInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + // 2 rel + ResourceRestUtils.checkCreateResponse(createVFInstResp); + createVFInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, resourceDetailsCP_01, + sdncDesignerDetails); + // 3 rel + ResourceRestUtils.checkCreateResponse(createVFInstResp); + // 2 rel + createVFInstResp = deleteVFInstance(compInstId, serviceDetails_01, sdncDesignerDetails); + ResourceRestUtils.checkDeleteResponse(createVFInstResp); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void associateDissociateTwoVFs() throws Exception { + + RestResponse createVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String fromCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + createVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_02, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String toCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + + String capType = CAPABILITY_TYPE; + String reqName = REQUIREMENT_NAME; + + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(fromCompInstId, toCompInstId, capType, reqName, + capList, reqList); + + associateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List list = capReqDef.getRequirements().get(capType); + AssertJUnit.assertEquals("Check requirement", null, list); + getComponentAndValidateRIs(serviceDetails_01, 2, 1); + + dissociateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + list = capReqDef.getRequirements().get(capType); + AssertJUnit.assertEquals("Check requirement", 1, list.size()); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + private RequirementCapabilityRelDef getReqCapRelation(String reqCompInstId, String capCompInstId, String capType, + String reqName, List capList, List reqList) { + return ElementFactory.getReqCapRelation(reqCompInstId, capCompInstId, reqOwnerId, capOwnerId, capType, reqName, + capList, reqList); + } + + @Test + public void createResourceInstanceByDifferentDesignerTest() throws Exception { + createVFInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), resourceDetailsVF_01, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2), 409); + createAtomicResourceInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsCP_01, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2), 409); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + @Test + public void createResourceInstanceByDifferentDesignerTest_ServiceIsCheckedin() throws Exception { + User designer2 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2); + + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + changeServiceLifecycleState(serviceDetails_01, designer2, LifeCycleStatesEnum.CHECKOUT); + + createVFInstanceAndAtomicResourceInstanceSuccessully(resourceDetailsVF_01, resourceDetailsCP_01, designer2); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + + } + + @Test + public void createResourceInstanceByTester() throws Exception { + createVFInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), resourceDetailsVF_01, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), 409); + createAtomicResourceInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsCP_01, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), 409); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + @Test + public void createResourceInstanceWithNotASDCUserTest() throws Exception { + sdncDesignerDetails.setUserId("ab0001"); + createVFInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), resourceDetailsVF_01, + sdncDesignerDetails, 409); + createAtomicResourceInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsCP_01, sdncDesignerDetails, 409); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + @Test + public void createResourceInstanceWithEmptyUserIdTest() throws Exception { + sdncDesignerDetails.setUserId(""); + createVFInstanceFail(ActionStatus.MISSING_INFORMATION, new ArrayList(), resourceDetailsVF_01, + sdncDesignerDetails, 403); + createAtomicResourceInstanceFail(ActionStatus.MISSING_INFORMATION, new ArrayList(), + resourceDetailsCP_01, sdncDesignerDetails, 403); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + @Test + public void createResourceInstanceWithEmptyServiceUidTest() throws Exception { + serviceDetails_01.setUniqueId(""); + RestResponse createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + assertEquals(404, createVFInstResp.getErrorCode().intValue()); + RestResponse createAtomicInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, + resourceDetailsCP_01, sdncDesignerDetails); + assertEquals(404, createAtomicInstResp.getErrorCode().intValue()); + } + + @Test + public void createResourceInstanceWhileResourceNotExistTest() throws Exception { + String vfResourceUniqueId = "1234"; + String atomicResourceUniqueId = "5678"; + + resourceDetailsVF_01.setUniqueId(vfResourceUniqueId); + resourceDetailsCP_01.setUniqueId(atomicResourceUniqueId); + + createVFInstanceFailWithoutChangeState(ActionStatus.RESOURCE_NOT_FOUND, + new ArrayList(Arrays.asList("")), resourceDetailsVF_01, sdncDesignerDetails, 404); + createAtomicResourceInstanceFailWithoutChangeState(ActionStatus.RESOURCE_NOT_FOUND, + new ArrayList(Arrays.asList("")), resourceDetailsCP_01, sdncDesignerDetails, 404); + } + + @Test + public void createResourceInstanceInServiceNotExistsTest() throws Exception { + serviceDetails_01.setUniqueId("1234"); + createVFInstanceFail(ActionStatus.SERVICE_NOT_FOUND, new ArrayList(Arrays.asList("")), + resourceDetailsVF_01, sdncDesignerDetails, 404); + createAtomicResourceInstanceFail(ActionStatus.SERVICE_NOT_FOUND, new ArrayList(Arrays.asList("")), + resourceDetailsCP_01, sdncDesignerDetails, 404); + } + + @Test + public void createResourceInstanceInCheckedinServiceTest() throws Exception { + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + + createVFInstanceFailWithoutChangeState(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsVF_01, sdncDesignerDetails, 409); + createAtomicResourceInstanceFailWithoutChangeState(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsCP_01, sdncDesignerDetails, 409); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + @Test(enabled = false) + public void createResourceInstance_ResourceInCheckoutStateTest() throws Exception { + LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + RestResponse createVFInstanceWithoutChangeStateResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ComponentInstanceRestUtils.checkCreateResponse(createVFInstanceWithoutChangeStateResp); + RestResponse createAtomicInstWithoutCheangeStateResp = createAtomicInstanceForService(serviceDetails_01, + resourceDetailsCP_01, sdncDesignerDetails); + ComponentInstanceRestUtils.checkCreateResponse(createAtomicInstWithoutCheangeStateResp); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void createResourceInstance_ResourceInCertificationRequestStateTest() throws Exception { + changeResourceLifecycleState(resourceDetailsVF_01, sdncDesignerDetails.getUserId(), + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + changeResourceLifecycleState(resourceDetailsCP_01, sdncDesignerDetails.getUserId(), + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + + createVFInstanceAndAtomicResourceInstanceSuccessully(resourceDetailsVF_01, resourceDetailsCP_01); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void createResourceInstance_startCertificationStateTest() throws Exception { + changeResourceLifecycleState(resourceDetailsVF_01, sdncDesignerDetails.getUserId(), + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + changeResourceLifecycleState(resourceDetailsCP_01, sdncDesignerDetails.getUserId(), + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + + changeResourceLifecycleState(resourceDetailsVF_01, sdncTesterDetails.getUserId(), + LifeCycleStatesEnum.STARTCERTIFICATION); + changeResourceLifecycleState(resourceDetailsCP_01, sdncTesterDetails.getUserId(), + LifeCycleStatesEnum.STARTCERTIFICATION); + + createVFInstanceAndAtomicResourceInstanceWithoutCheckin(resourceDetailsVF_01, resourceDetailsCP_01, + sdncDesignerDetails); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + + } + + @Test + public void createResourceInstance_certifiedStateTest() throws Exception { + certifyResource(resourceDetailsVF_01); + certifyResource(resourceDetailsCP_01); + + createVFInstanceAndAtomicResourceInstanceWithoutCheckin(resourceDetailsVF_01, resourceDetailsCP_01, + sdncDesignerDetails); + } + + @Test + public void createResourceInstance_OneHasDifferentOwner() throws Exception { + User designer2 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2); + + ResourceReqDetails vfResource = new ResourceReqDetails(resourceDetailsVF_01, "0.1"); + vfResource.setUniqueId(null); + vfResource.setName("newVF"); + vfResource.setTags(new ArrayList(Arrays.asList(vfResource.getName()))); + createVF(vfResource, designer2); + + RestResponse atomicInstanceForService = createCheckedinAtomicInstanceForService(serviceDetails_01, + resourceDetailsCP_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(atomicInstanceForService); + createVFInstanceFailWithoutChangeState(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), vfResource, + designer2, 409); + + getComponentAndValidateRIs(serviceDetails_01, 1, 0); + } + + @Test + public void indexesOfVFInstancesTest() throws Exception { + String firstInstanceName = resourceDetailsVF_01.getName() + SPACE_STRING + "1"; + String secondInstanceName = resourceDetailsVF_01.getName() + SPACE_STRING + "2"; + String thirdInstanceName = resourceDetailsVF_01.getName() + SPACE_STRING + "3"; + + LifecycleRestUtils.changeResourceState(resourceDetailsVF_01, sdncDesignerDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + + RestResponse createFirstVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createSecondVFInstResp); + RestResponse createThirdVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createThirdVFInstResp); + + Component service = getComponentAndValidateRIs(serviceDetails_01, 3, 0); + List componentInstancesList = service.getComponentInstances(); + for (ComponentInstance instance : componentInstancesList) { + String instanceName = instance.getName(); + boolean isEqualToFirstInstanceName = instanceName.equals(firstInstanceName); + boolean isEqualToSecondInstanceName = instanceName.equals(secondInstanceName); + boolean isEqualToThirdInstanceName = instanceName.equals(thirdInstanceName); + assertTrue(isEqualToFirstInstanceName || isEqualToSecondInstanceName || isEqualToThirdInstanceName); + } + } + + @Test + public void vfInstancesAmountInTwoServiceVersionsTest() throws Exception { + String oldServiceUniqueId = serviceDetails_01.getUniqueId(); + + createTwoCheckedinVFInstances(); + + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKOUT); + + String newSerivceUniqueIdAfterChangeLifecycleState = serviceDetails_01.getUniqueId(); + getComponentAndValidateRIsAfterChangeLifecycleState(oldServiceUniqueId, serviceDetails_01, 2, 0); + + // Check old version + checkServiceOldVersionRIs(oldServiceUniqueId, newSerivceUniqueIdAfterChangeLifecycleState, 2, 0); + + // Add one more resource instance to second version of service + LifecycleRestUtils.changeResourceState(resourceDetailsVL_01, sdncDesignerDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + RestResponse createAtomicResourceInstResp = createAtomicResourceInstanceToSecondServiceVersion( + newSerivceUniqueIdAfterChangeLifecycleState, resourceDetailsVL_01); + String atomicResourceUniqueId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstResp); + getComponentAndValidateRIsAfterAddingAtomicResourceInstance(oldServiceUniqueId, serviceDetails_01, 3, 0); + + // Check that RIs are same as in the beginning - like in old version of + // service + deleteCompInstReqCapFromExpected(atomicResourceUniqueId); + checkServiceOldVersionRIs(oldServiceUniqueId, newSerivceUniqueIdAfterChangeLifecycleState, 2, 0); + + } + + private void createTwoCheckedinVFInstances() throws Exception { + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createSecondVFInstResp); + } + + private void getComponentAndValidateRIsAfterAddingAtomicResourceInstance(String oldComponentUniqueId, + ComponentReqDetails componentDetails, int numOfRIs, int numOfRelations) throws Exception { + getComponentAndValidateRIsAfterChangeLifecycleState(oldComponentUniqueId, componentDetails, numOfRIs, + numOfRelations); + + } + + private void checkServiceOldVersionRIs(String oldUniqueId, String newUniqueId, int numOfRIs, int numOfRelations) + throws IOException, Exception { + serviceDetails_01.setUniqueId(oldUniqueId); + getComponentAndValidateRIsAfterChangeLifecycleState(newUniqueId, serviceDetails_01, numOfRIs, numOfRelations); + } + + private RestResponse createAtomicResourceInstanceToSecondServiceVersion(String secondServiceUniqueId, + ResourceReqDetails resourceToAdd) throws Exception { + serviceDetails_01.setUniqueId(secondServiceUniqueId); + RestResponse createAtomicResourceInstResp = createAtomicInstanceForService(serviceDetails_01, resourceToAdd, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstResp); + return createAtomicResourceInstResp; + } + + @Test + public void createResourceInstanceToUnsupportedComponentTest() throws Exception { + String unsupportedType = "unsupported"; + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetailsCP_01); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, sdncDesignerDetails, serviceDetails_01.getUniqueId(), unsupportedType); + checkErrorMessage(ActionStatus.UNSUPPORTED_ERROR, new ArrayList(Arrays.asList(unsupportedType)), 400, + createResourceInstanceResponse); + } + + @Test + public void deleteResourceInstanceByDifferentDesignerTest() throws Exception { + + createVFInstanceAndAtomicResourceInstanceSuccessully(resourceDetailsVF_01, resourceDetailsCP_01); + + deleteVFInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), resourceDetailsVF_01, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2), 409); + deleteAtomicResourceInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsCP_01, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2), 409); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void deleteResourceInstanceByDifferentDesignerTest_ServiceIsCheckedin() throws Exception { + + String oldServiceUniqueId = serviceDetails_01.getUniqueId(); + + RestResponse createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + RestResponse createAtomicResourceInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, + resourceDetailsCP_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstResp); + + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + changeServiceLifecycleState(serviceDetails_01, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2), + LifeCycleStatesEnum.CHECKOUT); + String newServiceUniqueId = serviceDetails_01.getUniqueId(); + + String oldVFInstanceUniqueId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + String newVFInstanceUniqueId = oldVFInstanceUniqueId.replaceAll(oldServiceUniqueId, + serviceDetails_01.getUniqueId()); + String oldAtomicResourceInstanceUniqueId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstResp); + String newAtomicResourceInstanceUniqueId = oldAtomicResourceInstanceUniqueId.replaceAll(oldServiceUniqueId, + serviceDetails_01.getUniqueId()); + + deleteVFInstanceAndAtomicResourceInstanceSuccessfully(newVFInstanceUniqueId, newAtomicResourceInstanceUniqueId, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2)); + + serviceDetails_01.setUniqueId(oldServiceUniqueId); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + + serviceDetails_01.setUniqueId(newServiceUniqueId); + updateExpectedReqCapAfterChangeLifecycleState(oldServiceUniqueId, serviceDetails_01.getUniqueId()); + deleteCompInstReqCapFromExpected(newVFInstanceUniqueId); + deleteCompInstReqCapFromExpected(newAtomicResourceInstanceUniqueId); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + private void deleteVFInstanceAndAtomicResourceInstanceSuccessfully(String vfInstanceUniqueId, + String atomicResourceInstanceUniqueId) throws IOException, Exception { + deleteVFInstanceAndAtomicResourceInstanceSuccessfully(vfInstanceUniqueId, atomicResourceInstanceUniqueId, + sdncDesignerDetails); + } + + private void deleteVFInstanceAndAtomicResourceInstanceSuccessfully(String vfInstanceUniqueId, + String atomicResourceInstanceUniqueId, User user) throws IOException, Exception { + RestResponse deleteVFInstResp = deleteVFInstance(vfInstanceUniqueId, serviceDetails_01, user); + ResourceRestUtils.checkDeleteResponse(deleteVFInstResp); + RestResponse deleteAtomicResourceInsResp = deleteAtomicInstanceForService(atomicResourceInstanceUniqueId, + serviceDetails_01, user); + ResourceRestUtils.checkDeleteResponse(deleteAtomicResourceInsResp); + } + + @Test + public void deleteResourceInstanceByTesterUserTest() throws Exception { + createVFInstanceAndAtomicResourceInstanceSuccessully(resourceDetailsVF_01, resourceDetailsCP_01); + deleteVFInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), resourceDetailsVF_01, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), 409); + deleteAtomicResourceInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsCP_01, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), 409); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void deleteResourceInstanceByNotASDCUserTest() throws Exception { + createVFInstanceAndAtomicResourceInstanceSuccessully(resourceDetailsVF_01, resourceDetailsCP_01); + User notASDCUser = new User(); + notASDCUser.setUserId("ab0001"); + deleteVFInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), resourceDetailsVF_01, + notASDCUser, 409); + deleteAtomicResourceInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsCP_01, notASDCUser, 409); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void deleteResourceInstanceFromCheckedinServiceTest() throws Exception { + createVFInstanceAndAtomicResourceInstanceSuccessully(resourceDetailsVF_01, resourceDetailsCP_01); + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + deleteVFInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), resourceDetailsVF_01, + sdncDesignerDetails, 409); + deleteAtomicResourceInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsCP_01, sdncDesignerDetails, 409); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void deleteResourceInstanceWhileResourceCertifiedStateTest() throws Exception { + certifyResource(resourceDetailsVF_01); + certifyResource(resourceDetailsCP_01); + + RestResponse createVFInstance = createVFInstance(serviceDetails_01, resourceDetailsVF_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstance); + String vfInstUniqueId = ResponseParser.getUniqueIdFromResponse(createVFInstance); + RestResponse atomicInstanceForService = createAtomicInstanceForService(serviceDetails_01, resourceDetailsCP_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(atomicInstanceForService); + String atomicInstUniqueId = ResponseParser.getUniqueIdFromResponse(atomicInstanceForService); + + deleteVFInstanceAndAtomicResourceInstanceSuccessfully(vfInstUniqueId, atomicInstUniqueId); + + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + // fail - bug DE191849 + @Test + public void deleteNotFoundResourceInstanceTest() throws Exception, Throwable { + + resourceDetailsVF_01.setUniqueId("1234"); + resourceDetailsCP_01.setUniqueId("5678"); + + deleteVFInstanceFail(ActionStatus.RESOURCE_NOT_FOUND, new ArrayList(Arrays.asList("")), + resourceDetailsVF_01, sdncDesignerDetails, 404); + deleteAtomicResourceInstanceFail(ActionStatus.RESOURCE_NOT_FOUND, new ArrayList(Arrays.asList("")), + resourceDetailsCP_01, sdncDesignerDetails, 404); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + + // {"requestError":{"serviceException":{"messageId":"SVC4503","text":"Error: + // Requested '%1' service was not found.","variables":["1234"]}}}> + } + + @Test + public void deleteResourceInstanceFromServiceNotFoundTest() throws Exception, Throwable { + serviceDetails_01.setUniqueId("1234"); + deleteVFInstanceFail(ActionStatus.SERVICE_NOT_FOUND, new ArrayList(Arrays.asList("")), + resourceDetailsVF_01, sdncDesignerDetails, 404); + deleteAtomicResourceInstanceFail(ActionStatus.SERVICE_NOT_FOUND, new ArrayList(Arrays.asList("")), + resourceDetailsCP_01, sdncDesignerDetails, 404); + } + + @Test + public void deleteResourceInstanceFromUnsupportedTypeTest() throws Exception { + String unsupportedType = "unsupportedType"; + RestResponse deleteVFInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance(sdncDesignerDetails, + serviceDetails_01.getUniqueId(), resourceDetailsVF_01.getUniqueId(), unsupportedType); + checkErrorMessage(ActionStatus.UNSUPPORTED_ERROR, new ArrayList(Arrays.asList(unsupportedType)), 400, + deleteVFInstanceResponse); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + @Test + public void deleteResourceInstanceWithEmptyServiceUidTest() throws Exception, Throwable { + serviceDetails_01.setUniqueId(""); + RestResponse deleteVFInstResp = deleteVFInstance(resourceDetailsVF_01.getUniqueId(), serviceDetails_01, + sdncDesignerDetails); + assertEquals(404, deleteVFInstResp.getErrorCode().intValue()); + } + + @Test + public void deleteResourceInstanceWithEmptyResourceInstanceUidTest() throws Exception, Throwable { + RestResponse deleteVFInstResp = deleteVFInstance("", serviceDetails_01, sdncDesignerDetails); + assertEquals(405, deleteVFInstResp.getErrorCode().intValue()); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + @Test + public void deleteResourceInstanceWithEmptyUserIdTest() throws Exception { + sdncDesignerDetails.setUserId(""); + deleteVFInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), resourceDetailsVF_01, + sdncDesignerDetails, 409); + deleteAtomicResourceInstanceFail(ActionStatus.RESTRICTED_OPERATION, new ArrayList(), + resourceDetailsCP_01, sdncDesignerDetails, 409); + getComponentAndValidateRIs(serviceDetails_01, 0, 0); + } + + // fail - bug DE188994 + @Test + public void associateResourceInstanceToResourceInstanceNotFoundTest() throws Exception, Throwable { + RestResponse createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + String capCompInstId = "1234"; + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + List capListBeforeAssociate = new ArrayList(); + CapabilityDefinition cap = new CapabilityDefinition(); + cap.setUniqueId(capCompInstId); + capListBeforeAssociate.add(cap); + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + assocaiteInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.RESOURCE_INSTANCE_NOT_FOUND, 404, + new ArrayList(Arrays.asList(capCompInstId))); + + CapReqDef capReqDefAfterAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capabilitiesAfterAssociate = capReqDefAfterAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List requirementsAfterAssoicate = capReqDefAfterAssociate.getRequirements() + .get(CAPABILITY_TYPE); + // AssertJUnit.assertEquals("Check requirement", reqListBeforeAssociate, + // requirementsAfterAssoicate); + // AssertJUnit.assertEquals("Check requirement", capListBeforeAssociate, + // capabilitiesAfterAssociate); + + getComponentAndValidateRIs(serviceDetails_01, 1, 0); + + // "messageId": "SVC4116", + // "text": "Error: Invalid Content.", + // "variables": [ + // "VF100 1", + // "9ae76786-2a9c-4409-95cb-db32885ed07f.eece8aaf-eb9f-4aff-b9a5-a11ca11de9e5.vf1001", + // "host" + // ] + } + + // this case is not relevant any more, it is tested as part of occurrences + // story + @Test(enabled = false) + public void associateOnceAgainExistingRelationTest() throws Exception { + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + associateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + ////////////////////////////////////////////// + // NO ERROR - RELATION ALREADY EXIST + // assocaiteInstancesFail(requirementDef, sdncDesignerDetails, + // ActionStatus.RESOURCE_INSTANCE_NOT_FOUND, 404, new + // ArrayList(Arrays.asList(capCompInstId))); + ////////////////////////////////////////////// + + CapReqDef capReqDefAfterAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListAfterAssociate = capReqDefAfterAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListAfterAssociate = capReqDefAfterAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + // AssertJUnit.assertEquals("Check requirement", null, + // reqListAfterAssociate); + // AssertJUnit.assertEquals("Check requirement", capListBeforeAssociate, + // capListAfterAssociate); + + getComponentAndValidateRIs(serviceDetails_01, 2, 1); + + // "messageId": "SVC4119", + // "text": "Error: No relation found between resource instances + // \u0027%1\u0027 and \u0027%2\u0027 for requirement \u0027%3\u0027.", + // "variables": [ + // "VF100 1", + // "VF_admin 2", + // "host" + + } + + @Test + public void associateInstancesInMissingServiceTest() throws Exception { + serviceDetails_01.setUniqueId("1234"); + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + assocaiteInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.SERVICE_NOT_FOUND, 404, + new ArrayList(Arrays.asList(""))); + } + + @Test + public void associateAfterDeletingResourceTest() throws Exception { + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + ResourceRestUtils.deleteResource(resourceDetailsVF_01.getUniqueId(), sdncDesignerDetails.getUserId()); + + associateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + CapReqDef capReqDefAfterAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListAfterAssociate = capReqDefAfterAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + + // for (CapabilityDefinition capabilityDefinition : + // capListBeforeAssociate) { + // if (capabilityDefinition.getType().equals(CAPABILITY_TYPE)){ + // capabilityDefinition.setMinOccurrences("0"); + // } + // } + // + // List reqListAfterAssociate = + // capReqDefAfterAssociate.getRequirements().get(CAPABILITY_TYPE); + // + // AssertJUnit.assertEquals("Check requirement", null, + // reqListAfterAssociate); + // + // AssertJUnit.assertEquals("Check requirement", capListBeforeAssociate, + // capListAfterAssociate); + + getComponentAndValidateRIs(serviceDetails_01, 2, 1); + } + + @Test + public void associateInstancesInCheckedinServiceTest() throws Exception { + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + + assocaiteInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.RESTRICTED_OPERATION, 409, + new ArrayList()); + + CapReqDef capReqDefAfterAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capabilitiesAfterAssociate = capReqDefAfterAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List requirementsAfterAssoicate = capReqDefAfterAssociate.getRequirements() + .get(CAPABILITY_TYPE); + AssertJUnit.assertEquals("Check requirement", reqListBeforeAssociate, requirementsAfterAssoicate); + AssertJUnit.assertEquals("Check requirement", capListBeforeAssociate, capabilitiesAfterAssociate); + + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + // fail - bug DE188994 + @Test + public void associateAfterCheckoutAllInstancesTest() throws Exception { + String firstVFUniqueId = resourceDetailsVF_01.getUniqueId(); + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + String secondVFUniqueId = resourceDetailsVF_02.getUniqueId(); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + changeResourceLifecycleState(resourceDetailsVF_01, sdncDesignerDetails.getUserId(), + LifeCycleStatesEnum.CHECKOUT); + changeResourceLifecycleState(resourceDetailsVF_02, sdncDesignerDetails.getUserId(), + LifeCycleStatesEnum.CHECKOUT); + + requirementDef.setFromNode( + requirementDef.getFromNode().replaceAll(firstVFUniqueId, resourceDetailsVF_01.getUniqueId())); + requirementDef + .setToNode(requirementDef.getToNode().replaceAll(secondVFUniqueId, resourceDetailsVF_02.getUniqueId())); + + assocaiteInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.RESTRICTED_OPERATION, 409, + new ArrayList()); + + CapReqDef capReqDefAfterAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capabilitiesAfterAssociate = capReqDefAfterAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List requirementsAfterAssoicate = capReqDefAfterAssociate.getRequirements() + .get(CAPABILITY_TYPE); + // AssertJUnit.assertEquals("Check requirement", reqListBeforeAssociate, + // requirementsAfterAssoicate); + // AssertJUnit.assertEquals("Check requirement", capListBeforeAssociate, + // capabilitiesAfterAssociate); + + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + + // "messageId": "SVC4116", + // "text": "Error: Invalid Content.", + // "variables": [ + // "e9dcea15-ce27-4381-a554-4278973cefb1.d0b3affd-cf92-4626-adfe-961b44103924.vf1001", + // "e9dcea15-ce27-4381-a554-4278973cefb1.d0b3affd-cf92-4626-adfe-961b44103924.vf1001", + // "host" + // ] + + } + + @Test + public void associateInstancesByDifferentUsersTest() throws Exception { + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + assocaiteInstancesFail(requirementDef, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2), + ActionStatus.RESTRICTED_OPERATION, 409, new ArrayList()); + assocaiteInstancesFail(requirementDef, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), + ActionStatus.RESTRICTED_OPERATION, 409, new ArrayList()); + assocaiteInstancesFail(requirementDef, ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR), + ActionStatus.RESTRICTED_OPERATION, 409, new ArrayList()); + assocaiteInstancesFail(requirementDef, ElementFactory.getDefaultUser(UserRoleEnum.OPS), + ActionStatus.RESTRICTED_OPERATION, 409, new ArrayList()); + assocaiteInstancesFail(requirementDef, ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1), + ActionStatus.RESTRICTED_OPERATION, 409, new ArrayList()); + + CapReqDef capReqDefAfterAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capabilitiesAfterAssociate = capReqDefAfterAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List requirementsAfterAssoicate = capReqDefAfterAssociate.getRequirements() + .get(CAPABILITY_TYPE); + AssertJUnit.assertEquals("Check requirement", reqListBeforeAssociate, requirementsAfterAssoicate); + AssertJUnit.assertEquals("Check requirement", capListBeforeAssociate, capabilitiesAfterAssociate); + + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + private void assocaiteInstancesFail(RequirementCapabilityRelDef requirementDef, User user, + ActionStatus actionStatus, int errorCode, List variables) throws IOException, Exception { + RestResponse associateInstancesResp = ComponentInstanceRestUtils.associateInstances(requirementDef, user, + serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + checkErrorMessage(actionStatus, variables, errorCode, associateInstancesResp); + } + + private void dissoicateInstancesFail(RequirementCapabilityRelDef requirementDef, User user, + ActionStatus actionStatus, int errorCode, List variables) throws IOException, Exception { + RestResponse dissoicateInstancesResp = ComponentInstanceRestUtils.dissociateInstances(requirementDef, user, + serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + checkErrorMessage(actionStatus, variables, errorCode, dissoicateInstancesResp); + } + + @Test + public void associateWithMissingServiceUidTest() throws Exception { + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + serviceDetails_01.setUniqueId(""); + RestResponse associateInstancesResp = ComponentInstanceRestUtils.associateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + assertEquals(404, associateInstancesResp.getErrorCode().intValue()); + } + + // fail - bug DE191824 + @Test + public void associateNotCompitableReqCapTest() throws Exception { + RestResponse createFirstAtomicResourceInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, + resourceDetailsCP_01, sdncDesignerDetails); + String reqCompInstName = ResponseParser.getNameFromResponse(createFirstAtomicResourceInstResp); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstAtomicResourceInstResp); + RestResponse createSecondAtomicResourceInstResp = createCheckedinAtomicInstanceForService(serviceDetails_01, + resourceDetailsVL_02, sdncDesignerDetails); + String capCompInstName = ResponseParser.getNameFromResponse(createSecondAtomicResourceInstResp); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondAtomicResourceInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + List variables = new ArrayList(); + variables.add(reqCompInstName); + variables.add(capCompInstName); + variables.add(REQUIREMENT_NAME); + + assocaiteInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.RESOURCE_INSTANCE_MATCH_NOT_FOUND, 404, + variables); + + CapReqDef capReqDefAfterAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capabilitiesAfterAssociate = capReqDefAfterAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List requirementsAfterAssoicate = capReqDefAfterAssociate.getRequirements() + .get(CAPABILITY_TYPE); + // AssertJUnit.assertEquals("Check requirement", reqListBeforeAssociate, + // requirementsAfterAssoicate); + // AssertJUnit.assertEquals("Check requirement", capListBeforeAssociate, + // capabilitiesAfterAssociate); + + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + + // {"requestError":{"serviceException":{"messageId":"SVC4119","text":"Error: + // No relation found between resource instances '%1' and '%2' for + // requirement '%3'.","variables":["CP100 1","VL200 2","host"]}}}> + } + + @Test + public void associateInstancesInTwoServiceVersionsTest() throws Exception { + String oldServiceUniqueId = serviceDetails_01.getUniqueId(); + RestResponse createFirstVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + associateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + getComponentAndValidateRIs(serviceDetails_01, 2, 1); + + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKOUT); + String secondServiceUniqueId = serviceDetails_01.getUniqueId(); + + serviceDetails_01.setUniqueId(oldServiceUniqueId); + getComponentAndValidateRIs(serviceDetails_01, 2, 1); + + updateCapabilitiesOwnerId(oldServiceUniqueId, capListBeforeAssociate, secondServiceUniqueId); + updateExpectedReqCapAfterChangeLifecycleState(oldServiceUniqueId, secondServiceUniqueId); + CapReqDef capReqDefAfterAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListAfterAssociate = capReqDefAfterAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListAfterAssociate = capReqDefAfterAssociate.getRequirements() + .get(CAPABILITY_TYPE); + // AssertJUnit.assertEquals("Check requirement", null, + // reqListAfterAssociate); + // AssertJUnit.assertEquals("Check capabilities", + // capListBeforeAssociate, capListAfterAssociate); + getComponentAndValidateRIs(serviceDetails_01, 2, 1); + + RestResponse createThirdVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqSecondCompInstId = ResponseParser.getUniqueIdFromResponse(createThirdVFInstResp); + + CapReqDef capReqDefBeforeSeconderyAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeSeconderyAssociate = capReqDefBeforeSeconderyAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeSeconderyAssociate = capReqDefBeforeSeconderyAssociate + .getRequirements().get(CAPABILITY_TYPE); + + capCompInstId = capCompInstId.replaceAll(oldServiceUniqueId, secondServiceUniqueId); + RequirementCapabilityRelDef secondRequirementDef = getReqCapRelation(reqSecondCompInstId, capCompInstId, + CAPABILITY_TYPE, REQUIREMENT_NAME, capListBeforeSeconderyAssociate, reqListBeforeSeconderyAssociate); + associateComponentInstancesForService(secondRequirementDef, serviceDetails_01, sdncDesignerDetails); + + CapReqDef capReqDefAfterSeconderyAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListAfterSeconderyAssociate = capReqDefAfterSeconderyAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListAfterSeconderyAssociate = capReqDefAfterSeconderyAssociate.getRequirements() + .get(CAPABILITY_TYPE); + // AssertJUnit.assertEquals("Check requirement", null, + // reqListAfterSeconderyAssociate); + // AssertJUnit.assertEquals("Check capabilities", + // capListBeforeAssociate, capListAfterSeconderyAssociate); + getComponentAndValidateRIs(serviceDetails_01, 3, 2); + } + + private void updateCapabilitiesOwnerId(String oldUniqueId, List capList, String newUniqueId) { + serviceDetails_01.setUniqueId(newUniqueId); + for (CapabilityDefinition cap : capList) { + String oldOwnerId = cap.getOwnerId(); + String newOwnerId = oldOwnerId.replaceAll(oldUniqueId, newUniqueId); + cap.setOwnerId(newOwnerId); + } + } + + @Test + public void dissociateRelationNotFoundTest() throws Exception { + createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, sdncDesignerDetails); + String reqCompInstId = "1234"; + createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, sdncDesignerDetails); + String capCompInstId = "4567"; + + CapReqDef capReqDef = ComponentRestUtils.getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + List capList = capReqDef.getCapabilities().get(CAPABILITY_TYPE); + List reqList = capReqDef.getRequirements().get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capList, reqList); + + List variables = new ArrayList(); + variables.add(reqCompInstId); + variables.add(capCompInstId); + variables.add(REQUIREMENT_NAME); + dissoicateInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND, + 404, variables); + + CapReqDef capReqDefAfterDissociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListAfterDissociate = capReqDefAfterDissociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListAfterDissociate = capReqDefAfterDissociate.getRequirements() + .get(CAPABILITY_TYPE); + + AssertJUnit.assertEquals("Check requirement", 1, reqListAfterDissociate.size()); + AssertJUnit.assertEquals("Check requirement", reqList, reqListAfterDissociate); + AssertJUnit.assertEquals("Check capabilities", capList, capListAfterDissociate); + + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + + } + + @Test + public void dissociateRelationInServiceNotFoundTest() throws Exception { + String uniqueId = "1234"; + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + serviceDetails_01.setUniqueId(uniqueId); + dissoicateInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.SERVICE_NOT_FOUND, 404, + new ArrayList(Arrays.asList(""))); + + } + + @Test + public void dissoicateRelationWhileInstanceNotFound() throws Exception { + String capUniqueId = "1234"; + + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, sdncDesignerDetails); + String capCompInstId = capUniqueId; + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + List variables = new ArrayList(); + variables.add(reqCompInstId); + variables.add(capCompInstId); + variables.add(REQUIREMENT_NAME); + dissoicateInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND, + 404, variables); + + CapReqDef capReqDefAfterDissociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListAfterDissociate = capReqDefAfterDissociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListAfterDissociate = capReqDefAfterDissociate.getRequirements() + .get(CAPABILITY_TYPE); + AssertJUnit.assertEquals("Check requirement", reqListBeforeAssociate, reqListAfterDissociate); + AssertJUnit.assertEquals("Check capabilities", capListBeforeAssociate, capListAfterDissociate); + + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void dissociateWhileServiceCheckedinTest() throws Exception { + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + dissoicateInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.RESTRICTED_OPERATION, 409, + new ArrayList()); + } + + @Test + public void dissoicateWithEmptyUserIdHeaderTest() throws Exception { + sdncDesignerDetails.setUserId(""); + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + dissoicateInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.RESTRICTED_OPERATION, 409, + new ArrayList()); + } + + @Test + public void dissociateWithMissingUidOfServiceTest() throws Exception { + serviceDetails_01.setUniqueId(""); + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + RestResponse dissociateResp = ComponentInstanceRestUtils.dissociateInstances(requirementDef, + sdncDesignerDetails, serviceDetails_01.getUniqueId(), ComponentTypeEnum.SERVICE); + assertEquals(404, dissociateResp.getErrorCode().intValue()); + } + + @Test + public void relationDeletedAfterDeletingResourceInstanceTest() throws Exception { + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + associateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + getComponentAndValidateRIs(serviceDetails_01, 2, 1); + + RestResponse deleteVFInstance = deleteVFInstance(reqCompInstId, serviceDetails_01, sdncDesignerDetails); + ComponentInstanceRestUtils.checkDeleteResponse(deleteVFInstance); + getComponentAndValidateRIs(serviceDetails_01, 1, 0); + } + + @Test + public void relationNotFoundInSecondVersionAfterDissociateTest() throws Exception { + String oldContainerUniqueIdToReplace = serviceDetails_01.getUniqueId(); + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + associateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + dissociateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKOUT); + + updateExpectedReqCapAfterChangeLifecycleState(oldContainerUniqueIdToReplace, serviceDetails_01.getUniqueId()); + getComponentAndValidateRIs(serviceDetails_01, 2, 0); + } + + @Test + public void dissociateOnceAgainTest() throws Exception { + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + String reqCompInsName = ResponseParser + .convertComponentInstanceResponseToJavaObject(createFirstVFInstResp.getResponse()).getName(); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + String capCompInstName = ResponseParser + .convertComponentInstanceResponseToJavaObject(createSecondVFInstResp.getResponse()).getName(); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, CAPABILITY_TYPE, + REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + associateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + dissociateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + + List variables = new ArrayList(); + variables.add(reqCompInsName); + variables.add(capCompInstName); + variables.add(REQUIREMENT_NAME); + + dissoicateInstancesFail(requirementDef, sdncDesignerDetails, ActionStatus.RESOURCE_INSTANCE_RELATION_NOT_FOUND, + 404, variables); + } + + // fail - bug : DE191707 + @Test + public void associateTwoRelations_CheckinCheckout_DissoicateOneRelationInSecondVersion() throws Exception { + String oldContainerUniqueIdToReplace = serviceDetails_01.getUniqueId(); + RestResponse createFirstVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createFirstVFInstResp); + RestResponse createSecondVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createSecondVFInstResp); + RestResponse createThirdVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + String secondReqCompInstId = ResponseParser.getUniqueIdFromResponse(createThirdVFInstResp); + + CapReqDef capReqDefBeforeAssociate = ComponentRestUtils + .getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, serviceDetails_01); + List capListBeforeAssociate = capReqDefBeforeAssociate.getCapabilities() + .get(CAPABILITY_TYPE); + List reqListBeforeAssociate = capReqDefBeforeAssociate.getRequirements() + .get(CAPABILITY_TYPE); + + RequirementCapabilityRelDef requirementDefFirstRelation = getReqCapRelation(reqCompInstId, capCompInstId, + CAPABILITY_TYPE, REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + RequirementCapabilityRelDef requirementDefSecondRelation = getReqCapRelation(secondReqCompInstId, capCompInstId, + CAPABILITY_TYPE, REQUIREMENT_NAME, capListBeforeAssociate, reqListBeforeAssociate); + + associateComponentInstancesForService(requirementDefFirstRelation, serviceDetails_01, sdncDesignerDetails); + associateComponentInstancesForService(requirementDefSecondRelation, serviceDetails_01, sdncDesignerDetails); + getComponentAndValidateRIs(serviceDetails_01, 3, 2); + + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKOUT); + String newContainerUniqueId = serviceDetails_01.getUniqueId(); + + // check if dissoicate of old relation is possibile + // dissoicateInstancesFail(requirementDefFirstRelation, + // sdncDesignerDetails, actionStatus, errorCode, variables); + getComponentAndValidateRIs(serviceDetails_01, 3, 2); + + requirementDefFirstRelation + .setFromNode(reqCompInstId.replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId)); + requirementDefFirstRelation + .setToNode(reqCompInstId.replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId)); + + dissociateComponentInstancesForService(requirementDefFirstRelation, serviceDetails_01, sdncDesignerDetails); + + // updateCapabilitiesOwnerId(oldContainerUniqueIdToReplace, + // capListBeforeAssociate, newContainerUniqueId); + // CapReqDef capReqDefAfterAssociate = + // ComponentRestUtils.getAndParseComponentRequirmentsCapabilities(sdncDesignerDetails, + // serviceDetails_01); + // List capListAfterAssociate = + // capReqDefAfterAssociate.getCapabilities().get(CAPABILITY_TYPE); + // List reqListAfterAssociate = + // capReqDefAfterAssociate.getRequirements().get(CAPABILITY_TYPE); + // AssertJUnit.assertEquals("Check requirement", reqListBeforeAssociate, + // reqListAfterAssociate); + // AssertJUnit.assertEquals("Check requirement", capListBeforeAssociate, + // capListAfterAssociate); + updateExpectedReqCapAfterChangeLifecycleState(oldContainerUniqueIdToReplace, serviceDetails_01.getUniqueId()); + getComponentAndValidateRIs(serviceDetails_01, 3, 1); + } + + @Test + public void createResourceInstancesAndUpdatedServiceMetadataTest() throws Exception, Exception { + serviceDetails_02.setUniqueId(serviceDetails_01.getUniqueId()); + createTwoCheckedinVFInstances(); + LifecycleRestUtils.changeResourceState(resourceDetailsCP_01, sdncDesignerDetails, "0.1", + LifeCycleStatesEnum.CHECKIN); + createVFInstanceAndAtomicResourceInstanceWithoutCheckin(resourceDetailsVF_01, resourceDetailsCP_01, + sdncDesignerDetails); + RestResponse updateServiceResp = ServiceRestUtils.updateService(serviceDetails_02, sdncDesignerDetails); + ServiceRestUtils.checkSuccess(updateServiceResp); + getComponentAndValidateRIs(serviceDetails_01, 4, 0); + } + + @Test(enabled = false) + public void forAcceptanceUserStory() throws Exception { + RestResponse createVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String reqCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + createVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_02, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + String capCompInstId = ResponseParser.getUniqueIdFromResponse(createVFInstResp); + + String capType = CAPABILITY_TYPE; + String reqName = REQUIREMENT_NAME; + + RestResponse getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + ResourceRestUtils.checkSuccess(getResourceResponse); + CapReqDef capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List capList = capReqDef.getCapabilities().get(capType); + List reqList = capReqDef.getRequirements().get(capType); + + RequirementCapabilityRelDef requirementDef = getReqCapRelation(reqCompInstId, capCompInstId, capType, reqName, + capList, reqList); + + associateComponentInstancesForService(requirementDef, serviceDetails_01, sdncDesignerDetails); + getResourceResponse = ComponentRestUtils.getComponentRequirmentsCapabilities(sdncDesignerDetails, + serviceDetails_01); + capReqDef = ResponseParser.parseToObject(getResourceResponse.getResponse(), CapReqDef.class); + List list = capReqDef.getRequirements().get(capType); + AssertJUnit.assertEquals("Check requirement", null, list); + + serviceDetails_02.setUniqueId(serviceDetails_01.getUniqueId()); + RestResponse updateServiceResp = ServiceRestUtils.updateService(serviceDetails_02, sdncDesignerDetails); + ServiceRestUtils.checkSuccess(updateServiceResp); + changeServiceLifecycleState(serviceDetails_01, sdncDesignerDetails, LifeCycleStatesEnum.CHECKIN); + getComponentAndValidateRIs(serviceDetails_01, 2, 1); + } + + @Test + public void testUnsatisfiedCpReqInService() throws Exception { + + // Certify all the needed atomic resources + RestResponse response = LifecycleRestUtils.certifyResource(resourceDetailsCP_01); + ResourceRestUtils.checkSuccess(response); + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails, + resourceDetailsVF_02.getUniqueId()); + ResourceRestUtils.checkSuccess(response); + response = LifecycleRestUtils.certifyResource(resourceDetailsVF_02); + ResourceRestUtils.checkSuccess(response); + capOwnerId = getUniqueIdOfFirstInstanceFromResponse(response); + + RestResponse createAtomicResourceInstance = createVFInstance(serviceDetails_01, resourceDetailsVF_02, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + String vfCompInstId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstance); + + createAtomicResourceInstance = createAtomicInstanceForService(serviceDetails_01, resourceDetailsCP_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createAtomicResourceInstance); + String compInstName = ResponseParser.getNameFromResponse(createAtomicResourceInstance); + String cpCompInstId = ResponseParser.getUniqueIdFromResponse(createAtomicResourceInstance); + + RestResponse submitForTesting = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + String[] variables = new String[] { serviceDetails_01.getName(), "service", "CP (Connection Point)", + compInstName, "requirement", "tosca.capabilities.network.Bindable", "fulfilled" }; + BaseValidationUtils.checkErrorResponse(submitForTesting, + ActionStatus.REQ_CAP_NOT_SATISFIED_BEFORE_CERTIFICATION, variables); + + fulfillCpRequirement(serviceDetails_01, cpCompInstId, vfCompInstId, capOwnerId, sdncDesignerDetails, + ComponentTypeEnum.SERVICE); + + submitForTesting = LifecycleRestUtils.changeServiceState(serviceDetails_01, sdncDesignerDetails, + LifeCycleStatesEnum.CERTIFICATIONREQUEST); + BaseValidationUtils.checkSuccess(submitForTesting); + } + + @Test + public void getVFInstanceSuccessfullyTest() throws Exception { + RestResponse createVFInstResp = createCheckedinVFInstance(serviceDetails_01, resourceDetailsVF_01, + sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + System.out.println("instance successfuly created"); + RestResponse getInstancesResponce = ComponentInstanceRestUtils.getComponentInstances(ComponentTypeEnum.SERVICE, + serviceDetails_01.getUniqueId(), sdncDesignerDetails); + + for (int i = 0; i < 1500; i++) { + createVFInstResp = createVFInstance(serviceDetails_01, resourceDetailsVF_01, sdncDesignerDetails); + ResourceRestUtils.checkCreateResponse(createVFInstResp); + System.out.println("instance " + i + "successfuly created"); + } + + getInstancesResponce = ComponentInstanceRestUtils.getComponentInstances(ComponentTypeEnum.SERVICE, + serviceDetails_01.getUniqueId(), sdncDesignerDetails); + + BaseValidationUtils.checkSuccess(getInstancesResponce); + + } + + private String getUniqueIdOfFirstInstanceFromResponse(RestResponse response) { + try { + JSONArray value = ResponseParser.getListFromJson(response, "componentInstances"); + return ResponseParser.getValueFromJsonResponse(value.get(0).toString(), "uniqueId"); + } catch (Exception e) { + return null; + } + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/UpdateServiceMetadataTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/UpdateServiceMetadataTest.java new file mode 100644 index 0000000000..262cb65adf --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/service/UpdateServiceMetadataTest.java @@ -0,0 +1,2158 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.service; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.codehaus.jettison.json.JSONException; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ServiceValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class UpdateServiceMetadataTest extends ComponentBaseTest { + + protected ArrayList listForMessage = new ArrayList(); + + protected ResourceReqDetails resourceDetails; + protected ServiceReqDetails serviceDetails; + protected User sdncDesignerDetails; + protected User sdncDesignerDetails2; + protected User sdncAdminDetails; + protected User sdncGovernorDeatails; + protected User sdncTesterDetails; + protected User sdncOpsDetails; + protected ComponentInstanceReqDetails resourceInstanceReqDetails; + protected Component resourceDetailsVFCcomp; + protected Component serviceDetailsCompp; + + @Rule + public static TestName name = new TestName(); + protected ServiceReqDetails updatedServiceDetails; + + public UpdateServiceMetadataTest() { + super(name, UpdateServiceMetadataTest.class.getName()); + } + + @BeforeMethod + public void setUp() throws Exception { + + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncDesignerDetails2 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER2); + sdncAdminDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncAdminDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN4); + sdncGovernorDeatails = ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR); + sdncTesterDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + sdncOpsDetails = ElementFactory.getDefaultUser(UserRoleEnum.OPS); + resourceDetailsVFCcomp = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVFCcomp, UserRoleEnum.DESIGNER, + true, true); + + AtomicOperationUtils.changeComponentState(resourceDetailsVFCcomp, UserRoleEnum.DESIGNER, + LifeCycleStatesEnum.CERTIFY, true); + Service serviceServ = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVFCcomp, serviceServ, + UserRoleEnum.DESIGNER, true); + + serviceDetails = new ServiceReqDetails(serviceServ); + updatedServiceDetails = updatedServiceDetails(serviceDetails); + + } + + protected void certifyService(ServiceReqDetails serviceDetails, String version) throws Exception { + LifecycleRestUtils.certifyService(serviceDetails); + } + + protected ServiceReqDetails updatedServiceDetails(ServiceReqDetails service) { + ServiceReqDetails updatedServiceDetails = new ServiceReqDetails(service); + + updatedServiceDetails.setDescription("updatedDescription"); + updatedServiceDetails.setName(service.getName()); + updatedServiceDetails.setProjectCode("987654654"); + updatedServiceDetails.setIcon("icon-service-red3"); + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("updateTag", updatedServiceDetails.getName()))); + updatedServiceDetails.removeAllCategories(); + updatedServiceDetails.setCategories(null); + updatedServiceDetails.addCategory(ServiceCategoriesEnum.VOIP.getValue()); + updatedServiceDetails.setContactId("xy0123"); + + return updatedServiceDetails; + } + + protected void addMandatoryArtifactsToService() throws Exception { + // TODO Andrey US575052 + // ServiceRestUtils.addServiceMandatoryArtifacts(sdncDesignerDetails, + // createServiceResponse); + } + + protected void getServiceAndValidate(ServiceReqDetails excpectedService, User creator, User updater, + LifecycleStateEnum lifeCycleState) throws Exception { + RestResponse getServiceResponse = ServiceRestUtils.getService(excpectedService.getUniqueId(), + sdncDesignerDetails); + AssertJUnit.assertNotNull("check response object is not null after updating service", getServiceResponse); + AssertJUnit.assertNotNull("check if error code exists in response after updating service", + getServiceResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after updating service", 200, + getServiceResponse.getErrorCode().intValue()); + Service actualService = ResponseParser.convertServiceResponseToJavaObject(getServiceResponse.getResponse()); + ServiceValidationUtils.validateServiceResponseMetaData(excpectedService, actualService, creator, updater, + lifeCycleState); + } + + public void getServiceAndValidate(ServiceReqDetails excpectedService, LifecycleStateEnum lifecycleState) + throws Exception { + getServiceAndValidate(excpectedService, sdncDesignerDetails, sdncDesignerDetails, lifecycleState); + } + + protected void validateResponse(RestResponse response, int errorCode, ActionStatus actionResponse, + List listOfVariables) throws Exception { + AssertJUnit.assertNotNull("check response object is not null after updating service", response); + AssertJUnit.assertNotNull("check if error code exists in response after updating service", + response.getErrorCode()); + AssertJUnit.assertEquals("Check response code after updating service", errorCode, + response.getErrorCode().intValue()); + + if (actionResponse != null) { + ErrorValidationUtils.checkBodyResponseOnError(actionResponse.name(), listOfVariables, + response.getResponse()); + return; + } + + Service actualService = ResponseParser.convertServiceResponseToJavaObject(response.getResponse()); + ServiceValidationUtils.validateServiceResponseMetaData(updatedServiceDetails, actualService, + sdncDesignerDetails, sdncDesignerDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + protected void validateActualVsExpected(ServiceReqDetails expectedService, RestResponse actualServiceFromResponse) { + Service actualService = ResponseParser + .convertServiceResponseToJavaObject(actualServiceFromResponse.getResponse()); + ServiceValidationUtils.validateServiceResponseMetaData(updatedServiceDetails, actualService, + sdncDesignerDetails, sdncDesignerDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + protected String multipleString(String ch, int repeat) { + return StringUtils.repeat(ch, repeat); + } + + protected void correctUpdate() throws Exception { + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 200, null, listForMessage); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + protected void updateWithInvalidValue(ActionStatus invalidValue, List arr) throws Exception { + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, invalidValue, arr); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + protected void charactersInRangeChecking(int min, int max, String field) throws Exception { + if (field != null) { + if (field == "name") { + for (char ch = (char) min; ch <= (char) max; ch++) { + updatedServiceDetails.setName("testname" + String.valueOf(ch)); + updatedServiceDetails.setTags( + addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + updateWithInvalidValue(ActionStatus.INVALID_COMPONENT_NAME, + new ArrayList<>(Arrays.asList("Service"))); + } + } else if (field == "icon") { + for (char ch = (char) min; ch <= (char) max; ch++) { + updatedServiceDetails.setIcon("testname" + String.valueOf(ch)); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_ICON, + new ArrayList<>(Arrays.asList("Service"))); + } + } else if (field == "tags") { + List variables = Arrays.asList("Service", "tag"); + for (char ch = (char) min; ch <= (char) max; ch++) { + updatedServiceDetails.setTags( + new ArrayList<>(Arrays.asList(String.valueOf(ch), updatedServiceDetails.getName()))); + updateWithInvalidValue(ActionStatus.INVALID_FIELD_FORMAT, variables); + } + } else if (field == "category") { + for (char ch = (char) min; ch <= (char) max; ch++) { + updatedServiceDetails.addCategoryChain(multipleString("1", 5) + String.valueOf(ch), + multipleString("1", 5) + String.valueOf(ch)); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CATEGORY, + new ArrayList<>(Arrays.asList("Service"))); + } + } + + else if (field == "projectCode") { + for (char ch = (char) min; ch <= (char) max; ch++) { + updatedServiceDetails.setProjectCode(multipleString("1", 5) + String.valueOf(ch)); + updateWithInvalidValue(ActionStatus.INVALID_PROJECT_CODE, listForMessage); + } + } + + else + return; + } + + } + + protected void specialCharsChecking(String field) throws Exception { + charactersInRangeChecking(33, 44, field); + charactersInRangeChecking(47, 47, field); + charactersInRangeChecking(58, 64, field); + charactersInRangeChecking(91, 94, field); + charactersInRangeChecking(96, 96, field); + charactersInRangeChecking(123, 126, field); + } + + @Test + public void updateServiceSuccessfully() throws Exception { + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 200, null, listForMessage); + + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + + } + + protected void checkErrorResponse(ActionStatus actionStatus, ArrayList arrList, RestResponse response) + throws Exception, JSONException { + ErrorValidationUtils.checkBodyResponseOnError(actionStatus.name(), arrList, response.getResponse()); + } + + protected List addServiceNameToTagsList(String serviceName, List tagsList) { + tagsList.add(serviceName); + return tagsList; + + } + + // @Test + // public void updateMetadateSuccessTest() throws Exception { + // CloseableHttpClient httpClient = HttpClients.createDefault(); + // HttpGet httpGet = + // ServiceRestUtils.createGetServiceGetRquest(serviceDetails, + // sdncDesignerDetails); + // CloseableHttpResponse response = httpClient.execute(httpGet); + // assertTrue(response.getStatusLine().getStatusCode() == 200); + // String responseString = new + // BasicResponseHandler().handleResponse(response); + // Service serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(responseString); + // assertTrue("service object creation failed the returned object is null", + // serviceObject != null); + // String currentCategory = serviceObject.getCategories().get(0).getName(); + // String currentServiceName = serviceObject.getName(); + // String currentProjectCode = serviceObject.getProjectCode(); + // String currentIcon = serviceObject.getIcon(); + // String currentDescription = serviceObject.getDescription(); + // List currentTags = serviceObject.getTags(); + // + // String newCategory = ServiceCategoriesEnum.VOIP.getValue(); + // serviceDetails.addCategory(newCategory); + // // String newServiceName = "updated name"; + // // serviceDetails.setServiceName(newServiceName); + // String newProjectCode = "68686868"; + // serviceDetails.setProjectCode(newProjectCode); + // String newIcon = "updated-icon"; + // serviceDetails.setIcon(newIcon); + // String newDescription = "updated description "; + // serviceDetails.setDescription(newDescription); + // List newTags = new ArrayList<>(); + // newTags.add("update1"); + // newTags.add("update2"); + // newTags.add(currentServiceName); + // serviceDetails.setTags(newTags); + // HttpPut httpPut = + // ServiceRestUtils.createUpdateServiceMetaDataPutRequest(serviceDetails, + // sdncDesignerDetails); + // response = httpClient.execute(httpPut); + // assertTrue(response.getStatusLine().getStatusCode() == 200); + // responseString = new BasicResponseHandler().handleResponse(response); + // String serviceUid = + // ServiceRestUtils.getServiceUniqueIdFromString(responseString); + // + // ServiceReqDetails details = new ServiceReqDetails(); + // details.setUniqueId(serviceUid); + // + // httpGet = ServiceRestUtils.createGetServiceGetRquest(details, + // sdncDesignerDetails); + // response = httpClient.execute(httpGet); + // assertTrue(response.getStatusLine().getStatusCode() == 200); + // responseString = new BasicResponseHandler().handleResponse(response); + // serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(responseString); + // assertTrue("service object creation failed the returned object is null", + // serviceObject != null); + // String updatedCategory = serviceObject.getCategories().get(0).getName(); + // String updatedServiceName = serviceObject.getName(); + // String updatedProjectCode = serviceObject.getProjectCode(); + // String updatedIcon = serviceObject.getIcon(); + // String updatedDescription = serviceObject.getDescription(); + // List updatedTags = serviceObject.getTags(); + // assertFalse("category did not cahnge", + // currentCategory.equals(updatedCategory)); + // assertEquals("categoruy did not match expacted value", updatedCategory, + // newCategory); + // // assertFalse("service name did not change", + // currentServiceName.equals(updatedServiceName) ); + // // assertEquals("service name did not match expacted + // value",updatedServiceName,newServiceName); + // assertFalse("projectCode did not change", + // currentProjectCode.equals(updatedProjectCode)); + // assertEquals("projectCode not match expacted value", updatedProjectCode, + // newProjectCode); + // assertFalse("icon did not change", currentIcon.equals(updatedIcon)); + // assertEquals("icon did not match expacted value", updatedIcon, newIcon); + // assertFalse("description did not change", + // currentDescription.equals(updatedDescription)); + // assertEquals("description did not match expacted value", "updated + // description", updatedDescription); + // assertFalse("tags did not change", currentTags.containsAll(updatedTags)); + // assertTrue("tags did not match expacted value", + // updatedTags.containsAll(newTags)); + // } + + @Test + public void updateService_ByOtherDesigner() throws Exception { + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails2); + validateResponse(updateServiceResponse, 409, ActionStatus.RESTRICTED_OPERATION, listForMessage); + + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void updateService_ByAdmin() throws Exception { + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncAdminDetails); + validateResponse(updateServiceResponse, 409, ActionStatus.RESTRICTED_OPERATION, listForMessage); + + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void updateServiceNotExist() throws Exception { + updatedServiceDetails.setUniqueId("nnnnn"); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 404, ActionStatus.SERVICE_NOT_FOUND, + new ArrayList(Arrays.asList(""))); + } + + @Test + public void updateCheckedinService() throws Exception { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 409, ActionStatus.RESTRICTED_OPERATION, listForMessage); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); + } + + @Test + public void updateCertifiedService() throws Exception { + // addMandatoryArtifactsToService(); + certifyService(serviceDetails, serviceDetails.getVersion()); + + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 409, ActionStatus.RESTRICTED_OPERATION, listForMessage); + getServiceAndValidate(serviceDetails, sdncDesignerDetails, sdncAdminDetails, LifecycleStateEnum.CERTIFIED); + } + + // TODO Irrelevant + // @Test(enabled = false) + // public void updateService_NameCaseSensitiveTest() throws Exception { + // ServiceRestUtils.setServiceUniqueId(serviceDetails.getName().toUpperCase()); + // + // RestResponse updateServiceResponse = + // ServiceRestUtils.updateService(updatedServiceDetails, + // sdncDesignerDetails); + // validateResponse(updateServiceResponse, 200, null, listForMessage); + // + // Service serviceFromJsonResponse = + // ResponseParser.convertServiceResponseToJavaObject(updateServiceResponse.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(updatedServiceDetails, + // serviceFromJsonResponse, sdncDesignerDetails, (LifecycleStateEnum)null); + // + // getServiceAndValidate(updatedServiceDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // } + + // @Test + // public void updateApprovedDistributionServiceTest() throws Exception { + // // addMandatoryArtifactsToService(); + // certifyService(serviceDetails, serviceDetails.getVersion()); + // + // RestResponse approveResponse = + // ServiceRestUtils.sendApproveDistribution(sdncAdminDetails, + // serviceDetails.getUniqueId(), userRemarks); + // // validateResponse(approveResponse, 200, null, listForMessage); + // + // RestResponse updateServiceResponse = + // ServiceRestUtils.updateService(updatedServiceDetails, + // sdncDesignerDetails); + // validateResponse(updateServiceResponse, 409, + // ActionStatus.RESTRICTED_OPERATION, listForMessage); + // + // getServiceAndValidate(serviceDetails, sdncDesignerDetails, + // sdncAdminDetails,LifecycleStateEnum.CERTIFIED); + // } + + @Test + public void updateServiceByMethod_delete() throws Exception { + RestResponse updateServiceResponse = ServiceRestUtils.createServiceByHttpMethod(updatedServiceDetails, + sdncDesignerDetails, "DELETE", Urls.UPDATE_SERVICE_METADATA); + validateResponse(updateServiceResponse, 405, ActionStatus.NOT_ALLOWED, listForMessage); + + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void updateServiceByMethod_get() throws Exception { + RestResponse updateServiceResponse = ServiceRestUtils.createServiceByHttpMethod(updatedServiceDetails, + sdncDesignerDetails, "GET", Urls.UPDATE_SERVICE_METADATA); + validateResponse(updateServiceResponse, 405, ActionStatus.NOT_ALLOWED, listForMessage); + + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void updateServiceByMethod_post() throws Exception { + RestResponse updateServiceResponse = ServiceRestUtils.createServiceByHttpMethod(updatedServiceDetails, + sdncDesignerDetails, "POST", Urls.UPDATE_SERVICE_METADATA); + validateResponse(updateServiceResponse, 405, ActionStatus.NOT_ALLOWED, listForMessage); + + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void updateCheckoutCertifiedService() throws Exception // certify a + // service + // and + // checkout + // it + { + // addMandatoryArtifactsToService(); + certifyService(serviceDetails, serviceDetails.getVersion()); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.SERVICE_CATEGORY_CANNOT_BE_CHANGED, listForMessage); + + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + // ---------------------------------------------------------Validation + // Tests--------------------------------------------------------- + + @Test + public void missingCategoryTest1() throws Exception { + List categories = updatedServiceDetails.getCategories(); + CategoryDefinition categoryDefinition = categories.get(0); + CategoryDefinition categoryDefinition2 = categoryDefinition; + categoryDefinition2.setName(""); + categories.set(0, categoryDefinition2); + updatedServiceDetails.setCategories(categories); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.COMPONENT_MISSING_CATEGORY, Arrays.asList("Service")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingCategoryTest2() throws Exception { + updatedServiceDetails.setCategories(null); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.COMPONENT_MISSING_CATEGORY, Arrays.asList("Service")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingServiceNameTest1() throws Exception { + updatedServiceDetails.setName(StringUtils.EMPTY); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.MISSING_COMPONENT_NAME, Arrays.asList("Service")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingServiceNameTest2() throws Exception { + + updatedServiceDetails.setName(null); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.MISSING_COMPONENT_NAME, Arrays.asList("Service")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + // TODO Irrelevant + @Test(enabled = false) + public void missingProjectCodeTest1() throws Exception { + updatedServiceDetails.setProjectCode(StringUtils.EMPTY); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.MISSING_PROJECT_CODE, listForMessage); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + // TODO Irrelevant + @Test(enabled = false) + public void missingProjectCodeTest2() throws Exception { + + updatedServiceDetails.setProjectCode(null); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.MISSING_PROJECT_CODE, listForMessage); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingIconTest1() throws Exception { + updatedServiceDetails.setIcon(StringUtils.EMPTY); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.COMPONENT_MISSING_ICON, Arrays.asList("Service")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingIconTest2() throws Exception { + updatedServiceDetails.setIcon(null); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.COMPONENT_MISSING_ICON, Arrays.asList("Service")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingDescriptionTest1() throws Exception { + updatedServiceDetails.setDescription(StringUtils.EMPTY); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.COMPONENT_MISSING_DESCRIPTION, + Arrays.asList("Service")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingDescriptionTest2() throws Exception { + updatedServiceDetails.setDescription(null); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.COMPONENT_MISSING_DESCRIPTION, + Arrays.asList("Service")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingTagsTest1() throws Exception { + updatedServiceDetails.setTags(new ArrayList()); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.COMPONENT_MISSING_TAGS, listForMessage); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingTagsTest2() throws Exception { + updatedServiceDetails.setTags(null); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.COMPONENT_MISSING_TAGS, listForMessage); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingTagsTest3() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList(StringUtils.EMPTY))); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.INVALID_FIELD_FORMAT, + Arrays.asList("Service", "tag")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void missingTagsTest4() throws Exception { + updatedServiceDetails + .setTags(new ArrayList<>(Arrays.asList(StringUtils.EMPTY, updatedServiceDetails.getName()))); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + validateResponse(updateServiceResponse, 400, ActionStatus.INVALID_FIELD_FORMAT, + Arrays.asList("Service", "tag")); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + // update non-settable/"updatable" parameters tests + + // ------------------------------------------correct + // values------------------------------------------ + @Test + public void contactIdValidationTest1() throws Exception { + updatedServiceDetails.setContactId("ab3456"); + correctUpdate(); + } + + @Test + public void contactIdValidationTest2() throws Exception { + + updatedServiceDetails.setContactId("cd789E"); + correctUpdate(); + } + + @Test + public void contactIdValidationTest3() throws Exception { + + updatedServiceDetails.setContactId("ef4567"); + correctUpdate(); + } + + @Test + public void contactIdValidationTest4() throws Exception { + updatedServiceDetails.setContactId("AA012A"); + correctUpdate(); + } + + @Test + public void contactIdValidationTest5() throws Exception { + updatedServiceDetails.setContactId("CD012c"); + correctUpdate(); + } + + @Test + public void contactIdValidationTest6() throws Exception { + updatedServiceDetails.setContactId("EF0123"); + correctUpdate(); + } + + // ------------------------------------------invalid + // values------------------------------------------ + @Test + public void contactIdValidationTest7() throws Exception { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + updatedServiceDetails.setContactId("ab0001"); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + } + + @Test + public void contactIdValidationTest8() throws Exception { + // addMandatoryArtifactsToService(); + + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + updatedServiceDetails = new ServiceReqDetails(certifyService); + updatedServiceDetails.setContactId("ab0001"); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + } + + @Test + public void contactIdValidationTest9() throws Exception { + updatedServiceDetails.setContactId("01345a"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, Arrays.asList("Service")); + } + + @Test + public void contactIdValidationTest10() throws Exception { + updatedServiceDetails.setContactId("0y000B"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, Arrays.asList("Service")); + } + + @Test + public void contactIdValidationTest11() throws Exception { + updatedServiceDetails.setContactId("Y1000b"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, Arrays.asList("Service")); + } + + @Test + public void contactIdValidationTest12() throws Exception { + updatedServiceDetails.setContactId("abxyzC"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, Arrays.asList("Service")); + } + + @Test + public void contactIdValidationTest13() throws Exception { + updatedServiceDetails.setContactId("cdXYZc"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest14() throws Exception { + updatedServiceDetails.setContactId("efXY1D"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest15() throws Exception { + updatedServiceDetails.setContactId("EFabcD"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest16() throws Exception { + updatedServiceDetails.setContactId("EFABCD"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest17() throws Exception { + updatedServiceDetails.setContactId("EFABC1"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest18() throws Exception { + updatedServiceDetails.setContactId("efui1D"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest19() throws Exception { + updatedServiceDetails.setContactId("efui1!"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest20() throws Exception { + updatedServiceDetails.setContactId("ef555!"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest21() throws Exception { + updatedServiceDetails.setContactId(",f555"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest22() throws Exception { + updatedServiceDetails.setContactId("EF55.5"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest23() throws Exception { + updatedServiceDetails.setContactId("ab000"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest24() throws Exception { + updatedServiceDetails.setContactId("ab000c0"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest25() throws Exception { + updatedServiceDetails.setContactId(" ab0001"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CONTACT, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void contactIdValidationTest26() throws Exception { + // addMandatoryArtifactsToService(); + certifyService(serviceDetails, serviceDetails.getVersion()); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + updatedServiceDetails = new ServiceReqDetails(serviceDetails); + updatedServiceDetails.setContactId("xy0002"); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest1() throws Exception { + updatedServiceDetails.setName(multipleString("a", 49)); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest2() throws Exception { + updatedServiceDetails.setName(multipleString("b", 50)); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest3() throws Exception { + updatedServiceDetails.setName("testNamE"); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest4() throws Exception { + updatedServiceDetails.setName("Testname"); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest5() throws Exception { + updatedServiceDetails.setName("Test_name"); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest6() throws Exception { + updatedServiceDetails.setName("Test name"); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest7() throws Exception { + updatedServiceDetails.setName("Test-name"); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest8() throws Exception { + updatedServiceDetails.setName("Test.name"); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest9() throws Exception { + updatedServiceDetails.setName("...1..."); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest10() throws Exception { + updatedServiceDetails.setName("-a_1. Arrrrrr"); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest11() throws Exception { + updatedServiceDetails.setName("Testname1234567890"); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + correctUpdate(); + } + + @Test + public void serviceNameValidationTest14() throws Exception { + updatedServiceDetails.setName(StringUtils.SPACE); // one space with + // nothing + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + // updateWithInvalidValue(ActionStatus.INVALID_COMPONENT_NAME, new + // ArrayList<>(Arrays.asList("Service"))); + validateResponse(updateServiceResponse, 400, ActionStatus.MISSING_COMPONENT_NAME, + new ArrayList<>(Arrays.asList("Service"))); + } + + // ------------------------------------------invalid + // values------------------------------------------ + @Test + public void serviceNameValidationTest12() throws Exception { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + updatedServiceDetails.setName("TestNamE"); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN); + } + + @Test + public void serviceNameValidationTest13() throws Exception { + updatedServiceDetails.setName(multipleString("c", 51)); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + updateWithInvalidValue(ActionStatus.COMPONENT_NAME_EXCEEDS_LIMIT, + new ArrayList<>(Arrays.asList("Service", "50"))); + } + + @Test + public void serviceNameValidationTest15() throws Exception { + specialCharsChecking("name"); + } + + @Test + public void serviceNameValidationTest16() throws Exception { + // addMandatoryArtifactsToService(); + LifecycleRestUtils.certifyService(serviceDetails); + updatedServiceDetails.setName("testnamename"); + updatedServiceDetails.setCategories(serviceDetails.getCategories()); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + getServiceAndValidate(serviceDetails, sdncDesignerDetails, sdncTesterDetails, LifecycleStateEnum.CERTIFIED); + } + + @Test + public void serviceNameValidationTest17() throws Exception { + // addMandatoryArtifactsToService(); + certifyService(serviceDetails, serviceDetails.getVersion()); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + updatedServiceDetails.setName("TestNamE"); + updatedServiceDetails.setCategories(serviceDetails.getCategories()); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + RestResponse updateServiceResponse2 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + validateResponse(updateServiceResponse2, 400, ActionStatus.SERVICE_NAME_CANNOT_BE_CHANGED, listForMessage); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void serviceNameValidationTest18() throws Exception { + updatedServiceDetails.setName(" testname "); + updatedServiceDetails + .setTags(addServiceNameToTagsList(updatedServiceDetails.getName(), updatedServiceDetails.getTags())); + RestResponse updateServiceResponse1 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse1); + assertNotNull(updateServiceResponse1.getErrorCode()); + assertEquals(200, updateServiceResponse1.getErrorCode().intValue()); + updatedServiceDetails.setName(updatedServiceDetails.getName()); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse1); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void iconValidationTest1() throws Exception { + updatedServiceDetails.setIcon(multipleString("a", 24)); + correctUpdate(); + } + + @Test + public void iconValidationTest2() throws Exception { + updatedServiceDetails.setIcon(multipleString("b", 25)); + correctUpdate(); + } + + @Test + public void iconValidationTest3() throws Exception { + updatedServiceDetails.setIcon("testNamE"); + correctUpdate(); + } + + @Test + public void iconValidationTest4() throws Exception { + updatedServiceDetails.setIcon("Testname"); + correctUpdate(); + } + + @Test + public void iconValidationTest5() throws Exception { + updatedServiceDetails.setIcon("Test_name"); + correctUpdate(); + } + + @Test + public void iconValidationTest6() throws Exception { + updatedServiceDetails.setIcon("Test-name"); + correctUpdate(); + } + + @Test + public void iconValidationTest7() throws Exception { + updatedServiceDetails.setIcon("Testname1234567890"); + correctUpdate(); + } + + @Test + public void iconValidationTest8() throws Exception { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + updatedServiceDetails.setIcon("TestNamE"); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + } + + @Test + public void iconValidationTest9() throws Exception { + // addMandatoryArtifactsToService(); + LifecycleRestUtils.certifyService(serviceDetails); + updatedServiceDetails.setIcon("testnamename"); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + } + + // ------------------------------------------invalid + // values------------------------------------------ + @Test + public void iconValidationTest10() throws Exception { + updatedServiceDetails.setIcon("Test name"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_ICON, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void iconValidationTest11() throws Exception { + updatedServiceDetails.setIcon(StringUtils.SPACE); // one space with + // nothing + updateWithInvalidValue(ActionStatus.COMPONENT_MISSING_ICON, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void iconValidationTest12() throws Exception { + updatedServiceDetails.setIcon("Test.name"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_ICON, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void iconValidationTest13() throws Exception { + specialCharsChecking("icon"); + charactersInRangeChecking(46, 46, "icon"); + } + + @Test + public void iconValidationTest14() throws Exception { + updatedServiceDetails.setIcon(multipleString("c", 26)); + updateWithInvalidValue(ActionStatus.COMPONENT_ICON_EXCEEDS_LIMIT, + new ArrayList<>(Arrays.asList("Service", "25"))); + } + + @Test + public void iconValidationTest15() throws Exception { + // addMandatoryArtifactsToService(); + RestResponse certifyServiceResp = LifecycleRestUtils.certifyService(serviceDetails); + Service certifyServiceServ = ResponseParser + .convertServiceResponseToJavaObject(certifyServiceResp.getResponse()); + ServiceReqDetails certifyService = new ServiceReqDetails(certifyServiceServ); + updatedServiceDetails = new ServiceReqDetails(certifyService); + updatedServiceDetails.setIcon("testnamename"); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + } + + @Test + public void iconValidationTest16() throws Exception { + // addMandatoryArtifactsToService(); + certifyService(serviceDetails, serviceDetails.getVersion()); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + updatedServiceDetails = new ServiceReqDetails(serviceDetails); + updatedServiceDetails.setIcon("TestNamE"); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.SERVICE_ICON_CANNOT_BE_CHANGED, listForMessage, updateServiceResponse); + } + + @Test + public void iconValidationTest17() throws Exception { + updatedServiceDetails.setIcon(" Icon "); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_ICON, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void categoryValidationTest1() throws Exception { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + updatedServiceDetails.addCategory(ServiceCategoriesEnum.VOIP.getValue()); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + } + + @Test + public void categoryValidationTest2() throws Exception { + // updatedServiceDetails.addCategory("someCategory"); + updatedServiceDetails.setCategories(null); + updatedServiceDetails.addCategoryChain("someCategory", null); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CATEGORY, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void categoryValidationTest3() throws Exception { + updatedServiceDetails.setCategories(null); + updatedServiceDetails.addCategoryChain("SomeCategory10", null); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CATEGORY, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void categoryValidationTest4() throws Exception { + updatedServiceDetails.setCategories(null); + updatedServiceDetails.addCategoryChain("some Category", null); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_CATEGORY, new ArrayList<>(Arrays.asList("Service"))); + } + + @Test + public void categoryValidationTest5() throws Exception { + // addMandatoryArtifactsToService(); + certifyService(serviceDetails, serviceDetails.getVersion()); + updatedServiceDetails = new ServiceReqDetails(serviceDetails); + updatedServiceDetails.addCategory("Network L1-3"); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + } + + @Test + public void categoryValidationTest6() throws Exception { + // addMandatoryArtifactsToService(); + certifyService(serviceDetails, serviceDetails.getVersion()); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + updatedServiceDetails = new ServiceReqDetails(serviceDetails); + updatedServiceDetails = serviceDetails; + List categories = updatedServiceDetails.getCategories(); + CategoryDefinition categoryDefinition = categories.get(0); + CategoryDefinition categoryDefinition2 = categoryDefinition; + categoryDefinition2.setName("ccc"); + categories.set(0, categoryDefinition2); + updatedServiceDetails.setCategories(categories); + RestResponse updateServiceResponse2 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + validateResponse(updateServiceResponse2, 400, ActionStatus.SERVICE_CATEGORY_CANNOT_BE_CHANGED, listForMessage); + getServiceAndValidate(serviceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void categoryValidationTest7() throws Exception { + updatedServiceDetails.removeAllCategories(); + updatedServiceDetails.addCategory(ServiceCategoriesEnum.NETWORK_L3.getValue()); + correctUpdate(); + } + + @Test + public void categoryValidationTest8() throws Exception { + updatedServiceDetails.setCategories(null); + updatedServiceDetails.addCategoryChain("Network L1-3", null); + correctUpdate(); + } + + @Test + public void tagsValidationTest1() throws Exception { + updatedServiceDetails + .setTags(new ArrayList<>(Arrays.asList(multipleString("a", 49), updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest2() throws Exception { + updatedServiceDetails + .setTags(new ArrayList<>(Arrays.asList(multipleString("B", 50), updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest3() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>( + Arrays.asList(multipleString("A", 50), multipleString("B", 50), updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest5() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("testTaG", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest6() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("Testtag", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest7() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("Test_tag", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest8() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("Test tag", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest9() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("Test-tag", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest10() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("Test.tag", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest11() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("...1...", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest12() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("-a_1. Arrrrrr", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest13() throws Exception { + updatedServiceDetails + .setTags(new ArrayList<>(Arrays.asList("Testtag1234567890", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest14() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("1", "2", "2", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest15() throws Exception { + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKIN); + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("TestTaG", updatedServiceDetails.getName()))); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + } + + @Test + public void tagsValidationTest16() throws Exception { + // addMandatoryArtifactsToService(); + LifecycleRestUtils.certifyService(serviceDetails); + updatedServiceDetails = new ServiceReqDetails(serviceDetails); + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("testtagtag", updatedServiceDetails.getName()))); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + checkErrorResponse(ActionStatus.RESTRICTED_OPERATION, listForMessage, updateServiceResponse); + } + + @Test + public void tagsValidationTest17() throws Exception { + // addMandatoryArtifactsToService(); + certifyService(serviceDetails, serviceDetails.getVersion()); + LifecycleRestUtils.changeServiceState(serviceDetails, sdncDesignerDetails, serviceDetails.getVersion(), + LifeCycleStatesEnum.CHECKOUT); + updatedServiceDetails = new ServiceReqDetails(serviceDetails); + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList("TestTaG", updatedServiceDetails.getName()))); + correctUpdate(); + } + + @Test + public void tagsValidationTest18() throws Exception { + int lengthOfServiceName = updatedServiceDetails.getName().length(); + int maxLengthTag = 50; + int tagsCount = 1024 - lengthOfServiceName; + ArrayList tagsList = new ArrayList<>(); + tagsList.add(updatedServiceDetails.getName()); + while (tagsCount > maxLengthTag) { + tagsList.add(multipleString("a", maxLengthTag)); + tagsCount -= maxLengthTag + 1 + + 1/* (50 and comma of each tag + one space, totally 52) */; + } + tagsList.add(multipleString("a", tagsCount)); + updatedServiceDetails.setTags(tagsList); + correctUpdate(); + } + + @Test + public void tagsValidationTest19() throws Exception { + updatedServiceDetails.setTags(new ArrayList<>(Arrays.asList(" Tag ", updatedServiceDetails.getName()))); + RestResponse updateServiceResponse1 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse1); + assertNotNull(updateServiceResponse1.getErrorCode()); + assertEquals(200, updateServiceResponse1.getErrorCode().intValue()); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse1); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void tagsValidationTest20() throws Exception { + ArrayList tagsList = new ArrayList<>(); + tagsList.add(updatedServiceDetails.getName()); + tagsList.add(""); + updatedServiceDetails.setTags(tagsList); + updateWithInvalidValue(ActionStatus.INVALID_FIELD_FORMAT, Arrays.asList("Service", "tag")); + } + + // ------------------------------------------invalid + // values------------------------------------------ + + @Test + public void tagsValidationTest21() throws Exception { + ArrayList tagsList = new ArrayList<>(); + tagsList.add("onetag"); + updatedServiceDetails.setTags(tagsList); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_TAGS_NO_COMP_NAME, listForMessage); + + } + + @Test + public void tagsValidationTest22() throws Exception { + specialCharsChecking("tags"); + } + + @Test + public void descriptionValidationTest1() throws Exception { + updatedServiceDetails.setDescription(multipleString("a", 1023)); + correctUpdate(); + } + + @Test + public void descriptionValidationTest2() throws Exception { + updatedServiceDetails.setDescription(multipleString("a", 1024)); + correctUpdate(); + } + + @Test + public void descriptionValidationTest3() throws Exception { + updatedServiceDetails.setDescription(multipleString("aB", 1024 / 2)); + correctUpdate(); + } + + @Test + public void descriptionValidationTest4() throws Exception { + updatedServiceDetails.setDescription("1234567890"); + correctUpdate(); + } + + @Test + public void descriptionValidationTest5() throws Exception { + updatedServiceDetails.setDescription("desc ription"); + correctUpdate(); + } + + @Test + public void descriptionValidationTest6() throws Exception { + updatedServiceDetails.setDescription("desc\tription"); + RestResponse updateServiceResponse1 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse1); + assertNotNull(updateServiceResponse1.getErrorCode()); + assertEquals(200, updateServiceResponse1.getErrorCode().intValue()); + updatedServiceDetails.setDescription("desc ription"); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse1); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void descriptionValidationTest7() throws Exception { + updatedServiceDetails.setDescription("desc ription "); + RestResponse updateServiceResponse2 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse2); + assertNotNull(updateServiceResponse2.getErrorCode()); + assertEquals(200, updateServiceResponse2.getErrorCode().intValue()); + updatedServiceDetails.setDescription("desc ription"); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse2); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void descriptionValidationTest8() throws Exception { + updatedServiceDetails.setDescription("desc" + StringUtils.LF + "ription"); + RestResponse updateServiceResponse3 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse3); + assertNotNull(updateServiceResponse3.getErrorCode()); + assertEquals(200, updateServiceResponse3.getErrorCode().intValue()); + updatedServiceDetails.setDescription("desc ription"); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse3); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void descriptionValidationTest9() throws Exception { + updatedServiceDetails.setDescription("Hello, world!"); + RestResponse updateServiceResponse4 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse4); + assertNotNull(updateServiceResponse4.getErrorCode()); + assertEquals(200, updateServiceResponse4.getErrorCode().intValue()); + updatedServiceDetails.setDescription("Hello, world!"); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse4); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void descriptionValidationTest10() throws Exception { + updatedServiceDetails.setDescription("\uC2B5"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_DESCRIPTION, new ArrayList<>(Arrays.asList("Service"))); + + } + + @Test + public void descriptionValidationTest10_a() throws Exception { + updatedServiceDetails.setDescription("文"); + updateWithInvalidValue(ActionStatus.COMPONENT_INVALID_DESCRIPTION, new ArrayList<>(Arrays.asList("Service"))); + + } + + @Test + public void descriptionValidationTest10_b() throws Exception { + updatedServiceDetails.setDescription("\uC2B5abc"); + RestResponse updateServiceResponse5 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse5); + assertNotNull(updateServiceResponse5.getErrorCode()); + assertEquals(200, updateServiceResponse5.getErrorCode().intValue()); + updatedServiceDetails.setDescription("abc"); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse5); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + + } + + @Test + public void descriptionValidationTest11() throws Exception { + updatedServiceDetails.setDescription("&<>"); + RestResponse updateServiceResponse6 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse6); + assertNotNull(updateServiceResponse6.getErrorCode()); + assertEquals(200, updateServiceResponse6.getErrorCode().intValue()); + updatedServiceDetails.setDescription("&<>"); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse6); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void descriptionValidationTest12() throws Exception { + updatedServiceDetails.setDescription("文 test"); + RestResponse updateServiceResponse7 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse7); + assertNotNull(updateServiceResponse7.getErrorCode()); + assertEquals(200, updateServiceResponse7.getErrorCode().intValue()); + updatedServiceDetails.setDescription("test"); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse7); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void descriptionValidationTest13() throws Exception { + updatedServiceDetails.setDescription(" description"); + RestResponse updateServiceResponse8 = ServiceRestUtils.updateService(updatedServiceDetails, + sdncDesignerDetails); + assertNotNull(updateServiceResponse8); + assertNotNull(updateServiceResponse8.getErrorCode()); + assertEquals(200, updateServiceResponse8.getErrorCode().intValue()); + updatedServiceDetails.setDescription("description"); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse8); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + @Test + public void descriptionValidationTest14() throws Exception { + updatedServiceDetails.setDescription(multipleString("a", 1025)); + updateWithInvalidValue(ActionStatus.COMPONENT_DESCRIPTION_EXCEEDS_LIMIT, + new ArrayList<>(Arrays.asList("Service", "1024"))); + } + + @Test + public void projectCodeValidationTest1() throws Exception { + String desc = StringUtils.EMPTY; + for (int i = 0; i < 10; i++) { + desc += Integer.toString(i); + if (i >= 4) { + updatedServiceDetails.setProjectCode(desc); + correctUpdate(); + } + } + } + + @Test + public void projectCodeValidationTest2() throws Exception { + updatedServiceDetails.setProjectCode(multipleString("1", 6)); + correctUpdate(); + } + + @Test + public void projectCodeValidationTest3() throws Exception { + this.specialCharsChecking("projectCode"); + } + + // TODO Irrelevant + @Test(enabled = false) + public void projectCodeValidationTest4() throws Exception { + updatedServiceDetails.setProjectCode(multipleString(" ", 5) + "99999"); + RestResponse updateServiceResponse = ServiceRestUtils.updateService(updatedServiceDetails, sdncDesignerDetails); + assertNotNull(updateServiceResponse); + assertNotNull(updateServiceResponse.getErrorCode()); + assertEquals(200, updateServiceResponse.getErrorCode().intValue()); + updatedServiceDetails.setProjectCode("12345"); + validateActualVsExpected(updatedServiceDetails, updateServiceResponse); + getServiceAndValidate(updatedServiceDetails, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + + } + + @Test + public void projectCodeValidationTest5() throws Exception { + updatedServiceDetails.setProjectCode(multipleString("0", 11)); + updateWithInvalidValue(ActionStatus.INVALID_PROJECT_CODE, listForMessage); + } + + @Test + public void projectCodeValidationTest6() throws Exception { + updatedServiceDetails.setProjectCode(multipleString("1", 4)); + updateWithInvalidValue(ActionStatus.INVALID_PROJECT_CODE, listForMessage); + } + + @Test + public void projectCodeValidationTest7() throws Exception { + updatedServiceDetails.setProjectCode("123456789"); + correctUpdate(); + } + + // ////US553874 + // @JsonIgnore + // @Test + // public void UpdateServiceVersion01_isVNF_toTrue() throws Exception{ + // + // //choose the user to create service + // User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // // new service details + // // ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + // // clean audit DB before updating service + // DbUtils.cleanAllAudits(); + // ServiceRestUtils.deleteServiceById(serviceDetails.getUniqueId(), + // sdncUserDetails.getUserId()); + // serviceDetails = ElementFactory.getDefaultService(); + // + // //send create service toward BE + // RestResponse restResponse = + // ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 201, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // RestResponse serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // Service serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // //validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceRestUtils.constructFieldsForAuditValidation(serviceDetails, "0.1", + // sdncUserDetails); + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus("201"); + // expectedResourceAuditJavaObject.setDesc("OK"); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + // + // + // //Update Service IsVNF to True + // restResponse = + // ServiceRestUtils.updateService(serviceDetails.getUniqueId(), + // serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 200, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // } + // + // @JsonIgnore + // @Test + // public void UpdateServiceVersion02_isVNF_toFalse() throws Exception{ + // + // //choose the user to create service + // User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // // new service details + // // ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + // // clean audit DB before updating service + // DbUtils.cleanAllAudits(); + // ServiceRestUtils.deleteServiceById(serviceDetails.getUniqueId(), + // sdncUserDetails.getUserId()); + // serviceDetails = ElementFactory.getDefaultService(); + // + // //send create service toward BE + // RestResponse restResponse = + // ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 201, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // RestResponse serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // Service serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // //validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceRestUtils.constructFieldsForAuditValidation(serviceDetails, "0.1", + // sdncUserDetails); + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus("201"); + // expectedResourceAuditJavaObject.setDesc("OK"); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + // + // + // //Update Service IsVNF to True + // restResponse = + // ServiceRestUtils.updateService(serviceDetails.getUniqueId(), + // serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 200, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // } + // + // @JsonIgnore + // @Test + // public void UpdateServiceVersion01_isVNF_TrueToNull() throws Exception{ + // + // //choose the user to create service + // User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // // new service details + // // ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + // // clean audit DB before updating service + // DbUtils.cleanAllAudits(); + // ServiceRestUtils.deleteServiceById(serviceDetails.getUniqueId(), + // sdncUserDetails.getUserId()); + // serviceDetails = ElementFactory.getDefaultService(); + // + // //send create service toward BE + // RestResponse restResponse = + // ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 201, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // RestResponse serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // Service serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // //validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceRestUtils.constructFieldsForAuditValidation(serviceDetails, "0.1", + // sdncUserDetails); + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus("201"); + // expectedResourceAuditJavaObject.setDesc("OK"); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + // + // + // //Update Service IsVNF to True + // restResponse = + // ServiceRestUtils.updateService(serviceDetails.getUniqueId(), + // serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 400, restResponse.getErrorCode().intValue()); + // List variables = Arrays.asList("VNF Service Indicator"); + // ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_DATA.name(), + // variables, restResponse.getResponse()); + // + // //get service and verify that service created with isVNF is remained with + // isVNF = true + // serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // } + // + // @JsonIgnore + // @Test + // public void UpdateServiceVersion01_isVNF_FalseToNull() throws Exception{ + // + // //choose the user to create service + // User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // // new service details + // // ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + // // clean audit DB before updating service + // DbUtils.cleanAllAudits(); + // ServiceRestUtils.deleteServiceById(serviceDetails.getUniqueId(), + // sdncUserDetails.getUserId()); + // serviceDetails = ElementFactory.getDefaultService(); + // + // //send create service toward BE + // RestResponse restResponse = + // ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 201, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // RestResponse serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // Service serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // //validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceRestUtils.constructFieldsForAuditValidation(serviceDetails, "0.1", + // sdncUserDetails); + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus("201"); + // expectedResourceAuditJavaObject.setDesc("OK"); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + // + // + // //Update Service IsVNF to True + // restResponse = + // ServiceRestUtils.updateService(serviceDetails.getUniqueId(), + // serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 400, restResponse.getErrorCode().intValue()); + // List variables = Arrays.asList("VNF Service Indicator"); + // ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.MISSING_DATA.name(), + // variables, restResponse.getResponse()); + // + // //get service and verify that service created with isVNF is remained with + // isVNF = true + // serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // } + // + // @JsonIgnore + // @Test + // public void UpdateServiceVersion02_IsVNF_toTrue() throws Exception{ + // + // //choose the user to create service + // User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // // new service details + // // ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + // // clean audit DB before updating service + // DbUtils.cleanAllAudits(); + // ServiceRestUtils.deleteServiceById(serviceDetails.getUniqueId(), + // sdncUserDetails.getUserId()); + // serviceDetails = ElementFactory.getDefaultService(); + // + // //send create service toward BE + // RestResponse restResponse = + // ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 201, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // RestResponse serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // Service serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // LifecycleRestUtils.changeServiceState(serviceDetails, + // sdncDesignerDetails, serviceDetails.getVersion(), + // LifeCycleStatesEnum.CHECKIN); + // LifecycleRestUtils.changeServiceState(serviceDetails, + // sdncDesignerDetails, serviceDetails.getVersion(), + // LifeCycleStatesEnum.CHECKOUT); + // + // //validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceRestUtils.constructFieldsForAuditValidation(serviceDetails, "0.1", + // sdncUserDetails); + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus("201"); + // expectedResourceAuditJavaObject.setDesc("OK"); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + // + // + // //Update Service IsVNF to True + // restResponse = + // ServiceRestUtils.updateService(serviceDetails.getUniqueId(), + // serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 200, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // } + // + // @JsonIgnore + // @Test + // public void UpdateServiceVersion02_IsVNF_toFalse() throws Exception{ + // + // //choose the user to create service + // User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + // // new service details + // // ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + // // clean audit DB before updating service + // DbUtils.cleanAllAudits(); + // ServiceRestUtils.deleteServiceById(serviceDetails.getUniqueId(), + // sdncUserDetails.getUserId()); + // serviceDetails = ElementFactory.getDefaultService(); + // + // //send create service toward BE + // RestResponse restResponse = + // ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 201, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // RestResponse serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // Service serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // LifecycleRestUtils.changeServiceState(serviceDetails, + // sdncDesignerDetails, serviceDetails.getVersion(), + // LifeCycleStatesEnum.CHECKIN); + // LifecycleRestUtils.changeServiceState(serviceDetails, + // sdncDesignerDetails, serviceDetails.getVersion(), + // LifeCycleStatesEnum.CHECKOUT); + // + // //validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceRestUtils.constructFieldsForAuditValidation(serviceDetails, "0.1", + // sdncUserDetails); + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus("201"); + // expectedResourceAuditJavaObject.setDesc("OK"); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + // + // + // //Update Service IsVNF to false + // restResponse = + // ServiceRestUtils.updateService(serviceDetails.getUniqueId(), + // serviceDetails, sdncUserDetails); + // //restResponse = + // ServiceRestUtils.updateService(serviceDetails.getUniqueId(), + // serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 200, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // } + // + // @JsonIgnore + // @Test + // public void UpdateServiceVersion11_IsVNF_toFalse() throws Exception{ + // // Can't update isVNF when service version is 1.X + // User sdncUserDetails = + // ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // // new service details + // // ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + // // clean audit DB before updating service + // DbUtils.cleanAllAudits(); + // ServiceRestUtils.deleteServiceById(serviceDetails.getUniqueId(), + // sdncUserDetails.getUserId()); + // serviceDetails = ElementFactory.getDefaultService(); + // + // //send create service toward BE + // RestResponse restResponse = + // ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 201, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // RestResponse serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // Service serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // //String serviceUniqueName = + // ServiceRestUtils.getServiceUniqueId(serviceByNameAndVersion); + // + // //validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceRestUtils.constructFieldsForAuditValidation(serviceDetails, "0.1", + // sdncUserDetails); + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus("201"); + // expectedResourceAuditJavaObject.setDesc("OK"); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + // + //// ServiceRestUtils.addServiceMandatoryArtifacts(sdncUserDetails, + // restResponse); + // RestResponse response = + // ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, + // sdncUserDetails, serviceDetails.getUniqueId(), + // ComponentTypeEnum.SERVICE); + // assertTrue("response code is not 201, returned: " + + // response.getErrorCode(),response.getErrorCode() == 201); + // RestResponse changeServiceState = + // LCSbaseTest.certifyService(serviceDetails, sdncDesignerDetails); + // assertTrue("certify service request returned status:" + + // changeServiceState.getErrorCode(),changeServiceState.getErrorCode() == + // 200); + // LifecycleRestUtils.changeServiceState(serviceDetails, sdncUserDetails, + // LifeCycleStatesEnum.CHECKOUT); + // + // //Update Service IsVNF to false + // restResponse = ServiceRestUtils.updateService(serviceDetails, + // sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating service metadata", 400, + // restResponse.getErrorCode().intValue()); + // List variables = new ArrayList(); + // ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_IS_VNF_CANNOT_BE_CHANGED.name(), + // variables, restResponse.getResponse()); + // + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "1.1"); + // serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // + // } + // + // @JsonIgnore + // @Test + // public void UpdateServiceVersion11_IsVNF_toTrue() throws Exception{ + // // Can't update isVNF when service version is 1.X + // User sdncUserDetails = + // ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // // new service details + // // ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + // // clean audit DB before updating service + // DbUtils.cleanAllAudits(); + // ServiceRestUtils.deleteServiceById(serviceDetails.getUniqueId(), + // sdncUserDetails.getUserId()); + // serviceDetails = ElementFactory.getDefaultService(); + // + // //send create service toward BE + // RestResponse restResponse = + // ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating Interface Artifact", + // 201, restResponse.getErrorCode().intValue()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // RestResponse serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "0.1"); + // Service serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // //String serviceUniqueName = + // ServiceRestUtils.getServiceUniqueId(serviceByNameAndVersion); + // + // //validate audit + // ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + // ServiceValidationUtils.constructFieldsForAuditValidation(serviceDetails, + // "0.1", sdncUserDetails); + // String auditAction="Create"; + // expectedResourceAuditJavaObject.setPrevState(""); + // expectedResourceAuditJavaObject.setPrevVersion(""); + // expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // expectedResourceAuditJavaObject.setStatus("201"); + // expectedResourceAuditJavaObject.setDesc("OK"); + // AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, + // auditAction, null, false); + // + //// ServiceRestUtils.addServiceMandatoryArtifacts(sdncUserDetails, + // restResponse); + // RestResponse response = + // ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, + // sdncUserDetails, serviceDetails.getUniqueId(), + // ComponentTypeEnum.SERVICE); + // assertTrue("response code is not 201, returned: " + + // response.getErrorCode(),response.getErrorCode() == 201); + // RestResponse changeServiceState = + // LCSbaseTest.certifyService(serviceDetails, sdncDesignerDetails); + // assertTrue("certify service request returned status:" + + // changeServiceState.getErrorCode(),changeServiceState.getErrorCode() == + // 200); + // LifecycleRestUtils.changeServiceState(serviceDetails, sdncUserDetails, + // LifeCycleStatesEnum.CHECKOUT); + // + // //Update Service IsVNF to false + // restResponse = ServiceRestUtils.updateService(serviceDetails, + // sdncUserDetails); + // assertNotNull("check error code exists in response after create service", + // restResponse.getErrorCode()); + // assertEquals("Check response code after updating service metadata", 400, + // restResponse.getErrorCode().intValue()); + // List variables = new ArrayList(); + // ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_IS_VNF_CANNOT_BE_CHANGED.name(), + // variables, restResponse.getResponse()); + // + // //get service and verify that service created with isVNF defined in + // serviceDetails + // serviceByNameAndVersion = + // ServiceRestUtils.getServiceByNameAndVersion(sdncUserDetails, + // serviceDetails.getName(), "1.1"); + // serviceObject = + // ResponseParser.convertServiceResponseToJavaObject(serviceByNameAndVersion.getResponse()); + // ServiceValidationUtils.validateServiceResponseMetaData(serviceDetails, + // serviceObject, sdncUserDetails, + // LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + // } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/ActivateDeActivateDeleteUser.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/ActivateDeActivateDeleteUser.java new file mode 100644 index 0000000000..24afcec40f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/ActivateDeActivateDeleteUser.java @@ -0,0 +1,756 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.user; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.http.HttpStatus; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.utils.UserStatusEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceRespJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedUserCRUDAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.users.UserResponseMessageEnum; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.general.Convertor; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.CatalogRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ImportRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.UserRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ResourceValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.UserValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; + +/** + * @author alitvinsky + * + */ +public class ActivateDeActivateDeleteUser extends ComponentBaseTest { + private static Logger logger = LoggerFactory.getLogger(ActivateDeActivateDeleteUser.class.getName()); + protected Gson gson = new Gson(); + protected User sdncAdminUser; + + @BeforeMethod + public void init() { + sdncAdminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + } + + @Rule + public static TestName name = new TestName(); + + public ActivateDeActivateDeleteUser() { + super(name, ActivateDeActivateDeleteUser.class.getName()); + } + + @Test + public void authorizeDeActivatedUser() throws Exception { + + User sdncUserDetails = getDefaultUserDetails(); + + try { + + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + DbUtils.cleanAllAudits(); + + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + validateSuccessCreateUserResponse(sdncUserDetails, createUserResponse); + + // deActivate created user + RestResponse deActivateUserResponse = UserRestUtils.deActivateUser(sdncUserDetails, sdncAdminUser); + sdncUserDetails.setStatus(UserStatusEnum.INACTIVE); + validateSuccessDeActivateUserResponse(sdncUserDetails, deActivateUserResponse); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_INACTIVE.name()); + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + + AssertJUnit.assertEquals("Check response code after deActive user", errorInfo.getCode(), + getUserResponse.getErrorCode()); + + List variables = Arrays.asList(sdncUserDetails.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.USER_INACTIVE.name(), variables, + getUserResponse.getResponse()); + + // clean audit before authorization test + DbUtils.cleanAllAudits(); + + // Perform login from WebSeal + User sealUserDetails = sdncUserDetails; + RestResponse authorizedUserResponse = UserRestUtils.authorizedUserTowardsCatalogBeQA(sealUserDetails); + + // validate response + + ErrorInfo errorInfo2 = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_ACCESS.name()); + + AssertJUnit.assertNotNull("check response object is not null after user login", authorizedUserResponse); + AssertJUnit.assertNotNull("check error code exists in response after user login", + authorizedUserResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after deActive user", errorInfo2.getCode(), + authorizedUserResponse.getErrorCode()); + + List variables2 = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.RESTRICTED_ACCESS.name(), variables2, + authorizedUserResponse.getResponse()); + + // validate against ES DB + + UserValidationUtils.validateDataAgainstAuditDB_access(sealUserDetails, + DbUtils.parseAuditRespByAction("Access"), authorizedUserResponse, errorInfo2, variables2); + + } finally { + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + } + + } + + public User getDefaultUserDetails() { + + String httpCspUserId = "km2000"; + String userFirstName = "Kot"; + String userLastName = "May"; + String email = "km2000@intl.sdc.com"; + String role = UserRoleEnum.ADMIN.name(); + User sdncUserDetails = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + + return sdncUserDetails; + } + + public void validateSuccessCreateUserResponse(User sdncUserDetails, RestResponse createUserResponse) + throws Exception { + + AssertJUnit.assertNotNull("check response object is not null after create user", createUserResponse); + AssertJUnit.assertNotNull("check error code exists in response after create user", + createUserResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create user", HttpStatus.SC_CREATED, + createUserResponse.getErrorCode().intValue()); + + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, createUserResponse.getResponse()); + // UserRestUtils.validateAddUserAuditMessage(sdncUserDetails, + // sdncAdminUser, String.valueOf(HttpStatus.SC_CREATED), + // UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + // UserRestUtils.getAddUserAuditMessage("AddUser")); + String addUser = "AddUser"; + ExpectedUserCRUDAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation(addUser, + sdncAdminUser, ActionStatus.CREATED, sdncUserDetails, null); + AuditValidationUtils.validateAddUserAudit(constructFieldsForAuditValidation, addUser); + + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, getUserResponse.getResponse()); + + } + + public void validateSuccessDeActivateUserResponse(User sdncUserDetails, RestResponse deActivateUserResponse) + throws Exception { + + AssertJUnit.assertNotNull("check response object is not null after deActive user", deActivateUserResponse); + AssertJUnit.assertNotNull("check error code exists in response after deActive user", + deActivateUserResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after deActive user", 200, + deActivateUserResponse.getErrorCode().intValue()); + + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, deActivateUserResponse.getResponse()); + + String deleteUser = "DeleteUser"; + ExpectedUserCRUDAudit constructFieldsForAuditValidation = Convertor + .constructFieldsForAuditValidation(deleteUser, sdncAdminUser, ActionStatus.OK, null, sdncUserDetails); + AuditValidationUtils.validateAddUserAudit(constructFieldsForAuditValidation, deleteUser); + + } + + // US498322 - Add Status Field to USER + + @Test + public void createNewUser() throws Exception { + + User sdncUserDetails = getDefaultUserDetails(); + try { + + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + DbUtils.cleanAllAudits(); + + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + validateSuccessCreateUserResponse(sdncUserDetails, createUserResponse); + + } finally { + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + } + + } + + @Test + public void createDefaultUser() throws Exception { + + User sdncUserDetails = getDefaultUserDetails(); + sdncUserDetails.setFirstName(null); + sdncUserDetails.setLastName(null); + sdncUserDetails.setEmail(null); + sdncUserDetails.setRole(null); + + try { + + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + DbUtils.cleanAllAudits(); + + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + validateSuccessCreateUserResponse(sdncUserDetails, createUserResponse); + + } finally { + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + } + + } + + @Test + public void createTesterUser() throws Exception { + + User sdncUserDetails = getDefaultUserDetails(); + sdncUserDetails.setLastName(null); + sdncUserDetails.setRole(UserRoleEnum.TESTER.name()); + + try { + + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + DbUtils.cleanAllAudits(); + + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + validateSuccessCreateUserResponse(sdncUserDetails, createUserResponse); + + } finally { + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + } + + } + + @Test + public void deActivateCreatedAdminUser() throws Exception { + + User sdncUserDetails = getDefaultUserDetails(); + + try { + + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + DbUtils.cleanAllAudits(); + + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + validateSuccessCreateUserResponse(sdncUserDetails, createUserResponse); + + // deActivate created user + RestResponse deActivateUserResponse = UserRestUtils.deActivateUser(sdncUserDetails, sdncAdminUser); + sdncUserDetails.setStatus(UserStatusEnum.INACTIVE); + validateSuccessDeActivateUserResponse(sdncUserDetails, deActivateUserResponse); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_INACTIVE.name()); + + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + + assertEquals("Check response code after get user", errorInfo.getCode(), getUserResponse.getErrorCode()); + + List variables = Arrays.asList(sdncUserDetails.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.USER_INACTIVE.name(), variables, + getUserResponse.getResponse()); + + } finally { + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + } + + } + + @Test + public void deActivateTheSameUserTwice() throws Exception { + + User sdncUserDetails = getDefaultUserDetails(); + + try { + + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + DbUtils.cleanAllAudits(); + + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + validateSuccessCreateUserResponse(sdncUserDetails, createUserResponse); + + // deActivate created user + RestResponse deActivateUserResponse = UserRestUtils.deActivateUser(sdncUserDetails, sdncAdminUser); + sdncUserDetails.setStatus(UserStatusEnum.INACTIVE); + validateSuccessDeActivateUserResponse(sdncUserDetails, deActivateUserResponse); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_INACTIVE.name()); + + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + + assertEquals("Check response code after deActive user", errorInfo.getCode(), + getUserResponse.getErrorCode()); + + List variables = Arrays.asList(sdncUserDetails.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.USER_INACTIVE.name(), variables, + getUserResponse.getResponse()); + + // deActivate the same user once time more + RestResponse deActivateUserResponse2 = UserRestUtils.deActivateUser(sdncUserDetails, sdncAdminUser); + ErrorInfo errorInfo2 = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_INACTIVE.name()); + assertEquals("Check response code after deActive user", errorInfo2.getCode(), + deActivateUserResponse2.getErrorCode()); + + List variables2 = Arrays.asList(sdncUserDetails.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.USER_INACTIVE.name(), variables2, + deActivateUserResponse2.getResponse()); + + } finally { + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + } + + } + + @Test + public void createAgainDeActivatedUser() throws Exception { + + User sdncUserDetails = getDefaultUserDetails(); + + try { + + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + DbUtils.cleanAllAudits(); + + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + validateSuccessCreateUserResponse(sdncUserDetails, createUserResponse); + + // deActivate created user + RestResponse deActivateUserResponse = UserRestUtils.deActivateUser(sdncUserDetails, sdncAdminUser); + sdncUserDetails.setStatus(UserStatusEnum.INACTIVE); + validateSuccessDeActivateUserResponse(sdncUserDetails, deActivateUserResponse); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_INACTIVE.name()); + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + + assertEquals("Check response code after deActive user", errorInfo.getCode(), + getUserResponse.getErrorCode()); + + List variables = Arrays.asList(sdncUserDetails.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.USER_INACTIVE.name(), variables, + getUserResponse.getResponse()); + + // create the user with the same UserId(details) as deActivated user + DbUtils.cleanAllAudits(); + + RestResponse createUserResponse2 = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + ErrorInfo errorInfo2 = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_INACTIVE.name()); + assertEquals("Check response code after deActive user", errorInfo2.getCode(), + createUserResponse2.getErrorCode()); + + List variables2 = Arrays.asList(sdncUserDetails.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.USER_INACTIVE.name(), variables2, + createUserResponse2.getResponse()); + + } finally { + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + } + + } + + // very not recommend to run this test, resources/services may be zombie + // @Test + public void deActivateLastAdminUser() throws Exception { + + try { + + // send get all ADMIN user request toward BE + RestResponse getAllAdminUsers = UserRestUtils.getAllAdminUsers(sdncAdminUser); + + assertNotNull("check response object is not null after create user", getAllAdminUsers); + assertNotNull("check error code exists in response after create user", getAllAdminUsers.getErrorCode()); + assertEquals("Check response code after create user", 200, getAllAdminUsers.getErrorCode().intValue()); + + TypeToken> typeToken = new TypeToken>() { + }; + List listOfUsersOnResponse = gson.fromJson(getAllAdminUsers.getResponse(), typeToken.getType()); + logger.debug("listOfUsers: {}", listOfUsersOnResponse); + + // build map of all Admin users from listOfUsersOnResponse from + // response + Map mapAllUsersOnResponse = new HashMap(); + for (User sdncUser : listOfUsersOnResponse) { + mapAllUsersOnResponse.put(sdncUser.getUserId(), sdncUser); + } + + // remove from mapAllUsersOnResponse map one of admin users + mapAllUsersOnResponse.remove(sdncAdminUser.getUserId()); + logger.debug("map Of all Admin users exclude one : {}", mapAllUsersOnResponse); + + // deActivate all Admin users from the userIdAllAdminList list + for (Entry entry : mapAllUsersOnResponse.entrySet()) { + UserRestUtils.deActivateUser(entry.getValue(), sdncAdminUser); + } + + // deActivate last Admin user user + RestResponse deActivateUserResponse = UserRestUtils.deActivateUser(sdncAdminUser, sdncAdminUser); + + ErrorInfo errorInfo = ErrorValidationUtils + .parseErrorConfigYaml(ActionStatus.DELETE_USER_ADMIN_CONFLICT.name()); + + assertEquals("Check response code after deActive user", errorInfo.getCode(), + deActivateUserResponse.getErrorCode()); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.DELETE_USER_ADMIN_CONFLICT.name(), variables, + deActivateUserResponse.getResponse()); + + } finally { + // UserRestUtils.deleteUser(UserRestUtils.getAdminDetails2(), + // sdncAdminUser); + // UserRestUtils.deleteUser(UserRestUtils.getAdminDetails3(), + // sdncAdminUser); + // UserRestUtils.createUser(UserRestUtils.getAdminDetails2(), + // sdncAdminUser); + // UserRestUtils.createUser(UserRestUtils.getAdminDetails3(), + // sdncAdminUser); + } + + } + + // test check the resource accessibility via catalog view, resource was + // created by user which was deActivated + + @Test + public void resourceAccessibility() throws Exception { + + User sdncUserDetails = getDefaultUserDetails(); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource("tosca.nodes.newresource4test4", + NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, "jh0003"); + String resourceBaseVersion = "0.1"; + + try { + // Delete resource + // resourceUtils.deleteResource_allVersions(resourceDetails, + // sdncAdminUser); + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + + DbUtils.cleanAllAudits(); + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + validateSuccessCreateUserResponse(sdncUserDetails, createUserResponse); + + // ------------------------Start create + // resource--------------------------------------------------------------------------------- + + // create resource + RestResponse createResponse = ResourceRestUtils.createResource(resourceDetails, sdncUserDetails); + assertEquals("Check response code after create", 201, createResponse.getErrorCode().intValue()); + + Resource createdResource = ResponseParser.convertResourceResponseToJavaObject(createResponse.getResponse()); + + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncUserDetails, + createdResource.getUniqueId()); + assertEquals("Check response code after get", 200, resourceGetResponse.getErrorCode().intValue()); + + // validate get response + ResourceRespJavaObject resourceRespJavaObject = Convertor.constructFieldsForRespValidation(resourceDetails, + resourceBaseVersion); + resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setAbstractt("false"); + resourceRespJavaObject.setCreatorUserId(sdncUserDetails.getUserId()); + resourceRespJavaObject.setLastUpdaterUserId(sdncUserDetails.getUserId()); + + resourceRespJavaObject + .setCreatorFullName(sdncUserDetails.getFirstName() + " " + sdncUserDetails.getLastName()); + resourceRespJavaObject + .setLastUpdaterFullName(sdncUserDetails.getFirstName() + " " + sdncUserDetails.getLastName()); + + ResourceValidationUtils.validateResp(resourceGetResponse, resourceRespJavaObject); + + // ------------------------End create + // resource--------------------------------------------------------------------------------- + + // clean audit before authorization test + DbUtils.cleanAllAudits(); + + // deActivate created user + RestResponse deActivateUserResponse = UserRestUtils.deActivateUser(sdncUserDetails, sdncAdminUser); + sdncUserDetails.setStatus(UserStatusEnum.INACTIVE); + validateSuccessDeActivateUserResponse(sdncUserDetails, deActivateUserResponse); + + UserValidationUtils.validateDeleteUserAuditMessage(sdncUserDetails, sdncAdminUser, "200", + UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("DeleteUser")); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_INACTIVE.name()); + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + + assertEquals("Check response code after deActive user", errorInfo.getCode(), + getUserResponse.getErrorCode()); + + List variables = Arrays.asList(sdncUserDetails.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.USER_INACTIVE.name(), variables, + getUserResponse.getResponse()); + + // checking if created resource is accessible + DbUtils.cleanAllAudits(); + + RestResponse getCatalogDataResponse = CatalogRestUtils.getCatalog(sdncAdminUser.getUserId()); + + // validate response + + assertNotNull("check response object is not null after user login", getCatalogDataResponse); + assertNotNull("check error code exists in response after user login", + getCatalogDataResponse.getErrorCode()); + assertEquals("Check response code after deActive user", 200, + getCatalogDataResponse.getErrorCode().intValue()); + + // expected resource list + List resourceExpectedUniqIdList = new ArrayList(); + resourceExpectedUniqIdList.add(resourceDetails.getUniqueId()); + logger.debug("resourceExpectedUniqIdList: {}", resourceExpectedUniqIdList); + + compareResourceUniqIdList(getCatalogDataResponse.getResponse(), resourceExpectedUniqIdList, true); + + } finally { + // resourceUtils.deleteResource_allVersions(resourceDetails, + // sdncAdminUser); + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + } + + } + + // test check the resource accessibility via catalog view, resource was + // created by user which was deActivated + + @Test + public void resourceAccessibilityOnImport() throws Exception { + + User sdncUserDetails = getDefaultUserDetails(); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource("importResource4test", + NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, "jh0003"); + resourceDetails.addCategoryChain(ResourceCategoryEnum.GENERIC_DATABASE.getCategory(), + ResourceCategoryEnum.GENERIC_DATABASE.getSubCategory()); + // String resourceBaseVersion = "1.0"; + + try { + // Delete resource + // resourceUtils.deleteResource_allVersions(resourceDetails, + // sdncAdminUser); + RestResponse deleteUserResponse = UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + assertTrue("delete user request failed", + deleteUserResponse.getErrorCode() == 200 || deleteUserResponse.getErrorCode() == 404); + DbUtils.cleanAllAudits(); + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + validateSuccessCreateUserResponse(sdncUserDetails, createUserResponse); + + // ------------------------Start import + // resource--------------------------------------------------------------------------------- + + // import new resource with CERTIFIED state + User importer = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN4); + RestResponse importResponse = ImportRestUtils.importResourceByName(resourceDetails, importer); + + assertNotNull("check response object is not null after create user", importResponse); + assertNotNull("check error code exists in response after create user", importResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, importResponse.getErrorCode().intValue()); + + // ------------------------End import + // resource--------------------------------------------------------------------------------- + + // clean audit before authorization test + DbUtils.cleanAllAudits(); + + // deActivate created user + RestResponse deActivateUserResponse = UserRestUtils.deActivateUser(sdncUserDetails, sdncAdminUser); + sdncUserDetails.setStatus(UserStatusEnum.INACTIVE); + validateSuccessDeActivateUserResponse(sdncUserDetails, deActivateUserResponse); + + UserValidationUtils.validateDeleteUserAuditMessage(sdncUserDetails, sdncAdminUser, "200", + UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("DeleteUser")); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_INACTIVE.name()); + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + + assertEquals("Check response code after deActive user", errorInfo.getCode(), + getUserResponse.getErrorCode()); + + List variables = Arrays.asList(sdncUserDetails.getUserId()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.USER_INACTIVE.name(), variables, + getUserResponse.getResponse()); + + // checking if created resource is accessible + DbUtils.cleanAllAudits(); + + RestResponse getCatalogDataResponse = CatalogRestUtils.getCatalog(sdncAdminUser.getUserId()); + + // validate response + + assertNotNull("check response object is not null after user login", getCatalogDataResponse); + assertNotNull("check error code exists in response after user login", + getCatalogDataResponse.getErrorCode()); + assertEquals("Check response code after deActive user", 200, + getCatalogDataResponse.getErrorCode().intValue()); + + // expected resource list + List resourceExpectedUniqIdList = new ArrayList(); + resourceExpectedUniqIdList.add(resourceDetails.getUniqueId()); + logger.debug("resourceExpectedUniqIdList: {}", resourceExpectedUniqIdList); + + compareResourceUniqIdList(getCatalogDataResponse.getResponse(), resourceExpectedUniqIdList, true); + + } finally { + // resourceUtils.deleteResource_allVersions(resourceDetails, + // sdncAdminUser); + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + } + + } + + public void compareServiceUniqIdList(String response, List expectedList, boolean flag) { + + JsonElement jelement = new JsonParser().parse(response); + JsonObject jobject = jelement.getAsJsonObject(); + JsonArray serviceArray = (JsonArray) jobject.get("services"); + logger.debug("{}", serviceArray); + assertTrue("expected service count: " + expectedList.size() + " or more" + ", actual: " + serviceArray.size(), + serviceArray.size() >= expectedList.size()); + + // build service list from response + List serviceReqDetailsListOnResponse = new ArrayList(); + for (int i = 0; i < serviceArray.size(); i++) { + ServiceReqDetails json = gson.fromJson(serviceArray.get(i), ServiceReqDetails.class); + serviceReqDetailsListOnResponse.add(json); + } + } + + public void compareResourceUniqIdList(String response, List expectedList, boolean flag) { + + JsonElement jelement = new JsonParser().parse(response); + JsonObject jobject = jelement.getAsJsonObject(); + JsonArray resourceArray = (JsonArray) jobject.get("resources"); + logger.debug("{}", resourceArray); + assertTrue("expected resource count: " + expectedList.size() + " or more" + ", actual: " + resourceArray.size(), + resourceArray.size() >= expectedList.size()); + + // build resource list from response + List resourceReqDetailsListOnResponse = new ArrayList(); + for (int i = 0; i < resourceArray.size(); i++) { + ResourceReqDetails json = gson.fromJson(resourceArray.get(i), ResourceReqDetails.class); + resourceReqDetailsListOnResponse.add(json); + } + + logger.debug("ResourceReqDetails list on response: {}", resourceReqDetailsListOnResponse); + + List resourceActualUniqIdList = new ArrayList(); + for (ResourceReqDetails resource : resourceReqDetailsListOnResponse) { + resourceActualUniqIdList.add(resource.getUniqueId()); + } + logger.debug("resourceActualUniqIdList on response: {}", resourceActualUniqIdList); + logger.debug("resourceExpectedUniqIdList on response: {}", expectedList); + + if (flag) { + assertTrue("actual list does not contain expected list", + resourceActualUniqIdList.containsAll(expectedList)); + } else { + assertFalse("actual list contains non expected list elements", + resourceActualUniqIdList.containsAll(expectedList)); + } + } + + // public User getDefaultUserDetails(){ + // + // String userFirstName = "Kot"; + // String userLastName = "May"; + // String role = UserRoleEnum.ADMIN.name(); + // User sdncUserDetails = new User(userFirstName, userLastName, + // httpCspUserId, email, role,null); + // + // return sdncUserDetails; + // } + // + // public void validateSuccessCreateUserResponse(User sdncUserDetails, + // RestResponse createUserResponse) throws Exception{ + // + // assertNotNull("check response object is not null after create user", + // createUserResponse); + // assertNotNull("check error code exists in response after create user", + // createUserResponse.getErrorCode()); + // assertEquals("Check response code after create user", + // HttpStatus.SC_CREATED, createUserResponse.getErrorCode().intValue()); + // + // UserRestUtils.validateUserDetailsOnResponse(sdncUserDetails, + // createUserResponse.getResponse()); + // UserRestUtils.validateAddUserAuditMessage(sdncUserDetails, sdncAdminUser, + // String.valueOf(HttpStatus.SC_CREATED), + // UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + // UserRestUtils.getAddUserAuditMessage("AddUser")); + // RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, + // sdncAdminUser); + // UserRestUtils.validateUserDetailsOnResponse(sdncUserDetails, + // getUserResponse.getResponse()); + // + // } + // + // public void validateSuccessDeActivateUserResponse(User sdncUserDetails, + // RestResponse deActivateUserResponse) throws Exception{ + // + // assertNotNull("check response object is not null after deActive user", + // deActivateUserResponse); + // assertNotNull("check error code exists in response after deActive user", + // deActivateUserResponse.getErrorCode()); + // assertEquals("Check response code after deActive user", 200, + // deActivateUserResponse.getErrorCode().intValue()); + // + // UserRestUtils.validateUserDetailsOnResponse(sdncUserDetails, + // deActivateUserResponse.getResponse()); + // UserRestUtils.validateDeleteUserAuditMessage(sdncUserDetails, + // sdncAdminUser, "200", UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + // UserRestUtils.getAddUserAuditMessage("DeleteUser")); + // + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/CreateUserApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/CreateUserApiTest.java new file mode 100644 index 0000000000..2f979f3d15 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/CreateUserApiTest.java @@ -0,0 +1,1693 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.user; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; + +import java.io.IOException; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedUserCRUDAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.users.UserResponseMessageEnum; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.general.Convertor; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.UserRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.UserValidationUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class CreateUserApiTest extends ComponentBaseTest { + + protected User sdncAdminUser; + protected User sdncDesignerUser; + protected User sdncGovernorUser; + protected User sdncTesterUser; + + public static final int STATUS_CODE_SUCCESS = 200; + public static final int STATUS_CODE_SUCSESS_CREATED = 201; + public static final int STATUS_CODE_SUCCESS_DELETE_GET = 200; + public static final int STATUS_CODE_INVALID_CONTENT = 400; + public static final int STATUS_CODE_MISSING_DATA = 400; + public static final int STATUS_CODE_MISSING_INFORMATION = 403; + public static final int STATUS_CODE_RESTRICTED_ACCESS = 403; + public static final int STATUS_CODE_NOT_FOUND = 404; + public static final int STATUS_CODE_RESTRICTED_OPERATION = 409; + public static final int USER_ALREADY_EXIST = 409; + public static final int INVALID_ROLE = 400; + + @Rule + public static TestName name = new TestName(); + + public CreateUserApiTest() { + super(name, CreateUserApiTest.class.getName()); + } + + @BeforeMethod + public void init() { + sdncAdminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + sdncDesignerUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncGovernorUser = ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR); + sdncTesterUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + + } + + // Story : REST API to provision new user (POST) - US429379 + // must parameters: UserId and Email + + // **********************************************************201*************************************************** + // create user with full parameter set(UserID, First Name, Last Name, Email, + // Role = "DESIGNER", Creator details) + // expected 201 Created + @Test + public void createUser() throws Exception { + + // user initialization + String httpCspUserId = "km2000"; + String userFirstName = "Kot"; + String userLastName = "Matroskin"; + String email = "km2000@intl.sdc.com"; + String role = "ADMIN"; + User sdncUserDetails = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + String addUser = "AddUser"; + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + DbUtils.cleanAllAudits(); + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + + AssertJUnit.assertNotNull("check response object is not null after create user", createUserResponse); + AssertJUnit.assertNotNull("check error code exists in response after create user", + createUserResponse.getErrorCode()); + AssertJUnit.assertEquals("Check response code after create user", 201, + createUserResponse.getErrorCode().intValue()); + + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, createUserResponse.getResponse()); + + ExpectedUserCRUDAudit constructFieldsForAuditValidation = Convertor.constructFieldsForAuditValidation(addUser, + sdncAdminUser, ActionStatus.CREATED, sdncUserDetails, null); + AuditValidationUtils.validateAddUserAudit(constructFieldsForAuditValidation, addUser); + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, getUserResponse.getResponse()); + } + + protected static final String ADD_USER = "AddUser"; + + private User mechIdUser = new User(); + private User emptyUser = new User(); + private static final User adminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + @AfterMethod + public void setup() throws IOException { + UserRestUtils.deactivateUser(mechIdUser, adminUser); + } + + // create default user(UserID, Email, Creator details) + // expected: role = DESIGNER, first and last name = null, 201 Created + @Test + public void createDefaultUser() throws Exception { + // user initialization + String httpCspUserId = "km2000"; + String userFirstName = null; + String userLastName = null; + String email = null; + String role = null; + User sdncUserDetails = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + + deleteUserAndAudit(sdncUserDetails); + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, createUserResponse.getResponse()); + UserValidationUtils.validateAddUserAuditMessage(sdncUserDetails, sdncAdminUser, "201", + UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, getUserResponse.getResponse()); + + } + + // create user with one optional parameter first name (UserID, Email, First + // Name, Creator details) + // expected: role = DESIGNER, last name = null, 201 Created + @Test + public void createUserFirstName() throws Exception { + // user initialization + String httpCspUserId = "km2000"; + String userFirstName = "Kot"; + String userLastName = null; + String email = null; + String role = null; + User sdncUserDetails = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + + deleteUserAndAudit(sdncUserDetails); + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, createUserResponse.getResponse()); + UserValidationUtils.validateAddUserAuditMessage(sdncUserDetails, sdncAdminUser, "201", + UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, getUserResponse.getResponse()); + } + + @Test + public void createDeleteOpsUser() throws Exception { + + String httpCspUserId = "oo2000"; + String userFirstName = "ops"; + String userLastName = "opsLast"; + String email = "ops@intl.sdc.com"; + String role = "OPS"; + User sdncUserDetails = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + + deleteUserAndAudit(sdncUserDetails); + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, createUserResponse.getResponse()); + UserValidationUtils.validateAddUserAuditMessage(sdncUserDetails, sdncAdminUser, "201", + UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, getUserResponse.getResponse()); + + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + RestResponse getDeletedUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + assertEquals("Check response code after delete user", 404, getDeletedUserResponse.getErrorCode().intValue()); + + } + + @Test + public void createDeleteGOVERNORUser() throws Exception { + + String httpCspUserId = "gg2000"; + String userFirstName = "gov"; + String userLastName = "govLast"; + String email = "gov@intl.sdc.com"; + String role = "GOVERNOR"; + User sdncUserDetails = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + + deleteUserAndAudit(sdncUserDetails); + RestResponse createUserResponse = UserRestUtils.createUser(sdncUserDetails, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, createUserResponse.getResponse()); + UserValidationUtils.validateAddUserAuditMessage(sdncUserDetails, sdncAdminUser, "201", + UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + RestResponse getUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(sdncUserDetails, getUserResponse.getResponse()); + + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + RestResponse getDeletedUserResponse = UserRestUtils.getUser(sdncUserDetails, sdncAdminUser); + assertEquals("Check response code after delete user", 404, getDeletedUserResponse.getErrorCode().intValue()); + + } + + // Benny + // Admin Create OPS user + @Test + public void createOpsUser() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "aa1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + User expectedOpsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedOpsUser); + RestResponse createUserResponse = UserRestUtils.createUser(expectedOpsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedOpsUser, createUserResponse.getResponse()); + deleteAndCheckUserResponse(expectedOpsUser, 200); + + } + + // Admin Create GOVERNOR user + @Test + public void createGovernorUser() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "aa1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "GOVERNOR"; + User expectedUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedUser); + RestResponse createUserResponse = UserRestUtils.createUser(expectedUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedUser, createUserResponse.getResponse()); + RestResponse getUserResponse = UserRestUtils.getUser(expectedUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(expectedUser, getUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(expectedUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update user role from OPS to GOVERNOR + @Test + public void updateOpsUserRole() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ab1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + String updatedRole = "GOVERNOR"; + User opsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User governerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + RestResponse createUserResponse = UserRestUtils.createUser(opsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(opsUser, createUserResponse.getResponse()); + + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + opsUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 200, updateUserRoleResponse.getErrorCode().intValue()); + + RestResponse getUpdatedRoleUserResponse = UserRestUtils.getUser(governerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(governerUser, getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Designer Create OPS user -409 Response Restricted operation + @Test + public void createOpsUserByDesigner() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "aa1122"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + User expectedOpsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedOpsUser); + RestResponse createUserResponse = UserRestUtils.createUser(expectedOpsUser, sdncDesignerUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 409, createUserResponse.getErrorCode().intValue()); + assertEquals("Check response code after create user", "Conflict", createUserResponse.getResponseMessage()); + } + + // Tester Create OPS user -409 Response Restricted operation + @Test + public void createOpsUserByTester() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "aa1122"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + User expectedOpsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedOpsUser); + RestResponse createUserResponse = UserRestUtils.createUser(expectedOpsUser, sdncTesterUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 409, createUserResponse.getErrorCode().intValue()); + assertEquals("Check response code after create user", "Conflict", createUserResponse.getResponseMessage()); + } + + // Designer Try Update OPS user role to GOVERNOR - Response 409 + @Test + public void updateOpsUserRolebyDesigner() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "bt751e"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + String updatedRole = "GOVERNOR"; + User opsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User governerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // Admin create user with OPS role + RestResponse createUserResponse = UserRestUtils.createUser(opsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(opsUser, createUserResponse.getResponse()); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // Designer user try to update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncDesignerUser, + opsUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 409, updateUserRoleResponse.getErrorCode().intValue()); + assertEquals("Check response code after updating user", "Conflict", + updateUserRoleResponse.getResponseMessage()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Tester Try Update OPS user role to GOVERNOR - Response 409 + @Test + public void updateOpsUserRolebyTester() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "bt751w"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + String updatedRole = "GOVERNOR"; + User opsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User governerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // Admin create user with OPS role + RestResponse createUserResponse = UserRestUtils.createUser(opsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(opsUser, createUserResponse.getResponse()); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // Designer user try to update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncTesterUser, + opsUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 409, updateUserRoleResponse.getErrorCode().intValue()); + assertEquals("Check response code after updating user", "Conflict", + updateUserRoleResponse.getResponseMessage()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update user role from OPS to Designer + @Test + public void updateOpsUserRoleFromOpsToDesigner() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ab1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + String updatedRole = "DESIGNER"; + User opsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User designerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + RestResponse createUserResponse = UserRestUtils.createUser(opsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(opsUser, createUserResponse.getResponse()); + + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + opsUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 200, updateUserRoleResponse.getErrorCode().intValue()); + + RestResponse getUpdatedRoleUserResponse = UserRestUtils.getUser(designerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(designerUser, getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update user role from OPS to TESTER + @Test + public void updateOpsUserRoleFromOpsToTester() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ac1001"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + String updatedRole = "TESTER"; + User opsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User testerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + RestResponse createUserResponse = UserRestUtils.createUser(opsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(opsUser, createUserResponse.getResponse()); + + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + opsUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 200, updateUserRoleResponse.getErrorCode().intValue()); + + RestResponse getUpdatedRoleUserResponse = UserRestUtils.getUser(testerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(testerUser, getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Tester try to Update user role from OPS to GOVERNOR - Response 409 + // Conflict + @Test + public void updateOpsUserRoleByTester() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ad1001"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + String updatedRole = "GOVERNOR"; + User opsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User governerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + // Create user by Admin + RestResponse createUserResponse = UserRestUtils.createUser(opsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(opsUser, createUserResponse.getResponse()); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR by Tester + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncTesterUser, + opsUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 409, updateUserRoleResponse.getErrorCode().intValue()); + assertEquals("Check response code after updating user", "Conflict", + updateUserRoleResponse.getResponseMessage()); + + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Designer try to Update user role from OPS to GOVERNOR - Response 409 + // Conflict + @Test + public void updateOpsUserRoleByDesigner() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ad1001"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + String updatedRole = "GOVERNOR"; + User opsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + // User governerUser = new User(userFirstName, + // userLastName,httpCspUserId, email, updatedRole); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + // Create user by Admin + RestResponse createUserResponse = UserRestUtils.createUser(opsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(opsUser, createUserResponse.getResponse()); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR by Tester + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncDesignerUser, + opsUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 409, updateUserRoleResponse.getErrorCode().intValue()); + assertEquals("Check response code after updating user", "Conflict", + updateUserRoleResponse.getResponseMessage()); + + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Create OPS user - user already exist + @Test + public void createOpsUserAlreadyExist() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "af1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "OPS"; + User expectedOpsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedOpsUser); + RestResponse createUserResponse = UserRestUtils.createUser(expectedOpsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedOpsUser, createUserResponse.getResponse()); + // Create user that already exists + RestResponse createUserAgainResponse = UserRestUtils.createUser(expectedOpsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserAgainResponse); + assertNotNull("check error code exists in response after create user", createUserAgainResponse.getErrorCode()); + assertEquals("Check response code after create user", 409, createUserAgainResponse.getErrorCode().intValue()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(expectedOpsUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update user role from OPS to GOVERNOR - user already has GOVERNOR + // role + @Test + public void updateRoleToSameRole() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ag1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "GOVERNOR"; + String updatedRole = "GOVERNOR"; + User opsUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User governerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + RestResponse createUserResponse = UserRestUtils.createUser(opsUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(opsUser, createUserResponse.getResponse()); + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from GOVERNOR to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + opsUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 200, updateUserRoleResponse.getErrorCode().intValue()); + + RestResponse getUpdatedRoleUserResponse = UserRestUtils.getUser(governerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(governerUser, getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update user role from Tester to GOVERNOR - 200 response + + // Admin Update user role from Designer to GOVERNOR - 200 response + @Test + public void updateUserRoleDesignerToGovernor() throws Exception { + DbUtils.cleanAllAudits(); + String httpCspUserId = "ah1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "DESIGNER"; + String updatedRole = "GOVERNOR"; + User designerUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User governerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(designerUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(designerUser, createUserResponse.getResponse()); + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from TESTER to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + designerUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 200, updateUserRoleResponse.getErrorCode().intValue()); + // Update user role + RestResponse getUpdatedRoleUserResponse = UserRestUtils.getUser(governerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(governerUser, getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(designerUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update deactivated user role - response 404 (user not found) + @Test + public void updateRoleToDeactivatedUser() throws Exception { + DbUtils.cleanAllAudits(); + String httpCspUserId = "aj1001"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "DESIGNER"; + String updatedRole = "GOVERNOR"; + User designerUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User governerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(designerUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(designerUser, createUserResponse.getResponse()); + deleteAndCheckUserResponse(designerUser, 200); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role - user deActivted + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + designerUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after create user", 404, updateUserRoleResponse.getErrorCode().intValue()); + } + + // Admin Update user role, user does not exist in DB - response 404 (user + // not found) + @Test + public void updateRoleForNonExistingUser() throws Exception { + DbUtils.cleanAllAudits(); + String httpCspUserId = "aj1001"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "DESIGNER"; + String updatedRole = "GOVERNOR"; + User designerUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + // User governerUser = new User(userFirstName, + // userLastName,httpCspUserId, email, updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role - user deActivted + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + designerUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 404, updateUserRoleResponse.getErrorCode().intValue()); + + } + + // Admin Update user role from GOVERNOR to TESTER + @Test + public void updateRoleFromGovernorToTester() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ak1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "GOVERNOR"; + String updatedRole = "TESTER"; + User governorUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User testerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + RestResponse createUserResponse = UserRestUtils.createUser(governorUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(governorUser, createUserResponse.getResponse()); + + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + governorUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 200, updateUserRoleResponse.getErrorCode().intValue()); + + RestResponse getUpdatedRoleUserResponse = UserRestUtils.getUser(testerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(testerUser, getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(governorUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update user role from GOVERNOR to DESIGNER + @Test + public void updateRoleFromGovernorToDesigner() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ak1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "GOVERNOR"; + String updatedRole = "DESIGNER"; + User governorUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User designerUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + RestResponse createUserResponse = UserRestUtils.createUser(governorUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(governorUser, createUserResponse.getResponse()); + + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + governorUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 200, updateUserRoleResponse.getErrorCode().intValue()); + + RestResponse getUpdatedRoleUserResponse = UserRestUtils.getUser(designerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(designerUser, getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(governorUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update user role from GOVERNOR to OPS + @Test + public void updateRoleFromGovernorToOps() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ak1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "GOVERNOR"; + String updatedRole = "OPS"; + User governorUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User opsUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + RestResponse createUserResponse = UserRestUtils.createUser(governorUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(governorUser, createUserResponse.getResponse()); + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + governorUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 200, updateUserRoleResponse.getErrorCode().intValue()); + + RestResponse getUpdatedRoleUserResponse = UserRestUtils.getUser(opsUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(opsUser, getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + deleteAndCheckUserResponse(governorUser, 200); + + } + + private void deleteAndCheckUserResponse(User userDetailes, int expectedResponseCode) throws IOException { + RestResponse deleteUser = UserRestUtils.deleteUser(sdncGovernorUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteUser); + assertEquals("Check response code after deleting user", expectedResponseCode, + deleteUser.getErrorCode().intValue()); + } + + // Admin Update user role from GOVERNOR to ADMIN + @Test + public void updateRoleFromGovernorToAdmin() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ak1000"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "GOVERNOR"; + String updatedRole = "ADMIN"; + User governorUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User adminUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + RestResponse createUserResponse = UserRestUtils.createUser(governorUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(governorUser, createUserResponse.getResponse()); + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + governorUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 200, updateUserRoleResponse.getErrorCode().intValue()); + + RestResponse getUpdatedRoleUserResponse = UserRestUtils.getUser(adminUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(adminUser, getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(governorUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update user role to non existing role - Response 400 Bad Request + @Test + public void updateRoleToNonExistingRole() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "al1001"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "GOVERNOR"; + String updatedRole = "VVVVVVV"; + User governorUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User newUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + RestResponse createUserResponse = UserRestUtils.createUser(governorUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(governorUser, createUserResponse.getResponse()); + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role from OPS to GOVERNOR + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + governorUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 400, updateUserRoleResponse.getErrorCode().intValue()); + assertEquals("Check response code after updating user", "Bad Request", + updateUserRoleResponse.getResponseMessage()); + + // RestResponse getUpdatedRoleUserResponse = + // UserRestUtils.getUser(adminUser,sdncAdminUser); + // UserValidationUtils.validateUserDetailsOnResponse(adminUser,getUpdatedRoleUserResponse.getResponse()); + // Delete OPS user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(governorUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // Admin Update user role to null - Response 400 Bad Request + @Test + public void updateRoleToNull() throws Exception { + DbUtils.cleanAllAudits(); + + String httpCspUserId = "ax1001"; + String userFirstName = "Benny"; + String userLastName = "Tal"; + String email = "optBenny@intl.sdc.com"; + String role = "GOVERNOR"; + String updatedRole = ""; + User governorUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + User newUser = new User(userFirstName, userLastName, httpCspUserId, email, updatedRole, null); + // UserRestUtils.deleteUser(opsUser, sdncAdminUser, true); + // UserRestUtils.deleteUser(UserUpdateRole, sdncAdminUser); + RestResponse createUserResponse = UserRestUtils.createUser(governorUser, sdncAdminUser); + assertNotNull("check response object is not null after create user", createUserResponse); + assertNotNull("check error code exists in response after create user", createUserResponse.getErrorCode()); + assertEquals("Check response code after create user", 201, createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(governorUser, createUserResponse.getResponse()); + // opsUser.setRole(updatedRole); + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // update user role + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + governorUser.getUserId()); + assertNotNull("check response object is not null after updating user", updateUserRoleResponse); + assertNotNull("check error code exists in response after updating user", updateUserRoleResponse.getErrorCode()); + assertEquals("Check response code after updating user", 400, updateUserRoleResponse.getErrorCode().intValue()); + assertEquals("Check response code after updating user", "Bad Request", + updateUserRoleResponse.getResponseMessage()); + // Delete user + RestResponse deleteOpsUser = UserRestUtils.deleteUser(governorUser, sdncAdminUser, true); + assertNotNull("check response object is not null after deleting user", deleteOpsUser); + assertEquals("Check response code after deleting user", 200, deleteOpsUser.getErrorCode().intValue()); + + } + + // create user with one optional parameter last name (UserID, Email, Last + // Name, Creator details) + // expected: role = DESIGNER, first name = null, 201 Created + // @Test + // public void createUserLastName(){ + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // // create user with one optional parameter role name (UserID, Email, Role + // = "TESTER", Creator details) + // // expected: first and last name = null, 201 Created + // @Test + // public void createUserRoleName(){ + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // // create user with two optional parameters first name and role (UserID, + // Email, First Name, Role = "ADMIN", Creator details) + // // expected: last name = null, 201 Created + // @Test + // public void createUserFirstNameAndRole(){ + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // // create user with two optional parameters first and last name(UserID, + // Email, First Name, Last name, Creator details) + // // expected: role = DESIGNER, 201 Created + // @Test + // public void createUserFirstAndLastName(){ + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // + // + // + // + // // + // **********************************************************Create*user*failed*************************************************** + // + // // + // **********************************************************403*************************************************** + // // create default user without creator details (UserID, Email) + // // expected: 403 Forbidden, error message:"Error : Missing information" + // @Test + // public void createDefaultUserNonCreatorDetails(){ + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // + // // create user with part of creator details (UserID, Email, First name, + // Last Name, Role, Part of creator details) + // // expected: 403 Forbidden, error message:"Error : Missing information" + // @Test + // public void createUserPartOfCreatorDetails(){ + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // // create user with full parameter set, non admin creator(UserID, First + // Name, Last Name, Email, Role, Creator details) + // // expected: 403 Forbidden, error message: + // "Error : Restricted operation" + // @Test + // public void createUserNonAdminCreator(){ + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // + // // + // **********************************************************405*************************************************** + // + // // create user with full parameter set by sending http PUT request + // (UserID, First Name, Last Name, Email, Role, Creator details) + // // expected: 405 not Allowed, error message: + // "Error : Method not allowed" + // @Test + // public void createUserPutRequest(){ + // // send PUT create user request + // // validate data on response + // // check the audit message + // } + // + // + // // create default user by sending http PUT request (UserID, Email, + // Creator details) + // // expected: 405 not Allowed, error message: + // "Error : Method not allowed" + // @Test + // public void createDefaultUserPutRequest(){ + // // send PUT create user request + // // validate data on response + // // check the audit message + // } + // + // + // // create user with full parameter set by sending http DELETE request + // (UserID, First Name, Last Name, Email, Role, Creator details) + // // expected: 405 not Allowed, error message: + // "Error : Method not allowed" + // @Test + // public void createUserDeleteRequest(){ + // // send DELETE create user request + // // validate data on response + // // check the audit message + // } + // + // + // // create default user by sending http DELETE request (UserID, Email, + // Creator details) + // // expected: 405 not Allowed, error message: + // "Error : Method not allowed" + // @Test + // public void createDefaultUserDeleteRequest(){ + // // send DELETE create user request + // // validate data on response + // // check the audit message + // } + // + // + // // create user with full parameter set by sending http GET request + // (UserID, First Name, Last Name, Email, Role, Creator details) + // // expected: 405 not Allowed, error message: + // "Error : Method not allowed" + // @Test + // public void createUserGetRequest(){ + // // send GET create user request + // // validate data on response + // // check the audit message + // } + // + // + // // create default user by sending http GET request (UserID, Email, + // Creator details) + // // expected: 405 not Allowed, error message: + // "Error : Method not allowed" + // @Test + // public void createDefaultUserGetRequest(){ + // // send GET create user request + // // validate data on response + // // check the audit message + // } + // + // + // // + // **********************************************************409*************************************************** + // + // // create the same user twice with full parameter set(UserID, First Name, + // Last Name, Email, Role, Creator details) + // // expected 409 Conflict, error message: + // "Error : User with '%s' ID already exists", where: %s - USER_ID + // @Test + // public void createSameUserTwice(){ + // // send POST create user request + // // validate data on response + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // // create user twice, first full details (UserID, First Name, Last Name, + // Email, Role, Creator details), second default user (UserID, Email, Role, + // Creator details) + // // expected 409 Conflict, error message: + // "Error : User with '%s' ID already exists", where: %s - USER_ID + // @Test + // public void createFullThanDefaultUserTwice(){ + // // send POST create user request + // + // // validate data on response + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // // create user twice, first default user (UserID, Email, Role, Creator + // details), second full details (UserID, First Name, Last Name, Email, + // Role, Creator details) + // // expected 409 Conflict, error message: + // "Error : User with '%s' ID already exists", where: %s - USER_ID + // @Test + // public void createDefaulThanFullUserTwice(){ + // // send POST create user request + // + // // validate data on response + // // send POST create user request + // // validate data on response + // // check the audit message + // } + // + // + // // + // **********************************************************400*************************************************** + // // create default user with invalid email address format(UserID, Email, + // Creator details) + // // expected: 400, error message: + // "Error : Invalid Content . Invalid e-mail address '%s'", where %s - + // email address + // @Test + // public void createDefaultUserInvalidEmailAddressFormat(){ + // // send GET create user request + // // validate data on response + // // check the audit message + // } + // + // // create an user with invalid role type (UserID, Email,Role = "TESTER-1" + // ,Creator details) + // // expected: 400, error message: + // "Error : Invalid Content . Invalid role '%s'", where %s - role type + // @Test + // public void createUserInvalidRoleType(){ + // // send GET create user request + // // validate data on response + // // check the audit message + // } + // + // // + // **********************************************************500*************************************************** + // // create default user when BE is down (UserID, Email, Creator details) + // // expected: 500, error message: + // "Error : Internal Server Error . Try later again." + // @Test + // public void createDefaultUserBeNoAccess(){ + // // send GET create user request + // // validate data on response + // // check the audit message + // } + // + + // Benny US570551 + + @Test + public void createProductManagerUser() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Man"; + String email = "prodMan@intl.sdc.com"; + String role = "PRODUCT_MANAGER"; + User expectedProductManagerUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + UserRestUtils.deleteUser(expectedProductManagerUser, sdncAdminUser, true); + DbUtils.deleteFromEsDbByPattern("_all"); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductManagerUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_SUCSESS_CREATED, + createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, createUserResponse.getResponse()); + // Audit validation + UserValidationUtils.validateAddUserAuditMessage(expectedProductManagerUser, sdncAdminUser, + Integer.toString(STATUS_CODE_SUCSESS_CREATED), UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + // get user and compare with expected + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductManagerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, getUserResponse.getResponse()); + // Delete ProductManager user + RestResponse deleteProductManagerUser = UserRestUtils.deleteUser(expectedProductManagerUser, sdncAdminUser, + true); + assertEquals("Check response code after deleting OPS user", STATUS_CODE_SUCCESS, + deleteProductManagerUser.getErrorCode().intValue()); + } + + @Test + public void createProductStrategistUser() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Strategist"; + String email = "prodStr@intl.sdc.com"; + String role = "PRODUCT_STRATEGIST"; + User expectedProductStrategistUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + UserRestUtils.deleteUser(expectedProductStrategistUser, sdncAdminUser, true); + DbUtils.deleteFromEsDbByPattern("_all"); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductStrategistUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_SUCSESS_CREATED, + createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductStrategistUser, + createUserResponse.getResponse()); + // Audit validation + UserValidationUtils.validateAddUserAuditMessage(expectedProductStrategistUser, sdncAdminUser, + Integer.toString(STATUS_CODE_SUCSESS_CREATED), UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + // get user and compare with expected + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductStrategistUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductStrategistUser, getUserResponse.getResponse()); + // Delete ProductStrategist user + RestResponse deleteProductStrategistUser = UserRestUtils.deleteUser(expectedProductStrategistUser, + sdncAdminUser, true); + assertNotNull("Check response object is not null after deleting OPS user", deleteProductStrategistUser); + assertEquals("Check response code after deleting OPS user", 200, + deleteProductStrategistUser.getErrorCode().intValue()); + } + + @Test + public void createProductStrategistUserByNonAdminUser() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Strategist"; + String email = "prodStr@intl.sdc.com"; + String role = "PRODUCT_STRATEGIST"; + User expectedProductStrategistUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + UserRestUtils.deleteUser(expectedProductStrategistUser, sdncAdminUser, true); + DbUtils.deleteFromEsDbByPattern("_all"); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductStrategistUser, sdncDesignerUser); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_RESTRICTED_OPERATION, + createUserResponse.getErrorCode().intValue()); + // Audit validation + expectedProductStrategistUser.setUserId(""); + expectedProductStrategistUser.setFirstName(null); + expectedProductStrategistUser.setLastName(null); + expectedProductStrategistUser.setEmail(""); + expectedProductStrategistUser.setRole(""); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + UserValidationUtils.validateAddUserAuditMessage(expectedProductStrategistUser, sdncDesignerUser, + Integer.toString(STATUS_CODE_RESTRICTED_OPERATION), errorInfo.getAuditDesc(""), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + // Try to get user - user is not created + expectedProductStrategistUser.setUserId("pm1000"); + expectedProductStrategistUser.setFirstName("Prod"); + expectedProductStrategistUser.setLastName("Strategist"); + expectedProductStrategistUser.setEmail("prodStr@intl.sdc.com"); + expectedProductStrategistUser.setRole("PRODUCT_STRATEGIST"); + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductStrategistUser, sdncAdminUser); + assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, getUserResponse.getErrorCode().intValue()); + } + + @Test + public void createProductManagerUserByNonAdminUser() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Man"; + String email = "prodStr@intl.sdc.com"; + String role = "PRODUCT_MANAGER"; + User expectedProductStrategistUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + UserRestUtils.deleteUser(expectedProductStrategistUser, sdncAdminUser, true); + DbUtils.deleteFromEsDbByPattern("_all"); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductStrategistUser, sdncDesignerUser); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_RESTRICTED_OPERATION, + createUserResponse.getErrorCode().intValue()); + // Audit validation + expectedProductStrategistUser.setUserId(""); + expectedProductStrategistUser.setFirstName(null); + expectedProductStrategistUser.setLastName(null); + expectedProductStrategistUser.setEmail(""); + expectedProductStrategistUser.setRole(""); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + UserValidationUtils.validateAddUserAuditMessage(expectedProductStrategistUser, sdncDesignerUser, + Integer.toString(STATUS_CODE_RESTRICTED_OPERATION), errorInfo.getAuditDesc(""), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + // Try to get user - user is not created + expectedProductStrategistUser.setUserId("pm1000"); + expectedProductStrategistUser.setFirstName("Prod"); + expectedProductStrategistUser.setLastName("Strategist"); + expectedProductStrategistUser.setEmail("prodStr@intl.sdc.com"); + expectedProductStrategistUser.setRole("PRODUCT_MANAGER"); + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductStrategistUser, sdncAdminUser); + assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, getUserResponse.getErrorCode().intValue()); + } + + @Test + public void createProductStrategistUserByNonExistingUser() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Strategist"; + String email = "prodStr@intl.sdc.com"; + String role = "PRODUCT_STRATEGIST"; + User noSdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + noSdncUserDetails.setRole("blabla"); + noSdncUserDetails.setUserId("bt750h"); + User expectedProductStrategistUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + DbUtils.deleteFromEsDbByPattern("_all"); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductStrategistUser, noSdncUserDetails); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_NOT_FOUND, + createUserResponse.getErrorCode().intValue()); + // Audit validation + expectedProductStrategistUser.setUserId(""); + expectedProductStrategistUser.setFirstName(null); + expectedProductStrategistUser.setLastName(null); + expectedProductStrategistUser.setEmail(""); + expectedProductStrategistUser.setRole(""); + noSdncUserDetails.setFirstName(""); + noSdncUserDetails.setLastName(""); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_NOT_FOUND.name()); + UserValidationUtils.validateAddUserAuditMessage(expectedProductStrategistUser, noSdncUserDetails, + Integer.toString(STATUS_CODE_NOT_FOUND), errorInfo.getAuditDesc(noSdncUserDetails.getUserId()), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + // Try to get user - user is not created + expectedProductStrategistUser.setUserId("pm1000"); + expectedProductStrategistUser.setFirstName("Prod"); + expectedProductStrategistUser.setLastName("Strategist"); + expectedProductStrategistUser.setEmail("prodStr@intl.sdc.com"); + expectedProductStrategistUser.setRole("PRODUCT_STRATEGIST"); + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductStrategistUser, sdncAdminUser); + assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, getUserResponse.getErrorCode().intValue()); + } + + @Test + public void createProductManagerUserByNonExistingUser() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Man"; + String email = "prodStr@intl.sdc.com"; + String role = "PRODUCT_MANAGER"; + User noSdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + noSdncUserDetails.setRole("blabla"); + noSdncUserDetails.setUserId("bt750h"); + User expectedProductStrategistUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + DbUtils.deleteFromEsDbByPattern("_all"); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductStrategistUser, noSdncUserDetails); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_NOT_FOUND, + createUserResponse.getErrorCode().intValue()); + // Audit validation + expectedProductStrategistUser.setUserId(""); + expectedProductStrategistUser.setFirstName(null); + expectedProductStrategistUser.setLastName(null); + expectedProductStrategistUser.setEmail(""); + expectedProductStrategistUser.setRole(""); + noSdncUserDetails.setFirstName(""); + noSdncUserDetails.setLastName(""); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_NOT_FOUND.name()); + UserValidationUtils.validateAddUserAuditMessage(expectedProductStrategistUser, noSdncUserDetails, + Integer.toString(STATUS_CODE_NOT_FOUND), errorInfo.getAuditDesc(noSdncUserDetails.getUserId()), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + // Try to get user - user is not created + expectedProductStrategistUser.setUserId("pm1000"); + expectedProductStrategistUser.setFirstName("Prod"); + expectedProductStrategistUser.setLastName("Strategist"); + expectedProductStrategistUser.setEmail("prodStr@intl.sdc.com"); + expectedProductStrategistUser.setRole("PRODUCT_MANAGER"); + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductStrategistUser, sdncAdminUser); + assertEquals("Check response code ", STATUS_CODE_NOT_FOUND, getUserResponse.getErrorCode().intValue()); + } + + @Test(enabled = false) + public void updateProjectManagerRole() throws Exception { + // Update user role from PRODUCT_STRATEGIST to PRODUCT_MANAGER + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Man"; + String email = "prodMan@intl.sdc.com"; + String role = "PRODUCT_MANAGER"; + String updatedRole = "GOVERNOR"; + User expectedProductManagerUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedProductManagerUser); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductManagerUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_SUCSESS_CREATED, + createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, createUserResponse.getResponse()); + // Update user role + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // Update user role from PRODUCT_STRATEGIST to PRODUCT_MANAGER + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + expectedProductManagerUser.getUserId()); + assertEquals("Check response code after create user", STATUS_CODE_SUCCESS, + updateUserRoleResponse.getErrorCode().intValue()); + expectedProductManagerUser.setRole(updatedRole); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, + updateUserRoleResponse.getResponse()); + // Audit validation + UserValidationUtils.validateAddUserAuditMessage(expectedProductManagerUser, sdncAdminUser, + Integer.toString(STATUS_CODE_SUCCESS), UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("UpdateUser")); + // get user and compare with expected + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductManagerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, getUserResponse.getResponse()); + // Delete ProductManager user + RestResponse deleteProductManagerUser = UserRestUtils.deleteUser(expectedProductManagerUser, sdncAdminUser, + true); + assertEquals("Check response code after deleting OPS user", STATUS_CODE_SUCCESS, + deleteProductManagerUser.getErrorCode().intValue()); + } + + @Test(enabled = false) + public void updateProductStrategistRole() throws Exception { + // Update user role from PRODUCT_STRATEGIST to PRODUCT_MANAGER + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Strategist"; + String email = "prodMan@intl.sdc.com"; + String role = "PRODUCT_STRATEGIST"; + String updatedRole = "TESTER"; + User expectedProductManagerUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedProductManagerUser); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductManagerUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_SUCSESS_CREATED, + createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, createUserResponse.getResponse()); + // Update user role + User newRoleUser = new User(); + newRoleUser.setRole(updatedRole); + // Update user role from PRODUCT_STRATEGIST to PRODUCT_MANAGER + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + expectedProductManagerUser.getUserId()); + assertEquals("Check response code after create user", STATUS_CODE_SUCCESS, + updateUserRoleResponse.getErrorCode().intValue()); + expectedProductManagerUser.setRole(updatedRole); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, + updateUserRoleResponse.getResponse()); + // Audit validation + UserValidationUtils.validateAddUserAuditMessage(expectedProductManagerUser, sdncAdminUser, + Integer.toString(STATUS_CODE_SUCCESS), UserResponseMessageEnum.SUCCESS_MESSAGE.getValue(), + UserValidationUtils.getAddUserAuditMessage("UpdateUser")); + // get user and compare with expected + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductManagerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, getUserResponse.getResponse()); + // Delete ProductManager user + RestResponse deleteProductManagerUser = UserRestUtils.deleteUser(expectedProductManagerUser, sdncAdminUser, + true); + assertEquals("Check response code after deleting OPS user", STATUS_CODE_SUCCESS, + deleteProductManagerUser.getErrorCode().intValue()); + } + + @Test + public void createProductManagerUserAlreadyExit() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Man"; + String email = "prodMan@intl.sdc.com"; + String role = "PRODUCT_MANAGER"; + User expectedProductManagerUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedProductManagerUser); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductManagerUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_SUCSESS_CREATED, + createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, createUserResponse.getResponse()); + // create same user again + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse createUserAgainResponse = UserRestUtils.createUser(expectedProductManagerUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", USER_ALREADY_EXIST, + createUserAgainResponse.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_ALREADY_EXIST.name()); + UserValidationUtils.validateAddUserAuditMessage(expectedProductManagerUser, sdncAdminUser, + Integer.toString(USER_ALREADY_EXIST), errorInfo.getAuditDesc(expectedProductManagerUser.getUserId()), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + // get user and compare with expected + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductManagerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, getUserResponse.getResponse()); + // Delete ProductManager user + RestResponse deleteProductManagerUser = UserRestUtils.deleteUser(expectedProductManagerUser, sdncAdminUser, + true); + assertEquals("Check response code after deleting OPS user", STATUS_CODE_SUCCESS, + deleteProductManagerUser.getErrorCode().intValue()); + } + + @Test + public void createProductStrategistUserAlreadyExit() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Strategist"; + String email = "prodMan@intl.sdc.com"; + String role = "PRODUCT_STRATEGIST"; + User expectedProductManagerUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedProductManagerUser); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductManagerUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_SUCSESS_CREATED, + createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, createUserResponse.getResponse()); + // create same user again + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse createUserAgainResponse = UserRestUtils.createUser(expectedProductManagerUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", USER_ALREADY_EXIST, + createUserAgainResponse.getErrorCode().intValue()); + // Audit validation + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.USER_ALREADY_EXIST.name()); + UserValidationUtils.validateAddUserAuditMessage(expectedProductManagerUser, sdncAdminUser, + Integer.toString(USER_ALREADY_EXIST), errorInfo.getAuditDesc(expectedProductManagerUser.getUserId()), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + // get user and compare with expected + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductManagerUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductManagerUser, getUserResponse.getResponse()); + // Delete ProductManager user + RestResponse deleteProductManagerUser = UserRestUtils.deleteUser(expectedProductManagerUser, sdncAdminUser, + true); + assertEquals("Check response code after deleting OPS user", STATUS_CODE_SUCCESS, + deleteProductManagerUser.getErrorCode().intValue()); + } + + @Test(enabled = false) + public void UpdateProductStrategistToNonExistingRole() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Strategist"; + String email = "prodMan@intl.sdc.com"; + String role = "PRODUCT_STRATEGIST"; + String nonExistingRole = "BLABLA"; + User expectedProductStrategistUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedProductStrategistUser); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductStrategistUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", STATUS_CODE_SUCSESS_CREATED, + createUserResponse.getErrorCode().intValue()); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductStrategistUser, + createUserResponse.getResponse()); + // Update user Role to non Existing role + User newRoleUser = new User(); + newRoleUser.setRole(nonExistingRole); + DbUtils.deleteFromEsDbByPattern("_all"); + RestResponse updateUserRoleResponse = UserRestUtils.updateUserRole(newRoleUser, sdncAdminUser, + expectedProductStrategistUser.getUserId()); + assertEquals("Check response code after updating user role", INVALID_ROLE, + updateUserRoleResponse.getErrorCode().intValue()); + + // Audit validation + /* + * expectedProductStrategistUser.setUserId(""); + * expectedProductStrategistUser.setFirstName(null); + * expectedProductStrategistUser.setLastName(null); + * expectedProductStrategistUser.setEmail(""); + * expectedProductStrategistUser.setRole(""); + */ + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_ROLE.name()); + UserValidationUtils.validateAddUserAuditMessage(expectedProductStrategistUser, sdncAdminUser, + Integer.toString(INVALID_ROLE), errorInfo.getAuditDesc(nonExistingRole), + UserValidationUtils.getAddUserAuditMessage("UpdateUser")); + // get user and compare with expected + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductStrategistUser, sdncAdminUser); + UserValidationUtils.validateUserDetailsOnResponse(expectedProductStrategistUser, getUserResponse.getResponse()); + // Delete ProductManager user + RestResponse deleteProductManagerUser = UserRestUtils.deleteUser(expectedProductStrategistUser, sdncAdminUser, + true); + assertEquals("Check response code after deleting OPS user", STATUS_CODE_SUCCESS, + deleteProductManagerUser.getErrorCode().intValue()); + } + + @Test(enabled = false) + public void createUserWithNonExistingRole() throws Exception { + String httpCspUserId = "pm1000"; + String userFirstName = "Prod"; + String userLastName = "Strategist"; + String email = "prodMan@intl.sdc.com"; + String role = "BLABLA"; + User expectedProductStrategistUser = new User(userFirstName, userLastName, httpCspUserId, email, role, null); + deleteUserAndAudit(expectedProductStrategistUser); + // create user + RestResponse createUserResponse = UserRestUtils.createUser(expectedProductStrategistUser, sdncAdminUser); + assertEquals("Check response code after create Product-Manager user", INVALID_ROLE, + createUserResponse.getErrorCode().intValue()); + + // Audit validation + /* + * expectedProductStrategistUser.setUserId(""); + * expectedProductStrategistUser.setFirstName(null); + * expectedProductStrategistUser.setLastName(null); + * expectedProductStrategistUser.setEmail(""); + * expectedProductStrategistUser.setRole(""); + */ + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_ROLE.name()); + UserValidationUtils.validateAddUserAuditMessage(expectedProductStrategistUser, sdncAdminUser, + Integer.toString(INVALID_ROLE), errorInfo.getAuditDesc(role), + UserValidationUtils.getAddUserAuditMessage("AddUser")); + // get user - verify user is not createdand compare with expected + RestResponse getUserResponse = UserRestUtils.getUser(expectedProductStrategistUser, sdncAdminUser); + assertEquals("Check user not created", STATUS_CODE_NOT_FOUND, getUserResponse.getErrorCode().intValue()); + + } + + private void deleteUserAndAudit(User sdncUserDetails) throws IOException { + UserRestUtils.deleteUser(sdncUserDetails, sdncAdminUser, true); + DbUtils.cleanAllAudits(); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/GovernorWorkspaceApiTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/GovernorWorkspaceApiTest.java new file mode 100644 index 0000000000..5dd1abcf24 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/user/GovernorWorkspaceApiTest.java @@ -0,0 +1,319 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.user; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.List; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.lifecycle.LCSbaseTest; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ServiceValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class GovernorWorkspaceApiTest extends ComponentBaseTest { + + private static Logger logger = LoggerFactory.getLogger(GovernorWorkspaceApiTest.class.getName()); + @Rule + public static TestName name = new TestName(); + + public GovernorWorkspaceApiTest() { + super(name, GovernorWorkspaceApiTest.class.getName()); + + } + + protected final User admin1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + protected final User governor = ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR); + protected final User sdncDesignerDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + protected ResourceReqDetails resourceDetails1; + protected ComponentInstanceReqDetails componentInstanceReqDetails; + protected ArtifactReqDetails heatArtifactDetails; + + protected final String serviceVersion = "0.1"; + protected final String servicesString = "services"; + protected final String userRemarks = "commentTest"; + + protected ServiceReqDetails serviceDetails11 = null; + protected ServiceReqDetails serviceDetails22 = null; + protected ServiceReqDetails serviceDetails33 = null; + + @BeforeMethod + public void initBeforeTest() throws Exception { + DbUtils.deleteFromEsDbByPattern("_all"); + Resource resourceObj = AtomicOperationUtils + .createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resourceDetails1 = new ResourceReqDetails(resourceObj); + heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + createThreeServices(sdncDesignerDetails1); + } + + protected void createThreeServices(User user) throws Exception { + + String checkinComment = "good checkin"; + String checkinComentJson = "{\"userRemarks\": \"" + checkinComment + "\"}"; + + RestResponse addInformationalArtifactToResource = ArtifactRestUtils.addInformationalArtifactToResource( + heatArtifactDetails, sdncDesignerDetails1, resourceDetails1.getUniqueId()); + RestResponse certifyResource = LifecycleRestUtils.certifyResource(resourceDetails1); + componentInstanceReqDetails = ElementFactory.getDefaultComponentInstance("defaultInstance", resourceDetails1); + + serviceDetails11 = ElementFactory.getDefaultService(); + serviceDetails22 = ElementFactory.getDefaultService(); + serviceDetails33 = ElementFactory.getDefaultService(); + + serviceDetails11.setName(serviceDetails11.getName() + "1"); + List tags = serviceDetails11.getTags(); + tags.add(serviceDetails11.getName()); + serviceDetails11.setTags(tags); + + serviceDetails22.setName(serviceDetails11.getName() + "2"); + tags = serviceDetails22.getTags(); + tags.add(serviceDetails22.getName()); + serviceDetails22.setTags(tags); + + serviceDetails33.setName(serviceDetails11.getName() + "3"); + tags = serviceDetails33.getTags(); + tags.add(serviceDetails33.getName()); + serviceDetails33.setTags(tags); + + RestResponse createServiceResponse1 = createService(user, serviceDetails11); + RestResponse createServiceResponse2 = createService(user, serviceDetails22); + RestResponse createServiceResponse3 = createService(user, serviceDetails33); + } + + protected RestResponse createService(User user, ServiceReqDetails serviceDetails) throws Exception, IOException { + RestResponse createServiceResponse1 = ServiceRestUtils.createService(serviceDetails, user); + assertNotNull("check response object is not null after creating service", createServiceResponse1); + assertNotNull("check if error code exists in response after creating service", + createServiceResponse1.getErrorCode()); + assertEquals("Check response code after creating service", 201, + createServiceResponse1.getErrorCode().intValue()); + Service convertServiceResponseToJavaObject = ResponseParser + .convertServiceResponseToJavaObject(createServiceResponse1.getResponse()); + serviceDetails.setUniqueId(convertServiceResponseToJavaObject.getUniqueId()); + logger.debug("Created service1 ={}", serviceDetails); + addResourceWithHeatArt(serviceDetails); + return createServiceResponse1; + } + + protected void addResourceWithHeatArt(ServiceReqDetails serviceDetails) throws Exception { + + RestResponse createResourceInstance = ComponentInstanceRestUtils.createComponentInstance( + componentInstanceReqDetails, sdncDesignerDetails1, serviceDetails.getUniqueId(), + ComponentTypeEnum.SERVICE); + // System.out.println("serviceUID --->" + serviceDetails.getUniqueId()); + assertEquals("Check response code ", 201, createResourceInstance.getErrorCode().intValue()); + } + + protected void certifyAllServices() throws Exception { + LifecycleRestUtils.certifyService(serviceDetails11); + LifecycleRestUtils.certifyService(serviceDetails22); + LifecycleRestUtils.certifyService(serviceDetails33); + } + + protected boolean isElementInArray(String elementId, JSONArray jsonArray) throws Exception { + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jobject = (JSONObject) jsonArray.get(i); + + if (jobject.get("uniqueId").toString().equals(elementId)) { + return true; + } + } + return false; + } + + protected void approveDistributionStatusOfCertifiedService(ServiceReqDetails serviceDetails, User user) + throws Exception { + approveDistributionStatusOfService(serviceDetails, user, "1.0"); + } + + protected void approveDistributionStatusOfService(ServiceReqDetails serviceDetails, User user, String version) + throws Exception { + RestResponse res = LifecycleRestUtils.sendApproveDistribution(user, serviceDetails.getUniqueId(), userRemarks); + assertEquals(200, res.getErrorCode().intValue()); + ServiceValidationUtils.validateDistrubtionStatusValue(res, DistributionStatusEnum.DISTRIBUTION_APPROVED); + } + + protected void rejectDistributionStatusOfService(ServiceReqDetails serviceDetails, User user) throws Exception { + rejectDistributionStatusOfService(serviceDetails, user, "1.0"); + } + + protected void rejectDistributionStatusOfService(ServiceReqDetails serviceDetails, User user, String version) + throws Exception { + RestResponse res = LifecycleRestUtils.rejectDistribution(serviceDetails, version, user, userRemarks); + assertEquals(200, res.getErrorCode().intValue()); + ServiceValidationUtils.validateDistrubtionStatusValue(res, DistributionStatusEnum.DISTRIBUTION_REJECTED); + } + + protected JSONArray getFollowedListAsJsonArray(User user) throws Exception { + RestResponse getGovernorFollowed = ServiceRestUtils.getFollowed(user); + assertNotNull(getGovernorFollowed); + assertNotNull(getGovernorFollowed.getErrorCode()); + assertEquals(200, getGovernorFollowed.getErrorCode().intValue()); + + JSONArray listArrayFromRestResponse = ServiceRestUtils.getListArrayFromRestResponse(getGovernorFollowed); + + return listArrayFromRestResponse; + } + + protected void changeDistributionStatusOfAllService(boolean approved, User user) throws Exception { + if (approved) { + approveDistributionStatusOfCertifiedService(serviceDetails11, user); + approveDistributionStatusOfCertifiedService(serviceDetails22, user); + approveDistributionStatusOfCertifiedService(serviceDetails33, user); + } else { + rejectDistributionStatusOfService(serviceDetails11, user); + rejectDistributionStatusOfService(serviceDetails22, user); + rejectDistributionStatusOfService(serviceDetails33, user); + } + + } + + protected JSONArray checkFollowed(User user) throws Exception { + JSONArray getFollowedList = getFollowedListAsJsonArray(user); + assertFalse(getFollowedList.isEmpty()); + assertTrue(isElementInArray(serviceDetails11.getUniqueId(), getFollowedList)); + assertTrue(isElementInArray(serviceDetails22.getUniqueId(), getFollowedList)); + assertTrue(isElementInArray(serviceDetails33.getUniqueId(), getFollowedList)); + + return getFollowedList; + } + + // -------------------------------------T E S T + // S------------------------------------------------------// + + @Test + public void governorList_AllCertifiedVersionsOfService() throws Exception { + certifyAllServices(); + String serviceUniqueIdCertified1 = serviceDetails11.getUniqueId(); + RestResponse res = LifecycleRestUtils.changeServiceState(serviceDetails11, sdncDesignerDetails1, "1.0", + LifeCycleStatesEnum.CHECKOUT); + assertEquals(200, res.getErrorCode().intValue()); + + JSONArray getFollowedList = getFollowedListAsJsonArray(governor); + assertFalse(getFollowedList.isEmpty()); + assertFalse(isElementInArray(serviceDetails11.getUniqueId(), getFollowedList)); + assertTrue(isElementInArray(serviceDetails22.getUniqueId(), getFollowedList)); + assertTrue(isElementInArray(serviceDetails33.getUniqueId(), getFollowedList)); + assertTrue(isElementInArray(serviceUniqueIdCertified1, getFollowedList)); + assertEquals(3, getFollowedList.size()); + + // certifyService(serviceDetails11, "1.1"); + LifecycleRestUtils.certifyService(serviceDetails11); + + JSONArray governorFollowedList2 = checkFollowed(governor); + assertEquals(4, governorFollowedList2.size()); + assertTrue(isElementInArray(serviceDetails11.getUniqueId(), governorFollowedList2)); + assertTrue(isElementInArray(serviceUniqueIdCertified1, governorFollowedList2)); + + } + + // -------------------------------------T E S T + // S------------------------------------------------------// + + @Test + public void governorList_distributionNotApproved() throws Exception { + certifyAllServices(); + + JSONArray checkFollowed = checkFollowed(governor); + assertEquals(3, checkFollowed.size()); + } + + @Test + public void governorGetEmptyListTest_notCertifiedServices() throws Exception { + JSONArray governorFollowedList = getFollowedListAsJsonArray(governor); + + assertTrue(governorFollowedList.isEmpty()); + } + + @Test + public void governorList_distributionApproved() throws Exception { + certifyAllServices(); + boolean approved = true; + changeDistributionStatusOfAllService(approved, governor); + + JSONArray checkFollowed = checkFollowed(governor); + assertEquals(3, checkFollowed.size()); + } + + @Test(enabled = false) + public void governorList_distributed() throws Exception { + certifyAllServices(); + + LifecycleRestUtils.changeDistributionStatus(serviceDetails11, "1.0", governor, userRemarks, + DistributionStatusEnum.DISTRIBUTED); + LifecycleRestUtils.changeDistributionStatus(serviceDetails22, "1.0", governor, userRemarks, + DistributionStatusEnum.DISTRIBUTED); + LifecycleRestUtils.changeDistributionStatus(serviceDetails33, "1.0", governor, userRemarks, + DistributionStatusEnum.DISTRIBUTED); + + JSONArray governorFollowedList = getFollowedListAsJsonArray(governor); + assertFalse(governorFollowedList.isEmpty()); + assertTrue(isElementInArray(serviceDetails11.getUniqueId(), governorFollowedList)); + assertTrue(isElementInArray(serviceDetails22.getUniqueId(), governorFollowedList)); + assertTrue(isElementInArray(serviceDetails33.getUniqueId(), governorFollowedList)); + } + + @Test + public void governorList_distributionRejected() throws Exception { + certifyAllServices(); + boolean distributionRejected = false; + changeDistributionStatusOfAllService(distributionRejected, governor); + + JSONArray checkFollowed = checkFollowed(governor); + assertEquals(3, checkFollowed.size()); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/executeOnUGN/distributionClient/ClientConfiguration.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/executeOnUGN/distributionClient/ClientConfiguration.java new file mode 100644 index 0000000000..c80f6c612d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/executeOnUGN/distributionClient/ClientConfiguration.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.executeOnUGN.distributionClient; + +import java.util.ArrayList; +import java.util.List; + +public class ClientConfiguration { + + private String asdcAddress; + private String user; + private String password; + private Integer pollingInterval; + private Integer pollingTimeout; + private List relevantArtifactTypes; + private String consumerGroup; + private String environmentName; + private String consumerID; + + public ClientConfiguration() { + + super(); + + this.asdcAddress = "localhost:8443"; + this.consumerID = "mso-123456"; + this.consumerGroup = "mso-group"; + this.environmentName = "PROD"; + this.password = "password"; + this.pollingInterval = 20; + this.pollingTimeout = 20; + this.relevantArtifactTypes = new ArrayList(); + this.relevantArtifactTypes.add("SHELL"); + this.user = "mso-user"; + } + + public String getAsdcAddress() { + return asdcAddress; + } + + public void setAsdcAddress(String asdcAddress) { + this.asdcAddress = asdcAddress; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public int getPollingInterval() { + return pollingInterval; + } + + public void setPollingInterval(Integer pollingInterval) { + this.pollingInterval = pollingInterval; + } + + public int getPollingTimeout() { + return pollingTimeout; + } + + public void setPollingTimeout(Integer pollingTimeout) { + this.pollingTimeout = pollingTimeout; + } + + public List getRelevantArtifactTypes() { + return relevantArtifactTypes; + } + + public void setRelevantArtifactTypes(List relevantArtifactTypes) { + this.relevantArtifactTypes = relevantArtifactTypes; + } + + public String getConsumerGroup() { + return consumerGroup; + } + + public void setConsumerGroup(String consumerGroup) { + this.consumerGroup = consumerGroup; + } + + public String getEnvironmentName() { + return environmentName; + } + + public void setEnvironmentName(String environmentName) { + this.environmentName = environmentName; + } + + public String getComsumerID() { + return consumerID; + } + + public void setComsumerID(String comsumerID) { + this.consumerID = comsumerID; + } + + public ClientConfiguration(String asdcAddress, String user, String password, Integer pollingInterval, + Integer pollingTimeout, List relevantArtifactTypes, String consumerGroup, String environmentName, + String comsumerID) { + super(); + this.asdcAddress = asdcAddress; + this.user = user; + this.password = password; + this.pollingInterval = pollingInterval; + this.pollingTimeout = pollingTimeout; + this.relevantArtifactTypes = relevantArtifactTypes; + this.consumerGroup = consumerGroup; + this.environmentName = environmentName; + this.consumerID = comsumerID; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/ComplexResourceBaseTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/ComplexResourceBaseTest.java new file mode 100644 index 0000000000..14c7a37101 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/ComplexResourceBaseTest.java @@ -0,0 +1,177 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.preRequisites; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.lifecycle.LCSbaseTest; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.annotations.BeforeMethod; + +public class ComplexResourceBaseTest extends ComponentBaseTest { + + protected ServiceReqDetails serviceDetails; + protected ResourceReqDetails resourceDetailsVFC; + protected ResourceReqDetails resourceDetailsVL; + protected ResourceReqDetails resourceDetailsVF; + protected ResourceReqDetails resourceDetailsCP; + protected ComponentInstanceReqDetails resourceInstanceReqDetailsVF; + protected ComponentInstanceReqDetails resourceInstanceReqDetailsVFC; + protected ComponentInstanceReqDetails resourceInstanceReqDetailsVL; + protected ComponentInstanceReqDetails resourceInstanceReqDetailsCP; + protected User sdncDesignerDetails1; + protected User sdncTesterDeatails1; + protected User sdncAdminDetails1; + protected ArtifactReqDetails heatArtifactDetails; + + protected ArtifactReqDetails defaultArtifactDetails; + protected int maxLength = 50; + protected Resource resourceVF = null; + + @Rule + public static TestName name = new TestName(); + + public ComplexResourceBaseTest() { + super(name, ComplexResourceBaseTest.class.getName()); + } + + @BeforeMethod + public void before() throws Exception { + + initializeMembers(); + + createComponents(); + + } + + public void initializeMembers() throws IOException, Exception { + + serviceDetails = ElementFactory.getDefaultService(); + resourceDetailsVFC = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VFC, "resourceVFC"); + resourceDetailsVF = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, "resourceVF3"); + resourceDetailsVL = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VL, "resourceVL"); + resourceDetailsCP = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.CP, "resourceCP"); + sdncDesignerDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncTesterDeatails1 = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + sdncAdminDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + + } + + protected void createComponents() throws Exception { + + RestResponse response = ServiceRestUtils.createService(serviceDetails, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("service uniqueId is null:", serviceDetails.getUniqueId()); + + response = ResourceRestUtils.createResource(resourceDetailsVFC, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("resource uniqueId is null:", resourceDetailsVFC.getUniqueId()); + response = LifecycleRestUtils.changeResourceState(resourceDetailsVFC, sdncDesignerDetails1, + resourceDetailsVFC.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertTrue("change LS state to CHECKIN, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + response = ResourceRestUtils.createResource(resourceDetailsVF, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("resource uniqueId is null:", resourceDetailsVF.getUniqueId()); + + response = ResourceRestUtils.createResource(resourceDetailsCP, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("resource uniqueId is null:", resourceDetailsCP.getUniqueId()); + response = LifecycleRestUtils.changeResourceState(resourceDetailsCP, sdncDesignerDetails1, + resourceDetailsCP.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertTrue("change LS state to CHECKIN, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + response = ResourceRestUtils.createResource(resourceDetailsVL, sdncDesignerDetails1); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + assertNotNull("resource uniqueId is null:", resourceDetailsVL.getUniqueId()); + response = LifecycleRestUtils.changeResourceState(resourceDetailsVL, sdncDesignerDetails1, + resourceDetailsVL.getVersion(), LifeCycleStatesEnum.CHECKIN); + assertTrue("change LS state to CHECKIN, returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + resourceInstanceReqDetailsVFC = ElementFactory.getDefaultComponentInstance("VFC", resourceDetailsVFC); + resourceInstanceReqDetailsVF = ElementFactory.getDefaultComponentInstance("VF", resourceDetailsVF); + resourceInstanceReqDetailsVL = ElementFactory.getDefaultComponentInstance("VL", resourceDetailsVL); + resourceInstanceReqDetailsCP = ElementFactory.getDefaultComponentInstance("CP", resourceDetailsCP); + + } + + protected void createVFWithCertifiedResourceInstance(ResourceReqDetails resourceDetails, + ComponentInstanceReqDetails resourceInstanceReqDetails) throws Exception { + + RestResponse response = LifecycleRestUtils.changeResourceState(resourceDetails, sdncDesignerDetails1, + resourceDetails.getVersion(), LifeCycleStatesEnum.CHECKOUT); + assertEquals("Check response code after CHECKOUT", 200, response.getErrorCode().intValue()); + + // add heat artifact to resource and certify + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncDesignerDetails1, + resourceDetails.getUniqueId()); + assertTrue("add HEAT artifact to resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + response = LCSbaseTest.certifyResource(resourceDetails, sdncDesignerDetails1); + assertEquals("Check response code after CERTIFY request", 200, response.getErrorCode().intValue()); + + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + + resourceInstanceReqDetails.setComponentUid(resourceDetails.getUniqueId()); + response = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, sdncDesignerDetails1, + resourceVF); + assertEquals("Check response code after create RI", 201, response.getErrorCode().intValue()); + + resourceVF = convertResourceGetResponseToJavaObject(resourceDetailsVF); + } + + protected Resource convertResourceGetResponseToJavaObject(ResourceReqDetails resourceDetails) throws IOException { + RestResponse response = ResourceRestUtils.getResource(resourceDetails, sdncDesignerDetails1); + assertEquals("Check response code after get resource", 200, response.getErrorCode().intValue()); + return ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/DownloadArtifactBaseTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/DownloadArtifactBaseTest.java new file mode 100644 index 0000000000..bde68528bf --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/DownloadArtifactBaseTest.java @@ -0,0 +1,125 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.preRequisites; + +import java.io.IOException; + +import org.apache.log4j.lf5.util.ResourceUtils; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.lifecycle.LCSbaseTest; +import org.openecomp.sdc.ci.tests.utils.ArtifactUtils; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; + +public class DownloadArtifactBaseTest extends ComponentBaseTest { + + protected ResourceReqDetails downloadResourceDetails; + protected ServiceReqDetails serviceDetails; + protected ComponentInstanceReqDetails resourceInstanceReqDetails; + protected User sdncUserDetails; + protected User sdncDesignerDetails1; + protected ArtifactReqDetails heatArtifactDetails; + + protected ArtifactReqDetails defaultArtifactDetails; + protected ResourceUtils resourceUtils; + protected ArtifactUtils artifactUtils; + protected Service service; + + public DownloadArtifactBaseTest(TestName testName, String className) { + super(testName, className); + } + + @BeforeMethod + public void before() throws Exception { + + initializeMembers(); + createComponents(); + + } + + public void initializeMembers() throws IOException, Exception { + downloadResourceDetails = ElementFactory.getDefaultResource(); + serviceDetails = ElementFactory.getDefaultService(); + sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + sdncDesignerDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + heatArtifactDetails = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + resourceInstanceReqDetails = ElementFactory.getDefaultComponentInstance(); + + } + + protected void createComponents() throws Exception { + + RestResponse response = ResourceRestUtils.createResource(downloadResourceDetails, sdncUserDetails); + AssertJUnit.assertTrue("create request returned status:" + response.getErrorCode(), + response.getErrorCode() == 201); + AssertJUnit.assertNotNull("resource uniqueId is null:", downloadResourceDetails.getUniqueId()); + + ArtifactReqDetails heatArtifactDetails = ElementFactory + .getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + response = ArtifactRestUtils.addInformationalArtifactToResource(heatArtifactDetails, sdncUserDetails, + downloadResourceDetails.getUniqueId()); + AssertJUnit.assertTrue("add HEAT artifact to resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + // certified resource + response = LCSbaseTest.certifyResource(downloadResourceDetails, sdncDesignerDetails1); + AssertJUnit.assertTrue("certify resource request returned status:" + response.getErrorCode(), + response.getErrorCode() == 200); + + response = ServiceRestUtils.createService(serviceDetails, sdncUserDetails); + AssertJUnit.assertTrue("create request returned status:" + response.getErrorCode(), + response.getErrorCode() == 201); + AssertJUnit.assertNotNull("service uniqueId is null:", serviceDetails.getUniqueId()); + + // add resource instance with HEAT deployment artifact to the service + resourceInstanceReqDetails.setComponentUid(downloadResourceDetails.getUniqueId()); + response = ComponentInstanceRestUtils.createComponentInstance(resourceInstanceReqDetails, sdncUserDetails, + serviceDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + AssertJUnit.assertTrue("response code is not 201, returned: " + response.getErrorCode(), + response.getErrorCode() == 201); + + response = ServiceRestUtils.getService(serviceDetails, sdncUserDetails); + AssertJUnit.assertTrue("response code is not 200, returned: " + response.getErrorCode(), + response.getErrorCode() == 200); + service = ResponseParser.convertServiceResponseToJavaObject(response.getResponse()); + + DbUtils.cleanAllAudits(); + + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/SimpleOneRsrcOneServiceTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/SimpleOneRsrcOneServiceTest.java new file mode 100644 index 0000000000..add06a587c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/preRequisites/SimpleOneRsrcOneServiceTest.java @@ -0,0 +1,96 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.preRequisites; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; + +import org.apache.log4j.lf5.util.ResourceUtils; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.ArtifactUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.annotations.BeforeMethod; + +public abstract class SimpleOneRsrcOneServiceTest extends ComponentBaseTest { + + protected ResourceReqDetails resourceDetails; + protected ServiceReqDetails serviceDetails; + protected ComponentInstanceReqDetails resourceInstanceReqDetails; + protected ArtifactReqDetails heatArtifactDetails1; + + private static final String heatExtension = "yaml"; + private static final String yangXmlExtension = "xml"; + private static final String muranoPkgExtension = "zip"; + private static final String extension = null; + private final String folderName = "heatEnv"; + + protected User sdncDesignerDetails; + protected ArtifactReqDetails defaultArtifactDetails; + protected ResourceUtils resourceUtils; + protected ArtifactUtils artifactUtils; + protected Utils utils; + + private static RestResponse createServiceResponse; + + public SimpleOneRsrcOneServiceTest(TestName testName, String className) { + super(testName, className); + } + + @BeforeMethod + public void before() throws Exception { + + initializeMembers(); + createComponents(); + + } + + public void initializeMembers() throws IOException, Exception { + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + resourceDetails = ElementFactory.getDefaultResource(); + serviceDetails = ElementFactory.getDefaultService(); + heatArtifactDetails1 = ElementFactory.getDefaultDeploymentArtifactForType(ArtifactTypeEnum.HEAT.getType()); + resourceInstanceReqDetails = ElementFactory.getDefaultComponentInstance("resourceInstanceReqDetails"); + } + + protected void createComponents() throws Exception { + + RestResponse response = ResourceRestUtils.createResource(resourceDetails, sdncDesignerDetails); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + + response = ServiceRestUtils.createService(serviceDetails, sdncDesignerDetails); + assertTrue("create request returned status:" + response.getErrorCode(), response.getErrorCode() == 201); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/rules/MyTestWatcher.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/rules/MyTestWatcher.java new file mode 100644 index 0000000000..bb2d2d579b --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/rules/MyTestWatcher.java @@ -0,0 +1,82 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.rules; + +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; +import org.openecomp.sdc.ci.tests.api.AttSdcTest; + +public class MyTestWatcher extends TestWatcher { + + AttSdcTest odlTest; + + public MyTestWatcher(AttSdcTest odlTest) { + this.odlTest = odlTest; + } + + /** + * Invoked when a test succeeds + * + * @param description + */ + @Override + protected void succeeded(Description description) { + String testName = description.getMethodName(); + odlTest.addTestSummary(testName, true); + + } + + /** + * Invoked when a test fails + * + * @param e + * @param description + */ + @Override + protected void failed(Throwable e, Description description) { + String testName = description.getMethodName(); + odlTest.addTestSummary(testName, false, e); + } + + /** + * Invoked when a test is about to start + * + * @param description + */ + @Override + protected void starting(Description description) { + // System.out.println("protected void starting(Description description) + // {"); + this.odlTest.getLogger().debug("Start running test {}", description.getMethodName()); + } + + /** + * Invoked when a test method finishes (whether passing or failing) + * + * @param description + */ + @Override + protected void finished(Description description) { + // System.out.println("protected void finished(Description description) + // {"); + this.odlTest.getLogger().debug("Finish running test {}", description.getMethodName()); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/run/StartTest.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/run/StartTest.java new file mode 100644 index 0000000000..9bb14d7f50 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/run/StartTest.java @@ -0,0 +1,279 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.run; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.utils.Utils; +//import org.junit.runner.JUnitCore; +//import org.junit.runner.Result; +//import org.junit.runner.notification.Failure; +import org.testng.TestListenerAdapter; +import org.testng.TestNG; +import org.testng.reporters.TestHTMLReporter; +import org.testng.xml.XmlSuite; + +public class StartTest { + + // private List> testClasses = new + // ArrayList>(); + public static long timeOfTest = 0; + + public static boolean debug = false; + + public static AtomicBoolean loggerInitialized = new AtomicBoolean(false); + + protected static Logger logger = null; + + public static void main(String[] args) { + + String debugEnabled = System.getProperty("debug"); + if (debugEnabled != null && debugEnabled.equalsIgnoreCase("true")) { + debug = true; + } + System.out.println("Debug mode is " + (debug ? "enabled" : "disabled")); + + enableLogger(); + + Config config = null; + try { + config = Utils.getConfig(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (config == null) { + logger.error("Failed to configuration file of ci tests."); + System.exit(1); + } + + TestNG testng = new TestNG(); + + List suites = new ArrayList(); + suites.add("testSuites/" + args[0]); + testng.setTestSuites(suites); + testng.setUseDefaultListeners(true); + testng.setOutputDirectory("target/"); + + testng.run(); + + } + + public StartTest() { + logger = Logger.getLogger(StartTest.class.getName()); + } + + public static void enableLogger() { + + if (false == loggerInitialized.get()) { + + loggerInitialized.set(true); + + String log4jPropsFile = System.getProperty("log4j.configuration"); + if (System.getProperty("os.name").contains("Windows")) { + String logProps = "src/main/resources/ci/conf/log4j.properties"; + if (log4jPropsFile == null) { + System.setProperty("targetlog", "target/"); + log4jPropsFile = logProps; + } + + } + PropertyConfigurator.configureAndWatch(log4jPropsFile); + + } + } + + private List getClassesForPackage(String pkgname) { + + List classes = new ArrayList(); + + // Get a File object for the package + File directory = null; + String fullPath; + String relPath = pkgname.replace('.', '/'); + + // System.out.println("ClassDiscovery: Package: " + pkgname + + // " becomes Path:" + relPath); + + URL resource = ClassLoader.getSystemClassLoader().getResource(relPath); + + // System.out.println("ClassDiscovery: Resource = " + resource); + if (resource == null) { + throw new RuntimeException("No resource for " + relPath); + } + fullPath = resource.getFile(); + // System.out.println("ClassDiscovery: FullPath = " + resource); + + if (debug) { + System.out.println("fullPath is " + fullPath); + } + + try { + directory = new File(resource.toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException( + pkgname + " (" + resource + + ") does not appear to be a valid URL / URI. Strange, since we got it from the system...", + e); + } catch (IllegalArgumentException e) { + directory = null; + } + // System.out.println("ClassDiscovery: Directory = " + directory); + + if (directory != null && directory.exists()) { + + // Get the list of the files contained in the package + String[] files = directory.list(); + for (int i = 0; i < files.length; i++) { + + // we are only interested in .class files + if (files[i].endsWith(".class") && false == files[i].contains("$")) { + + // removes the .class extension + String className = pkgname + '.' + files[i].substring(0, files[i].length() - 6); + + // System.out.println("ClassDiscovery: className = " + + // className); + + if (debug) { + System.out.println("ClassDiscovery: className = " + className); + } + + try { + Class clas = Class.forName(className); + boolean isAddToRun = false; + Method[] methods = clas.getMethods(); + for (Method method : methods) { + Annotation[] anns = method.getAnnotations(); + for (Annotation an : anns) { + if (an.annotationType().getSimpleName().equalsIgnoreCase("Test")) { + isAddToRun = true; + break; + } + } + } + if (isAddToRun) + classes.add(clas); + } catch (ClassNotFoundException e) { + throw new RuntimeException("ClassNotFoundException loading " + className); + } + } + } + } else { + try { + String jarPath = fullPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", ""); + + if (debug) { + System.out.println("jarPath is " + jarPath); + } + + JarFile jarFile = new JarFile(jarPath); + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String entryName = entry.getName(); + if (entryName.startsWith(relPath) && entryName.length() > (relPath.length() + "/".length())) { + + // System.out.println("ClassDiscovery: JarEntry: " + + // entryName); + String className = entryName.replace('/', '.').replace('\\', '.').replace(".class", ""); + + // System.out.println("ClassDiscovery: className = " + + // className); + + if (false == className.contains("$")) { + + if (debug) { + System.out.println("ClassDiscovery: className = " + className); + } + + try { + Class clas = Class.forName(className); + boolean isAddToRun = false; + Method[] methods = clas.getMethods(); + for (Method method : methods) { + Annotation[] anns = method.getAnnotations(); + for (Annotation an : anns) { + if (an.annotationType().getSimpleName().equalsIgnoreCase("Test")) { + isAddToRun = true; + break; + } + } + } + if (isAddToRun) + classes.add(clas); + } catch (ClassNotFoundException e) { + throw new RuntimeException("ClassNotFoundException loading " + className); + } + } + } + } + jarFile.close(); + + } catch (IOException e) { + throw new RuntimeException(pkgname + " (" + directory + ") does not appear to be a valid package", e); + } + } + return classes; + } + + private void addTableHead(StringBuilder results) { + results.append("
"); + results.append(""); + results.append(""); + results.append(""); + } + + // private void addUnitTestResult(StringBuilder results, + // Class testClass, Result unitTestResult) { + // + // boolean isSuccess = unitTestResult.wasSuccessful(); + // + // String result = (isSuccess) ? "success" : "fail"; + // String fileName = FileUtils.getFileName(testClass.getName()); + // results.append(""); + // // + // results.append(""); + // results.append(""); + // results.append(""); + // results.append(""); + // } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/run/StartTest2backup.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/run/StartTest2backup.java new file mode 100644 index 0000000000..d5b06b396f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/run/StartTest2backup.java @@ -0,0 +1,408 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.run; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.apache.log4j.PropertyConfigurator; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.openecomp.sdc.ci.tests.api.AttSdcTest; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StartTest2backup { + + private List> testClasses = new ArrayList>(); + public static long timeOfTest = 0; + + public static boolean debug = false; + + public static AtomicBoolean loggerInitialized = new AtomicBoolean(false); + + protected static Logger logger = null; + + public static void main(String[] args) { + + String debugEnabled = System.getProperty("debug"); + if (debugEnabled != null && debugEnabled.equalsIgnoreCase("true")) { + debug = true; + } + System.out.println("Debug mode is " + (debug ? "enabled" : "disabled")); + + enableLogger(); + + Config config = null; + try { + config = Utils.getConfig(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (config == null) { + logger.error("Failed to configuration file of ci tests."); + System.exit(1); + } + + List packagesToRun = config.getPackages(); + if (packagesToRun == null || true == packagesToRun.isEmpty()) { + logger.error("No package was configured to be executed."); + System.exit(2); + } + StartTest2backup tests = new StartTest2backup(); + + boolean stopOnClassFailure = false; + String stopOnClassFailureStr = System.getProperty("stopOnClassFailure"); + if (stopOnClassFailureStr != null && stopOnClassFailureStr.equalsIgnoreCase("true")) { + stopOnClassFailure = true; + } else { + Boolean stopOnClassFailureObj = config.isStopOnClassFailure(); + if (stopOnClassFailureObj != null) { + stopOnClassFailure = stopOnClassFailureObj.booleanValue(); + } + } + + tests.start(packagesToRun, stopOnClassFailure); + } + + public StartTest2backup() { + logger = LoggerFactory.getLogger(StartTest2backup.class.getName()); + } + + public static void enableLogger() { + + if (false == loggerInitialized.get()) { + + loggerInitialized.set(true); + + String log4jPropsFile = System.getProperty("log4j.configuration"); + if (System.getProperty("os.name").contains("Windows")) { + String logProps = "src/main/resources/ci/conf/log4j.properties"; + if (log4jPropsFile == null) { + System.setProperty("targetlog", "target/"); + log4jPropsFile = logProps; + } + + } + PropertyConfigurator.configureAndWatch(log4jPropsFile); + + } + } + + public void start(List packages, boolean exitOnFailure) { + + boolean success = true; + StringBuilder results = new StringBuilder(); + Result result; + + if (packages == null) { + return; + } + + for (String packageName : packages) { + // List classesForPackage = + // getClassesForPackage("org.openecomp.sdc.ci.tests.execute"); + List classesForPackage = getClassesForPackage(packageName); + if (classesForPackage != null && false == classesForPackage.isEmpty()) { + for (Class testUnit : classesForPackage) { + testClasses.add(testUnit); + } + } + } + + System.out.println(testClasses); + + // tsetClasses.add(LogValidatorTest.class); + // tsetClasses.add(AttNorthboundTest.class); + + results.append( + ""); + + Calendar calendar = Calendar.getInstance(); + timeOfTest = calendar.getTimeInMillis(); + SimpleDateFormat date_format = new SimpleDateFormat("MMM dd yyyy HH:mm:ss"); + results.append("

This report generated on " + date_format.format(calendar.getTime()) + "


"); + + results.append("
").append(testName).append("").append(result).append("").append(message).append("").append(convertExceptionToString(exception)).append(""); + + doc.append(""); + doc.append("
"); + + doc.append(convertExceptionToString(exception)); + + doc.append("
"); + doc.append("
").append("Unit Test").append("").append("Result").append("
").append(FileUtils.getFileName(testClass.getName())).append("") + // .append("" + // + fileName + "").append("").append(result) + // .append("
"); + addTableHead(results); + + int size = testClasses.size(); + int index = 0; + + int totalRunTests = 0; + int totalFailureTests = 0; + int totalIgnoreTests = 0; + int numOfFailureClasses = 0; + for (Class testClass : testClasses) { + + index++; + + StringBuilder builder = new StringBuilder(); + String str = "***************************************************************************"; + builder.append(str + "\n"); + String current = "class " + index + "/" + size + " failure(" + numOfFailureClasses + ") + RUNS(" + + totalRunTests + ")" + " FAILURES(" + totalFailureTests + ") IGNORED(" + totalIgnoreTests + ")"; + int interval = ((str.length() - current.length() - 2) / 2); + String substring = str.substring(0, interval); + builder.append(substring + " " + current + " " + substring + "\n"); + builder.append(str + "\n"); + + System.out.println(builder.toString()); + + logger.debug(builder.toString()); + logger.debug("Going to run test class {}", testClass.getName()); + + result = JUnitCore.runClasses(testClass); + if (result.wasSuccessful() == false) { + numOfFailureClasses++; + } + logger.debug("Test class {} finished {}",testClass.getName(),(result.wasSuccessful() ? "OK." : " WITH ERROR.")); + List failures = result.getFailures(); + if (failures != null) { + for (Failure failure : failures) { + logger.error("Test class {} failure test {}-{}",testClass.getName(),failure.getTestHeader(),failure.getTrace()); + } + } + int runsPerClass = result.getRunCount(); + int failuresPerClass = result.getFailureCount(); + int ignoredPerClass = result.getIgnoreCount(); + + totalRunTests += runsPerClass; + totalFailureTests += failuresPerClass; + totalIgnoreTests += ignoredPerClass; + + logger.debug("class {} Failed tests {} %",testClass.getName(),(failuresPerClass * 1.0) / runsPerClass * 100); + logger.debug("class {} Ignored tests {} %",testClass.getName(),(ignoredPerClass * 1.0) / runsPerClass * 100); + + // List failures = result.getFailures(); + // if (failures != null) { + // for (Failure failure : failures) { + // System.err.println("9999999999" + failure.getTestHeader()); + // } + // } + + addUnitTestResult(results, testClass, result); + success &= result.wasSuccessful(); + + if (numOfFailureClasses > 0) { + // if (exitOnFailure) { + if (exitOnFailure) { + break; + } + } + } + + results.append("
"); + results.append("

Tests Summary:


"); + results.append("Total Runs : " + totalRunTests + "
"); + results.append("Total Failure : " + totalFailureTests + "
"); + results.append("Total: " + totalFailureTests + "/" + totalRunTests + "
"); + results.append(""); + + FileUtils.writeToFile(Config.instance().getOutputFolder() + File.separator + Config.instance().getReportName(), + results.toString()); + + if (!success) { + System.out.println("FAILURE"); + logger.error("Failure tests : {} %",((totalFailureTests + totalIgnoreTests) * 1.0) / (totalRunTests + totalIgnoreTests)); + logger.error("Ignored tests : {} %",(totalIgnoreTests * 1.0) / (totalRunTests + totalIgnoreTests)); + System.exit(1); + } + + System.out.println("SUCCESS"); + } + + private List getClassesForPackage(String pkgname) { + + List classes = new ArrayList(); + + // Get a File object for the package + File directory = null; + String fullPath; + String relPath = pkgname.replace('.', '/'); + + // System.out.println("ClassDiscovery: Package: " + pkgname + + // " becomes Path:" + relPath); + + URL resource = ClassLoader.getSystemClassLoader().getResource(relPath); + + // System.out.println("ClassDiscovery: Resource = " + resource); + if (resource == null) { + throw new RuntimeException("No resource for " + relPath); + } + fullPath = resource.getFile(); + // System.out.println("ClassDiscovery: FullPath = " + resource); + + if (debug) { + System.out.println("fullPath is " + fullPath); + } + + try { + directory = new File(resource.toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException( + pkgname + " (" + resource + + ") does not appear to be a valid URL / URI. Strange, since we got it from the system...", + e); + } catch (IllegalArgumentException e) { + directory = null; + } + // System.out.println("ClassDiscovery: Directory = " + directory); + + if (directory != null && directory.exists()) { + + // Get the list of the files contained in the package + String[] files = directory.list(); + for (int i = 0; i < files.length; i++) { + + // we are only interested in .class files + if (files[i].endsWith(".class") && false == files[i].contains("$")) { + + // removes the .class extension + String className = pkgname + '.' + files[i].substring(0, files[i].length() - 6); + + // System.out.println("ClassDiscovery: className = " + + // className); + + if (debug) { + System.out.println("ClassDiscovery: className = " + className); + } + + try { + Class clas = Class.forName(className); + boolean isAddToRun = false; + Method[] methods = clas.getMethods(); + for (Method method : methods) { + Annotation[] anns = method.getAnnotations(); + for (Annotation an : anns) { + if (an.annotationType().getSimpleName().equalsIgnoreCase("Test")) { + isAddToRun = true; + break; + } + } + } + if (isAddToRun) + classes.add(clas); + } catch (ClassNotFoundException e) { + throw new RuntimeException("ClassNotFoundException loading " + className); + } + } + } + } else { + try { + String jarPath = fullPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", ""); + + if (debug) { + System.out.println("jarPath is " + jarPath); + } + + JarFile jarFile = new JarFile(jarPath); + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String entryName = entry.getName(); + if (entryName.startsWith(relPath) && entryName.length() > (relPath.length() + "/".length())) { + + // System.out.println("ClassDiscovery: JarEntry: " + + // entryName); + String className = entryName.replace('/', '.').replace('\\', '.').replace(".class", ""); + + // System.out.println("ClassDiscovery: className = " + + // className); + + if (false == className.contains("$")) { + + if (debug) { + System.out.println("ClassDiscovery: className = " + className); + } + + try { + Class clas = Class.forName(className); + boolean isAddToRun = false; + Method[] methods = clas.getMethods(); + for (Method method : methods) { + Annotation[] anns = method.getAnnotations(); + for (Annotation an : anns) { + if (an.annotationType().getSimpleName().equalsIgnoreCase("Test")) { + isAddToRun = true; + break; + } + } + } + if (isAddToRun) + classes.add(clas); + } catch (ClassNotFoundException e) { + throw new RuntimeException("ClassNotFoundException loading " + className); + } + } + } + } + jarFile.close(); + + } catch (IOException e) { + throw new RuntimeException(pkgname + " (" + directory + ") does not appear to be a valid package", e); + } + } + return classes; + } + + private void addTableHead(StringBuilder results) { + results.append(""); + results.append("").append("Unit Test").append(""); + results.append("").append("Result").append(""); + results.append(""); + } + + private void addUnitTestResult(StringBuilder results, Class testClass, + Result unitTestResult) { + + boolean isSuccess = unitTestResult.wasSuccessful(); + + String result = (isSuccess) ? "success" : "fail"; + String fileName = FileUtils.getFileName(testClass.getName()); + results.append(""); + // results.append("").append(FileUtils.getFileName(testClass.getName())).append(""); + results.append("") + .append("" + fileName + "").append(""); + results.append("").append(result).append(""); + results.append(""); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/sanity/CrudE2E.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/sanity/CrudE2E.java new file mode 100644 index 0000000000..b676b29bda --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/sanity/CrudE2E.java @@ -0,0 +1,287 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.sanity; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.Pair; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.AssocType; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.Test; + +import fj.data.Either; + +public class CrudE2E extends ComponentBaseTest { + private static Logger log = LoggerFactory.getLogger(CrudE2E.class.getName()); + + public Component resourceDetailsVFCcomp_01; + public Component resourceDetailsVFCsoft_01; + public Component resourceDetailsCP_01; + public Component resourceDetailsVL_01; + public Component resourceDetailsVF_01; + public Component resourceDetailsVF_02; + + public ComponentInstance resourceDetailsVFC1compIns1; + public ComponentInstance resourceDetailsVFC1softIns1; + public ComponentInstance resourceDetailsCP1ins_01; + public ComponentInstance resourceDetailsVL1ins_01; + public ComponentInstance resourceDetailsVF1ins_01; + public Component defaultService1; + private List variablesAsList = new ArrayList(); + + @Rule + public static TestName name = new TestName(); + + public CrudE2E() { + super(name, CrudE2E.class.getName()); + } + + @Test + public void complexScenario() throws Exception { + + User designer = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + //////// create defaultService1 /////////////////////// + + Either createDefaultService1e = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + defaultService1 = createDefaultService1e.left().value(); + + //////// create VFC1 (resourceDetailsVFCcomp_01) DerivedFrom COMPUTE + //////// type add all possible informational artifacts and change state + //////// to CERTIFY//////// + Either resourceDetailsVFCcompE = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.COMPUTE, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, + true); + resourceDetailsVFCcomp_01 = resourceDetailsVFCcompE.left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.CHEF, resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.PUPPET, resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, false, true); + // AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.SHELL_SCRIPT, + // resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.YANG, resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.YANG_XML, resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, false, true); + // AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, + // resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.DG_XML, resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.MURANO_PKG, resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.changeComponentState(resourceDetailsVFCcomp_01, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + + //////// create VFC2 (resourceDetailsVFCsoft_01) DerivedFrom SOFTWARE + //////// type and change state to CERTIFY//////// + Either resourceDetailsVFCsoftE = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.SOFTWARE_COMPONENT, ResourceCategoryEnum.GENERIC_DATABASE, UserRoleEnum.DESIGNER, + true); + resourceDetailsVFCsoft_01 = resourceDetailsVFCsoftE.left().value(); + AtomicOperationUtils.changeComponentState(resourceDetailsVFCsoft_01, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + + //////// create CP1 (resourceDetailsVFCsoft_01) DerivedFrom PORT type + //////// and change state to CHECKIN//////// + Either resourceDetailsCP_01e = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.CP, NormativeTypesEnum.PORT, ResourceCategoryEnum.GENERIC_DATABASE, UserRoleEnum.DESIGNER, true); + resourceDetailsCP_01 = resourceDetailsCP_01e.left().value(); + AtomicOperationUtils.changeComponentState(resourceDetailsCP_01, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + + //////// create VL1 (resourceDetailsVFCsoft_01) DerivedFrom NETWORK type + //////// and change state to CERTIFY//////// + Either resourceDetailsVL_01e = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VL, NormativeTypesEnum.NETWORK, ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, UserRoleEnum.DESIGNER, + true); + resourceDetailsVL_01 = resourceDetailsVL_01e.left().value(); + AtomicOperationUtils.changeComponentState(resourceDetailsVL_01, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + + //////// create VF1 (resourceDetailsVFCcomp_01) DerivedFrom COMPUTE type + //////// add all possible deployment and informational artifacts + //////// ////////// + Either resourceDetailsVF_01e = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + resourceDetailsVF_01 = resourceDetailsVF_01e.left().value(); + ArtifactDefinition heatArtifact = AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT_VOL, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT_NET, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true, true); + + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.CHEF, resourceDetailsVF_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.PUPPET, resourceDetailsVF_01, UserRoleEnum.DESIGNER, false, true); + // AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.SHELL_SCRIPT, + // resourceDetailsVF_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.YANG, resourceDetailsVF_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.YANG_XML, resourceDetailsVF_01, UserRoleEnum.DESIGNER, false, true); + // AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.HEAT, + // resourceDetailsVF_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.DG_XML, resourceDetailsVF_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.MURANO_PKG, resourceDetailsVF_01, UserRoleEnum.DESIGNER, false, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, resourceDetailsVF_01, UserRoleEnum.DESIGNER, false, true); + + //////// Add VFC1 VFC2 CP and VL to VF container ///////////// + resourceDetailsVFC1compIns1 = AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVFCcomp_01, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true).left().value(); + resourceDetailsVFC1softIns1 = AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVFCsoft_01, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true).left().value(); + resourceDetailsCP1ins_01 = AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsCP_01, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true).left().value(); + resourceDetailsVL1ins_01 = AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVL_01, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true).left().value(); + + //////// associate cp-vl vl-vfcComp and vfcComp-vfcSoft//////// + resourceDetailsVF_01 = AtomicOperationUtils.getResourceObject(resourceDetailsVF_01, UserRoleEnum.DESIGNER); + AtomicOperationUtils.associate2ResourceInstances(resourceDetailsVF_01, resourceDetailsCP1ins_01, resourceDetailsVL1ins_01, AssocType.LINKABLE.getAssocType(), UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.associate2ResourceInstances(resourceDetailsVF_01, resourceDetailsCP1ins_01, resourceDetailsVFC1compIns1, AssocType.BINDABLE.getAssocType(), UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.associate2ResourceInstances(resourceDetailsVF_01, resourceDetailsVFC1compIns1, resourceDetailsVFC1softIns1, AssocType.NODE.getAssocType(), UserRoleEnum.DESIGNER, true); + + //////// download all VF1 artifacts//////// + + Collection artifacts = resourceDetailsVF_01.getDeploymentArtifacts().values(); + List collect = artifacts.stream().filter(p -> p.checkEsIdExist() == true).map(p -> p.getUniqueId()).collect(Collectors.toList()); + artifacts.stream().filter(p -> p.checkEsIdExist() == true).map(p -> p.getUniqueId()).forEach(item -> log.debug(item)); + + //////// get all VF1 artifacts//////// + + Collection> componentInstancesProperties = resourceDetailsVF_01.getComponentInstancesProperties().values(); + List collect2 = componentInstancesProperties.stream().filter(p -> p.isEmpty() == false).flatMap(l -> l.stream()).collect(Collectors.toList()).stream().map(p -> p.getUniqueId()).collect(Collectors.toList()); + // PropertyRestUtils.updateProperty(resourceDetailsVF_01.getUniqueId(), + // propertyId, "1", designer); + // .forEach((someOtherString) -> { + // System.out.println("Content With Java: " + someOtherString); + // }); + // componentInstancesProperties.stream().filter(p -> + // p.isEmpty()==false).flatMap(l -> l.stream()).map(e -> + // e.getUniqueId()); + // resourceDetailsVF_01.getComponentInstancesProperties(). + + // ArtifactDefinition artifactDefinition = + // resourceDetailsVF_01.getDeploymentArtifacts().get(ArtifactTypeEnum.HEAT.getType().toLowerCase()).getEsId(); + // ArtifactDefinition artifactDefinition = + // resource.getDeploymentArtifacts().get(depResArtType); + // ArtifactReqDetails artifacJavaObject = + // ResponseParser.convertArtifactDefinitionToArtifactReqDetailsObject(artifactDefinition); + // ArtifactRestUtils.updateDeploymentArtifactToRI(artifactDetails, + // sdncModifierDetails, resourceInstanceId, serviceId) + + //////// certify VF1 - failed due to uncertified CP instance //////// + + RestResponse changeVfStateFailed = LifecycleRestUtils.changeComponentState(resourceDetailsVF_01, designer, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + Resource resResourceDetailsVF_01 = (Resource) resourceDetailsVF_01; + variablesAsList = Arrays.asList(resResourceDetailsVF_01.getResourceType().toString(), resourceDetailsCP_01.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.VALIDATED_RESOURCE_NOT_FOUND.name(), variablesAsList, changeVfStateFailed.getResponse()); + + //////// certify resources CP1 //////// + resourceDetailsCP_01 = AtomicOperationUtils.changeComponentState(resourceDetailsCP_01, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + //////// replace VF1 instances with new certified instances (CP1 + //////// replaced) //////// + Either, RestResponse> changeComponentInstanceVersion = AtomicOperationUtils.changeComponentInstanceVersion(resourceDetailsVF_01, resourceDetailsCP1ins_01, resourceDetailsCP_01, UserRoleEnum.DESIGNER, true); + resourceDetailsVF_01 = changeComponentInstanceVersion.left().value().getLeft(); + resourceDetailsCP1ins_01 = changeComponentInstanceVersion.left().value().getRight(); + + //////// associate cp-vl and cp-vfc1,//////// + AtomicOperationUtils.associate2ResourceInstances(resourceDetailsVF_01, resourceDetailsCP1ins_01, resourceDetailsVL1ins_01, AssocType.LINKABLE.getAssocType(), UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.associate2ResourceInstances(resourceDetailsVF_01, resourceDetailsCP1ins_01, resourceDetailsVFC1compIns1, AssocType.BINDABLE.getAssocType(), UserRoleEnum.DESIGNER, true); + + /////// change VF1 state to CHECK-IN and add it as instance to service1 + /////// container + resourceDetailsVF_01 = AtomicOperationUtils.changeComponentState(resourceDetailsVF_01, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resourceDetailsVF1ins_01 = AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceDetailsVF_01, defaultService1, UserRoleEnum.DESIGNER, true).left().value(); + + //////// distribute service1 - failed due to incorrect LifeCyclestatus + //////// //////// + RestResponse distributeService = AtomicOperationUtils.distributeService(defaultService1, false); + Assert.assertEquals(distributeService, null, "verification failed"); + + //////// certify service1 - failed due to uncertified instances //////// + designer = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + RestResponse changeServicetStateFailed = LifecycleRestUtils.changeComponentState(defaultService1, designer, LifeCycleStatesEnum.CERTIFICATIONREQUEST); + variablesAsList = Arrays.asList(defaultService1.getComponentType().toString().toLowerCase(), resourceDetailsVF_01.getName()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.VALIDATED_RESOURCE_NOT_FOUND.name(), variablesAsList, changeServicetStateFailed.getResponse()); + + ////// change VF1 state to CERTIFIED + resourceDetailsVF_01 = AtomicOperationUtils.changeComponentState(resourceDetailsVF_01, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + //////// replace VF1 instances with new certified instances //////// + changeComponentInstanceVersion = AtomicOperationUtils.changeComponentInstanceVersion(defaultService1, resourceDetailsVF1ins_01, resourceDetailsVF_01, UserRoleEnum.DESIGNER, true); + resourceDetailsVF_01 = changeComponentInstanceVersion.left().value().getLeft(); + resourceDetailsVFC1compIns1 = changeComponentInstanceVersion.left().value().getRight(); + + /////// certify service1 //////// + defaultService1 = AtomicOperationUtils.changeComponentState(defaultService1, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + //////// distribute service1 - successfully //////// + AtomicOperationUtils.distributeService(defaultService1, true); + + /////// create VF2 //////// + + Either resourceDetailsVF_02e = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + resourceDetailsVF_02 = resourceDetailsVF_02e.left().value(); + + } + + // private void updateArtParameterInResource(Resource resource) throws + // IOException { + // + // ArtifactRestUtils.uploadArtifact(artifactDetails, component, + // sdncModifierDetails) + // + // for (String depResArtType : Utils.getListOfDepResArtLabels(true)) { + // ArtifactDefinition artifactDefinition = + // resource.getDeploymentArtifacts().get(depResArtType); + // ArtifactReqDetails artifacJavaObject = + // ResponseParser.convertArtifactDefinitionToArtifactReqDetailsObject(artifactDefinition); + // + // //update parameter + // List resourceHeatParameters = + // resource.getDeploymentArtifacts().get(depResArtType).getHeatParameters(); + // for (HeatParameterDefinition heatParameterDefinition : + // resourceHeatParameters){ + // if (heatParameterDefinition.getName().equals("address")){ + // heatParameterDefinition.setCurrentValue("negev"); + // break; + // } + // } + // artifacJavaObject.setHeatParameters(resourceHeatParameters); + // artifacJavaObject.setPayloadData(null); + // RestResponse updateInformationalArtifactToResource = + // ArtifactRestUtils.updateDeploymentArtifactToResource(artifacJavaObject, + // sdncDesignerDetails, resource.getUniqueId()); + // assertTrue("response code is not 200, returned: " + + // updateInformationalArtifactToResource.getErrorCode(),updateInformationalArtifactToResource.getErrorCode() + // == 200); + // } + // } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/sanity/MultipleResourceUpdate.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/sanity/MultipleResourceUpdate.java new file mode 100644 index 0000000000..0a7b4a98aa --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/sanity/MultipleResourceUpdate.java @@ -0,0 +1,131 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.sanity; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.AssocType; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.testng.annotations.Test; +import static org.testng.AssertJUnit.assertTrue; + +public class MultipleResourceUpdate extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public MultipleResourceUpdate() { + super(name, MultipleResourceUpdate.class.getName()); + } + + @Test + public void simpleScenario() throws Exception { + + // Creating VF and Resource instances + Resource vf = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left() + .value(); + Resource cp1 = AtomicOperationUtils + .createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.CP, NormativeTypesEnum.PORT, + ResourceCategoryEnum.NETWORK_CONNECTIVITY_CON_POINT, UserRoleEnum.DESIGNER, true) + .left().value(); + Resource cp2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.CP, UserRoleEnum.DESIGNER, true) + .left().value(); + Resource vl = AtomicOperationUtils + .createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VL, NormativeTypesEnum.NETWORK, + ResourceCategoryEnum.NETWORK_CONNECTIVITY_VIRTUAL_LINK, UserRoleEnum.DESIGNER, true) + .left().value(); + + vf.getCreatorUserId(); + + // Check In Resources + AtomicOperationUtils.changeComponentState(cp1, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + AtomicOperationUtils.changeComponentState(cp2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + AtomicOperationUtils.changeComponentState(vl, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + + // CheckIn all other except VF + ComponentInstance instanceCP1 = AtomicOperationUtils + .addComponentInstanceToComponentContainer(cp1, vf, UserRoleEnum.DESIGNER, true).left().value(); + ComponentInstance instanceVL = AtomicOperationUtils + .addComponentInstanceToComponentContainer(vl, vf, UserRoleEnum.DESIGNER, true).left().value(); + ComponentInstance instanceCP2 = AtomicOperationUtils + .addComponentInstanceToComponentContainer(cp2, vf, UserRoleEnum.DESIGNER, true).left().value(); + + vf = (Resource) AtomicOperationUtils.getCompoenntObject(vf, UserRoleEnum.DESIGNER); + + // Create Vertex(Link/Associate 2 Resource Instances on Canvas) + AtomicOperationUtils.associate2ResourceInstances(vf, instanceCP1, instanceVL, AssocType.LINKABLE.getAssocType(), + UserRoleEnum.DESIGNER, true); + + List componentInstanceReqDetailsList = new ArrayList<>(); + componentInstanceReqDetailsList.add(new ComponentInstanceReqDetails(instanceCP1)); + componentInstanceReqDetailsList.add(new ComponentInstanceReqDetails(instanceCP2)); + componentInstanceReqDetailsList.add(new ComponentInstanceReqDetails(instanceVL)); + + ComponentInstanceReqDetails compInstDet = componentInstanceReqDetailsList.get(0); + compInstDet.setPosX("150"); + compInstDet.setPosY("150"); + compInstDet = componentInstanceReqDetailsList.get(1); + compInstDet.setPosX("400"); + compInstDet.setPosY("150"); + compInstDet = componentInstanceReqDetailsList.get(2); + compInstDet.setPosX("150"); + compInstDet.setPosY("300"); + + RestResponse response = ComponentInstanceRestUtils.updateMultipleComponentInstance( + componentInstanceReqDetailsList, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), vf.getUniqueId(), + vf.getComponentType()); + assertTrue("response code is not 200, returned: " + response.getErrorCode(), + response.getErrorCode() == ProductRestUtils.STATUS_CODE_SUCCESS); + + compInstDet = componentInstanceReqDetailsList.get(0); + compInstDet.setPosX("350"); + compInstDet.setPosY("350"); + compInstDet = componentInstanceReqDetailsList.get(1); + compInstDet.setPosX("600"); + compInstDet.setPosY("350"); + compInstDet = componentInstanceReqDetailsList.get(2); + compInstDet.setPosX("350"); + compInstDet.setPosY("500"); + + response = ComponentInstanceRestUtils.updateMultipleComponentInstance(componentInstanceReqDetailsList, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), vf.getUniqueId(), vf.getComponentType()); + assertTrue("response code is not 200, returned: " + response.getErrorCode(), + response.getErrorCode() == ProductRestUtils.STATUS_CODE_SUCCESS); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ParametersDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ParametersDefinition.java new file mode 100644 index 0000000000..a14dc8c76f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ParametersDefinition.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.List; + +public class ParametersDefinition { + + private String type; + private String description; + private Object Default; + private String status; +// private List constraints; + private String entry_schema; + private Object value; + + public ParametersDefinition() { + super(); + // TODO Auto-generated constructor stub + } + + public ParametersDefinition(String type, String description, Object default1, String status, String entry_schema, Object value) { + super(); + this.type = type; + this.description = description; + Default = default1; + this.status = status; + this.entry_schema = entry_schema; + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Object getDefault() { + return Default; + } + + public void setDefault(Object default1) { + Default = default1; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getEntry_schema() { + return entry_schema; + } + + public void setEntry_schema(String entry_schema) { + this.entry_schema = entry_schema; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + @Override + public String toString() { + return "ParametersDefinition [type=" + type + ", description=" + description + ", Default=" + Default + ", status=" + status + ", entry_schema=" + entry_schema + ", value=" + value + "]"; + } + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaCapabilitiesNodeTemplatesDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaCapabilitiesNodeTemplatesDefinition.java new file mode 100644 index 0000000000..76c0c86680 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaCapabilitiesNodeTemplatesDefinition.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +public class ToscaCapabilitiesNodeTemplatesDefinition { + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaDefinition.java new file mode 100644 index 0000000000..5a89a6766c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaDefinition.java @@ -0,0 +1,120 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.TypeDescription; + +public class ToscaDefinition { + + String tosca_definitions_version; + Map metadata; +// Map imports; +// TODO waiting for answer about imports representation + Object imports; + Map node_types; + ToscaTopologyTemplateDefinition topology_template; + + public ToscaDefinition() { + super(); + } + + @Override + public String toString() { + return "ToscaDefinition [tosca_definitions_version=" + tosca_definitions_version + ", metadata=" + metadata + ", imports=" + imports + ", node_types=" + node_types + ", topology_template=" + topology_template + "]"; + } + + public String getTosca_definitions_version() { + return tosca_definitions_version; + } + + public void setTosca_definitions_version(String tosca_definitions_version) { + this.tosca_definitions_version = tosca_definitions_version; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + + + +// public Map getImports() { +// return (Map) imports; +// } +// +// public void setImports(Map imports) { +// this.imports = imports; +// } +// +// public List getImports() { +// return (List) imports; +// } +// +// public void setImports(List imports) { +// this.imports = imports; +// } + + public Object getImports() { + return imports; + } + + public void setImports(Object imports) { + this.imports = imports; + } + + public Map getNode_types() { + return node_types; + } + + public void setNode_types(Map node_types) { + this.node_types = node_types; + } + + public ToscaTopologyTemplateDefinition getTopology_template() { + return topology_template; + } + + public void setTopology_template(ToscaTopologyTemplateDefinition topology_template) { + this.topology_template = topology_template; + } + + + + //gets Type description for Yaml snake + public static TypeDescription getTypeDescription(){ + TypeDescription typeDescription = new TypeDescription(ToscaDefinition.class); + typeDescription.putMapPropertyType("metadata", String.class, String.class); +// TODO Andrey imports format + typeDescription.putMapPropertyType("imports", String.class, ToscaImportsDefinition.class); + typeDescription.putListPropertyType("imports", List.class); + typeDescription.putMapPropertyType("node_types", String.class, ToscaNodeTypesDefinition.class); + return typeDescription; + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaGroupsMetadataDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaGroupsMetadataDefinition.java new file mode 100644 index 0000000000..eec057ed52 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaGroupsMetadataDefinition.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +public class ToscaGroupsMetadataDefinition { + + private String vfModuleModelName; + private String vfModuleModelInvariantUUID; + private String vfModuleModelCustomizationUUID; + private String vfModuleModelUUID; + private String vfModuleModelVersion; + + public ToscaGroupsMetadataDefinition() { + super(); + // TODO Auto-generated constructor stub + } + + public String getVfModuleModelName() { + return vfModuleModelName; + } + + public void setVfModuleModelName(String vfModuleModelName) { + this.vfModuleModelName = vfModuleModelName; + } + + public String getVfModuleModelInvariantUUID() { + return vfModuleModelInvariantUUID; + } + + public void setVfModuleModelInvariantUUID(String vfModuleModelInvariantUUID) { + this.vfModuleModelInvariantUUID = vfModuleModelInvariantUUID; + } + + public String getVfModuleModelCustomizationUUID() { + return vfModuleModelCustomizationUUID; + } + + public void setVfModuleModelCustomizationUUID(String vfModuleModelCustomizationUUID) { + this.vfModuleModelCustomizationUUID = vfModuleModelCustomizationUUID; + } + + public String getVfModuleModelUUID() { + return vfModuleModelUUID; + } + + public void setVfModuleModelUUID(String vfModuleModelUUID) { + this.vfModuleModelUUID = vfModuleModelUUID; + } + + public String getVfModuleModelVersion() { + return vfModuleModelVersion; + } + + public void setVfModuleModelVersion(String vfModuleModelVersion) { + this.vfModuleModelVersion = vfModuleModelVersion; + } + + @Override + public String toString() { + return "ToscaGroupsMetadataDefinition [vfModuleModelName=" + vfModuleModelName + ", vfModuleModelInvariantUUID=" + vfModuleModelInvariantUUID + ", vfModuleModelCustomizationUUID=" + vfModuleModelCustomizationUUID + + ", vfModuleModelUUID=" + vfModuleModelUUID + ", vfModuleModelVersion=" + vfModuleModelVersion + "]"; + } + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaGroupsTopologyTemplateDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaGroupsTopologyTemplateDefinition.java new file mode 100644 index 0000000000..dc3c40751c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaGroupsTopologyTemplateDefinition.java @@ -0,0 +1,126 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.TypeDescription; + +// spec page 102 +public class ToscaGroupsTopologyTemplateDefinition { + + private String type; // required + private String description; + private Map properties; + private Map targets; // required + private Map interfaces; + private List members; +// private Map metadata; + private ToscaGroupsMetadataDefinition metadata; + + public ToscaGroupsTopologyTemplateDefinition() { + super(); + } + + public ToscaGroupsMetadataDefinition getMetadata() { + return metadata; + } + + public void setMetadata(ToscaGroupsMetadataDefinition metadata) { + this.metadata = metadata; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public Map getTargets() { + return targets; + } + + public void setTargets(Map targets) { + this.targets = targets; + } + + public Map getInterfaces() { + return interfaces; + } + + public void setInterfaces(Map interfaces) { + this.interfaces = interfaces; + } + + public List getMembers() { + return members; + } + + public void setMembers(List members) { + this.members = members; + } + +// public Map getMetadata() { +// return metadata; +// } +// +// public void setMetadata(Map metadata) { +// this.metadata = metadata; +// } + + @Override + public String toString() { + return "ToscaGroupsTopologyTemplateDefinition [type=" + type + ", description=" + description + ", properties=" + properties + ", targets=" + targets + ", interfaces=" + interfaces + ", members=" + members + ", metadata=" + metadata + + "]"; + } + + //gets Type description for Yaml snake + public static TypeDescription getTypeDescription(){ + TypeDescription typeDescription = new TypeDescription(ToscaGroupsTopologyTemplateDefinition.class); + typeDescription.putMapPropertyType("properties", String.class, Object.class); + typeDescription.putMapPropertyType("interfaces", String.class, Object.class); + typeDescription.putMapPropertyType("targets", String.class, Object.class); +// typeDescription.putMapPropertyType("metadata", String.class, String.class); + typeDescription.putMapPropertyType("metadata", String.class, String.class); + typeDescription.putListPropertyType("members", String.class); + return typeDescription; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaImportsDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaImportsDefinition.java new file mode 100644 index 0000000000..d62e33e1dd --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaImportsDefinition.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +public class ToscaImportsDefinition { + + private String file; + private String repository; + private String namespace_uri; + private String namespace_prefix; + + public ToscaImportsDefinition() { + super(); + // TODO Auto-generated constructor stub + } + + public ToscaImportsDefinition(String file, String repository, String namespace_uri, String namespace_prefix) { + super(); + this.file = file; + this.repository = repository; + this.namespace_uri = namespace_uri; + this.namespace_prefix = namespace_prefix; + } + + @Override + public String toString() { + return "ToscaImportsDefinition [file=" + file + ", repository=" + repository + ", namespace_uri=" + namespace_uri + ", namespace_prefix=" + namespace_prefix + "]"; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + this.file = file; + } + + public String getRepository() { + return repository; + } + + public void setRepository(String repository) { + this.repository = repository; + } + + public String getNamespace_uri() { + return namespace_uri; + } + + public void setNamespace_uri(String namespace_uri) { + this.namespace_uri = namespace_uri; + } + + public String getNamespace_prefix() { + return namespace_prefix; + } + + public void setNamespace_prefix(String namespace_prefix) { + this.namespace_prefix = namespace_prefix; + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaInputsTopologyTemplateDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaInputsTopologyTemplateDefinition.java new file mode 100644 index 0000000000..6f9590f0ae --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaInputsTopologyTemplateDefinition.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.Map; + +public class ToscaInputsTopologyTemplateDefinition { + + private Map> inputs; + + public ToscaInputsTopologyTemplateDefinition() { + super(); + // TODO Auto-generated constructor stub + } + + public Map> getInputs() { + return inputs; + } + + public void setInputs(Map> inputs) { + this.inputs = inputs; + } + + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaNodeTemplatesTopologyTemplateDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaNodeTemplatesTopologyTemplateDefinition.java new file mode 100644 index 0000000000..d42ca8e307 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaNodeTemplatesTopologyTemplateDefinition.java @@ -0,0 +1,174 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.TypeDescription; + +public class ToscaNodeTemplatesTopologyTemplateDefinition { + + private String name; + private String type; + private String description; + private String [] directives; + private Map properties; + private List> attributes; + private List> requirements; + private List> capabilities; + private List> interfaces; + private List> artifacts; + private List> node_filter; + private String copy; + private Map metadata; + + +// private Map properties; +// private Map requirements; +// private Map capabilities; + + public ToscaNodeTemplatesTopologyTemplateDefinition() { + super(); + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String[] getDirectives() { + return directives; + } + + public void setDirectives(String[] directives) { + this.directives = directives; + } + + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public List> getAttributes() { + return attributes; + } + + public void setAttributes(List> attributes) { + this.attributes = attributes; + } + + public List> getRequirements() { + return requirements; + } + + public void setRequirements(List> requirements) { + this.requirements = requirements; + } + + public List> getCapabilities() { + return capabilities; + } + + public void setCapabilities(List> capabilities) { + this.capabilities = capabilities; + } + + public List> getInterfaces() { + return interfaces; + } + + public void setInterfaces(List> interfaces) { + this.interfaces = interfaces; + } + + public List> getArtifacts() { + return artifacts; + } + + public void setArtifacts(List> artifacts) { + this.artifacts = artifacts; + } + + public List> getNode_filter() { + return node_filter; + } + + public void setNode_filter(List> node_filter) { + this.node_filter = node_filter; + } + + public String getCopy() { + return copy; + } + + public void setCopy(String copy) { + this.copy = copy; + } + + //gets Type description for Yaml snake + public static TypeDescription getTypeDescription(){ + TypeDescription typeDescription = new TypeDescription(ToscaNodeTemplatesTopologyTemplateDefinition.class); + typeDescription.putMapPropertyType("properties", String.class, Object.class); + typeDescription.putListPropertyType("requirements", Map.class); + typeDescription.putListPropertyType("capabilities", Map.class); + typeDescription.putListPropertyType("attributes", Map.class); + typeDescription.putListPropertyType("interfaces", Map.class); + typeDescription.putListPropertyType("artifacts", Map.class); + typeDescription.putListPropertyType("node_filter", Map.class); + typeDescription.putMapPropertyType("metadata", String.class, String.class); + return typeDescription; + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaNodeTypesDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaNodeTypesDefinition.java new file mode 100644 index 0000000000..07fd223d2c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaNodeTypesDefinition.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.Map; + +// spec page 88 +public class ToscaNodeTypesDefinition { + + private String name; + private String derived_from; + private String version; + private String description; + private Map properties; + private Map attributes; + private Map requirements; + private Map capabilities; + private Map interfaces; + private Map artifacts; + + public ToscaNodeTypesDefinition() { + super(); + } + + public ToscaNodeTypesDefinition(String name, String derived_from, String version, String description, Map properties, Map attributes, Map requirements, Map capabilities, + Map interfaces, Map artifacts) { + super(); + this.name = name; + this.derived_from = derived_from; + this.version = version; + this.description = description; + this.properties = properties; + this.attributes = attributes; + this.requirements = requirements; + this.capabilities = capabilities; + this.interfaces = interfaces; + this.artifacts = artifacts; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDerived_from() { + return derived_from; + } + + public void setDerived_from(String derived_from) { + this.derived_from = derived_from; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + public Map getRequirements() { + return requirements; + } + + public void setRequirements(Map requirements) { + this.requirements = requirements; + } + + public Map getCapabilities() { + return capabilities; + } + + public void setCapabilities(Map capabilities) { + this.capabilities = capabilities; + } + + public Map getInterfaces() { + return interfaces; + } + + public void setInterfaces(Map interfaces) { + this.interfaces = interfaces; + } + + public Map getArtifacts() { + return artifacts; + } + + public void setArtifacts(Map artifacts) { + this.artifacts = artifacts; + } + + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaOutputsTopologyTemplateDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaOutputsTopologyTemplateDefinition.java new file mode 100644 index 0000000000..02ca03dfa5 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaOutputsTopologyTemplateDefinition.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.Map; + +public class ToscaOutputsTopologyTemplateDefinition { + + private Map outputs; + + public ToscaOutputsTopologyTemplateDefinition() { + super(); + // TODO Auto-generated constructor stub + } + + public Map getOutputs() { + return outputs; + } + + public void setOutputs(Map outputs) { + this.outputs = outputs; + } + + @Override + public String toString() { + return "ToscaOutputsTopologyTemplateDefinition [outputs=" + outputs + "]"; + } + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaPoliciesTopologyTemplateDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaPoliciesTopologyTemplateDefinition.java new file mode 100644 index 0000000000..7ac3e876b4 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaPoliciesTopologyTemplateDefinition.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.Map; + +public class ToscaPoliciesTopologyTemplateDefinition { + + public ToscaPoliciesTopologyTemplateDefinition() { + super(); + } + + private String type; // required + private String description; + private Map properties; + private Map targets; + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public Map getProperties() { + return properties; + } + public void setProperties(Map properties) { + this.properties = properties; + } + public Map getTargets() { + return targets; + } + public void setTargets(Map targets) { + this.targets = targets; + } + @Override + public String toString() { + return "ToscaPoliciesTopologyTemplateDefinition [type=" + type + ", description=" + description + ", properties=" + properties + ", targets=" + targets + "]"; + } + + + +} + diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaRelationshipTemplatesTopologyTemplateDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaRelationshipTemplatesTopologyTemplateDefinition.java new file mode 100644 index 0000000000..392ffc4e42 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaRelationshipTemplatesTopologyTemplateDefinition.java @@ -0,0 +1,79 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.Map; + +public class ToscaRelationshipTemplatesTopologyTemplateDefinition { + + public ToscaRelationshipTemplatesTopologyTemplateDefinition() { + // TODO Auto-generated constructor stub + } + + private String type; + private String description; + private Map properties; + private Map attributes; + private Map interfaces; + private String copy; + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public Map getProperties() { + return properties; + } + public void setProperties(Map properties) { + this.properties = properties; + } + public Map getAttributes() { + return attributes; + } + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + public Map getInterfaces() { + return interfaces; + } + public void setInterfaces(Map interfaces) { + this.interfaces = interfaces; + } + public String getCopy() { + return copy; + } + public void setCopy(String copy) { + this.copy = copy; + } + @Override + public String toString() { + return "ToscaRelationshipTemplatesTopologyTemplateDefinition [type=" + type + ", description=" + description + ", properties=" + properties + ", attributes=" + attributes + ", interfaces=" + interfaces + ", copy=" + copy + "]"; + } + + +} diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/AttributeDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaRequirementsNodeTemplatesDefinition.java similarity index 50% rename from catalog-model/src/main/java/org/openecomp/sdc/be/model/AttributeDefinition.java rename to test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaRequirementsNodeTemplatesDefinition.java index 120a87c610..bd9f0f0f5e 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/AttributeDefinition.java +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaRequirementsNodeTemplatesDefinition.java @@ -18,54 +18,55 @@ * ============LICENSE_END========================================================= */ -package org.openecomp.sdc.be.model; +package org.openecomp.sdc.ci.tests.tosca.datatypes; -import java.io.Serializable; +public class ToscaRequirementsNodeTemplatesDefinition { -import org.openecomp.sdc.be.datatypes.elements.AttributeDataDefinition; + String name; + String capability; + String node; + String relationship; -public class AttributeDefinition extends AttributeDataDefinition implements IComplexDefaultValue, Serializable { + public ToscaRequirementsNodeTemplatesDefinition() { + super(); + } - /** - * - */ - private static final long serialVersionUID = -6306111879714097811L; + public String getName() { + return name; + } - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((parentUniqueId == null) ? 0 : parentUniqueId.hashCode()); - return result; + public void setName(String name) { + this.name = name; } - /** - * The resource id which this property belongs to - */ - private String parentUniqueId; + public String getCapability() { + return capability; + } - public AttributeDefinition(AttributeDefinition hpdd) { - super(hpdd); + public void setCapability(String capability) { + this.capability = capability; } - public AttributeDefinition() { - super(); + public String getNode() { + return node; } - public AttributeDefinition(AttributeDataDefinition p) { - super(p); + public void setNode(String node) { + this.node = node; } - public String getParentUniqueId() { - return parentUniqueId; + public String getRelationship() { + return relationship; } - public void setParentUniqueId(String parentUniqueId) { - this.parentUniqueId = parentUniqueId; + public void setRelationship(String relationship) { + this.relationship = relationship; } @Override public String toString() { - return super.toString() + " [ parentUniqueId=" + parentUniqueId + "]"; + return "ToscaRequirementsDefinition [name=" + name + ", capability=" + capability + ", node=" + node + + ", relationship=" + relationship + "]"; } + } diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaSubstitutionMappingsDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaSubstitutionMappingsDefinition.java new file mode 100644 index 0000000000..957d988c4d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaSubstitutionMappingsDefinition.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.Map; + +import org.yaml.snakeyaml.TypeDescription; + +public class ToscaSubstitutionMappingsDefinition { + + private String node_type; + private Map requirements; + private Map capabilities; + + public ToscaSubstitutionMappingsDefinition() { + super(); + // TODO Auto-generated constructor stub + } + + public String getNode_type() { + return node_type; + } + + public void setNode_type(String node_type) { + this.node_type = node_type; + } + + public Map getRequirements() { + return requirements; + } + + public void setRequirements(Map requirements) { + this.requirements = requirements; + } + + public Map getCapabilities() { + return capabilities; + } + + public void setCapabilities(Map capabilities) { + this.capabilities = capabilities; + } + +// gets Type description for Yaml snake + public static TypeDescription getTypeDescription(){ + TypeDescription typeDescription = new TypeDescription(ToscaSubstitutionMappingsDefinition.class); + typeDescription.putMapPropertyType("requirements", String.class, Object.class); + typeDescription.putMapPropertyType("capabilities", String.class, Object.class); + return typeDescription; + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaTopologyTemplateDefinition.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaTopologyTemplateDefinition.java new file mode 100644 index 0000000000..539c9b4d63 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaTopologyTemplateDefinition.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.TypeDescription; + +// spec page 104 +public class ToscaTopologyTemplateDefinition { + + String description; + Map inputs; + Map node_templates; +// Map relationship_templates; + Map groups; +// Map policies; +// Map outputs; + ToscaSubstitutionMappingsDefinition substitution_mappings; + + public ToscaTopologyTemplateDefinition() { + super(); + // TODO Auto-generated constructor stub + } + + + public ToscaSubstitutionMappingsDefinition getSubstitution_mappings() { + return substitution_mappings; + } + + + public void setSubstitution_mappings(ToscaSubstitutionMappingsDefinition substitution_mappings) { + this.substitution_mappings = substitution_mappings; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getInputs() { + return inputs; + } + + public void setInputs(Map inputs) { + this.inputs = inputs; + } + + public Map getNode_templates() { + return node_templates; + } + + public void setNode_templates(Map node_templates) { + this.node_templates = node_templates; + } + +// public Map getRelationship_templates() { +// return relationship_templates; +// } +// +// public void setRelationship_templates(Map relationship_templates) { +// this.relationship_templates = relationship_templates; +// } + + public Map getGroups() { + return groups; + } + + public void setGroups(Map groups) { + this.groups = groups; + } +// +// public Map getPolicies() { +// return policies; +// } +// +// public void setPolicies(Map policies) { +// this.policies = policies; +// } +// +// public Map getOutputs() { +// return outputs; +// } +// +// public void setOutputs(Map outputs) { +// this.outputs = outputs; +// } +// +// public Map getSubstitution_mappings() { +// return substitution_mappings; +// } +// +// public void setSubstitution_mappings(Map substitution_mappings) { +// this.substitution_mappings = substitution_mappings; +// } + +// @Override +// public String toString() { +// return "ToscaTopologyTemplateDefinition [description=" + description + ", inputs=" + inputs + ", node_templates=" + node_templates + ", relationship_templates=" + relationship_templates + ", groups=" + groups + ", policies=" +// + policies + ", outputs=" + outputs + ", substitution_mappings=" + substitution_mappings + "]"; +// } + + //gets Type description for Yaml snake + public static TypeDescription getTypeDescription(){ + TypeDescription typeDescription = new TypeDescription(ToscaTopologyTemplateDefinition.class); + typeDescription.putMapPropertyType("inputs", String.class, Object.class); + typeDescription.putMapPropertyType("node_templates", String.class, ToscaNodeTemplatesTopologyTemplateDefinition.class); + typeDescription.putMapPropertyType("groups", String.class, ToscaGroupsTopologyTemplateDefinition.class); + return typeDescription; + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaTopologyTemplateDefinition2.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaTopologyTemplateDefinition2.java new file mode 100644 index 0000000000..735c8a0f95 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/tosca/datatypes/ToscaTopologyTemplateDefinition2.java @@ -0,0 +1,78 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.tosca.datatypes; + +import java.util.Map; + +// spec page 104 +public class ToscaTopologyTemplateDefinition2 { + + String description; + Map> inputs; + Map node_templates; +// Map relationship_templates; + Map groups; +// Map policies; +// Map outputs; +// Map substitution_mappings; + + public ToscaTopologyTemplateDefinition2() { + super(); + // TODO Auto-generated constructor stub + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + + public Map> getInputs() { + return inputs; + } + + public void setInputs(Map> inputs) { + this.inputs = inputs; + } + + public Map getNode_templates() { + return node_templates; + } + + public void setNode_templates(Map node_templates) { + this.node_templates = node_templates; + } + + public Map getGroups() { + return groups; + } + + public void setGroups(Map groups) { + this.groups = groups; + } + + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/AddUserAuditMessageInfo.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/AddUserAuditMessageInfo.java new file mode 100644 index 0000000000..9ca8adee53 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/AddUserAuditMessageInfo.java @@ -0,0 +1,113 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.users; + +public class AddUserAuditMessageInfo { + + String TIMESTAMP; + String ACTION; + // String MODIFIER_NAME; + String MODIFIER; + // String USER_UID; + // String USER_NAME; + // String USER_EMAIL; + // String USER_ROLE; + String USER; + String STATUS; + String DESC; + + public AddUserAuditMessageInfo(String timestamp, String action, String modifierName, String modifierUid, + String user, String status, String desc) { + super(); + this.TIMESTAMP = timestamp; + this.ACTION = action; + // this.MODIFIER_NAME = modifierName; + this.MODIFIER = modifierUid; + this.USER = user; + this.STATUS = status; + this.DESC = desc; + } + + public AddUserAuditMessageInfo() { + super(); + } + + public String getTIMESTAMP() { + return TIMESTAMP; + } + + public void setTIMESTAMP(String tIMESTAMP) { + TIMESTAMP = tIMESTAMP; + } + + public String getACTION() { + return ACTION; + } + + public void setACTION(String aCTION) { + ACTION = aCTION; + } + + // public String getMODIFIER_NAME() { + // return MODIFIER_NAME; + // } + // public void setMODIFIER_NAME(String mODIFIER_NAME) { + // MODIFIER_NAME = mODIFIER_NAME; + // } + public String getMODIFIER() { + return MODIFIER; + } + + public void setMODIFIER(String mODIFIER_UID) { + MODIFIER = mODIFIER_UID; + } + + public String getUSER() { + return USER; + } + + public void setUSER(String uSER) { + USER = uSER; + } + + public String getSTATUS() { + return STATUS; + } + + public void setSTATUS(String sTATUS) { + STATUS = sTATUS; + } + + public String getDESC() { + return DESC; + } + + public void setDESC(String dESC) { + DESC = dESC; + } + + @Override + public String toString() { + return "AddUserAuditMessageInfo [timestamp=" + TIMESTAMP + ", action=" + ACTION + ", modifierUid=" + MODIFIER + + ", user=" + USER + ", status=" + STATUS + ", desc=" + DESC + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserAuditJavaObject.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserAuditJavaObject.java new file mode 100644 index 0000000000..b34d474cf0 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserAuditJavaObject.java @@ -0,0 +1,133 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.users; + +public class UserAuditJavaObject { + + String TIMESTAMP; + String ACTION; + // String MODIFIER_NAME; + String MODIFIER; + String USER; + // String USER_NAME; + // String USER_EMAIL; + // String USER_ROLE; + String STATUS; + String DESC; + + public UserAuditJavaObject(String timestamp, String action, String modifier, String user, String status, + String desc) { + super(); + this.TIMESTAMP = timestamp; + this.ACTION = action; + // this.MODIFIER_NAME = modifierName; + this.MODIFIER = modifier; + this.USER = user; + // this.USER_NAME = userName; + // this.USER_EMAIL = userEmail; + // this.USER_ROLE = userRole; + this.STATUS = status; + this.DESC = desc; + } + + public UserAuditJavaObject() { + super(); + } + + public String getTIMESTAMP() { + return TIMESTAMP; + } + + public void setTIMESTAMP(String tIMESTAMP) { + TIMESTAMP = tIMESTAMP; + } + + public String getACTION() { + return ACTION; + } + + public void setACTION(String aCTION) { + ACTION = aCTION; + } + + // public String getMODIFIER_NAME() { + // return MODIFIER_NAME; + // } + // public void setMODIFIER_NAME(String mODIFIER_NAME) { + // MODIFIER_NAME = mODIFIER_NAME; + // } + public String getMODIFIER() { + return MODIFIER; + } + + public void setMODIFIER(String mODIFIER_UID) { + MODIFIER = mODIFIER_UID; + } + + public String getUSER() { + return USER; + } + + public void setUSER(String uSER) { + USER = uSER; + } + + // public String getUSER_NAME() { + // return USER_NAME; + // } + // public void setUSER_NAME(String uSER_NAME) { + // USER_NAME = uSER_NAME; + // } + // public String getUSER_EMAIL() { + // return USER_EMAIL; + // } + // public void setUSER_EMAIL(String uSER_EMAIL) { + // USER_EMAIL = uSER_EMAIL; + // } + // public String getUSER_ROLE() { + // return USER_ROLE; + // } + // public void setUSER_ROLE(String uSER_ROLE) { + // USER_ROLE = uSER_ROLE; + // } + public String getSTATUS() { + return STATUS; + } + + public void setSTATUS(String sTATUS) { + STATUS = sTATUS; + } + + public String getDESC() { + return DESC; + } + + public void setDESC(String dESC) { + DESC = dESC; + } + + @Override + public String toString() { + return "UserAuditJavaObject [timestamp=" + TIMESTAMP + ", action=" + ACTION + ", modifier=" + MODIFIER + + ", user=" + USER + ", status=" + STATUS + ", desc=" + DESC + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserHeaderData.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserHeaderData.java new file mode 100644 index 0000000000..06320bcb5f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserHeaderData.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.users; + +public class UserHeaderData { + String contentType; + String httpCspUserId; + String accept; + + public UserHeaderData(String contentType, String httpCspUserId, String accept) { + super(); + this.contentType = contentType; + this.httpCspUserId = httpCspUserId; + this.accept = accept; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getHttpCspUserId() { + return httpCspUserId; + } + + public void setHttpCspUserId(String httpCspUserId) { + this.httpCspUserId = httpCspUserId; + } + + public String getAccept() { + return accept; + } + + public void setAccept(String accept) { + this.accept = accept; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserResponseMessageEnum.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserResponseMessageEnum.java new file mode 100644 index 0000000000..97a08479f8 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/UserResponseMessageEnum.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.users; + +public enum UserResponseMessageEnum { + + SUCCESS_MESSAGE("OK"), MISSING_INFORMATION("Error: Missing information"), METHOD_NOT_ALLOWED("Error: Method not allowed"), RESTRICTED_OPERATION("Error: Restricted operation"), USER_ALREADY_EXISTS("Error: User with %s ID already exists"), + INVALID_EMAIL("Error: Invalid Content. Invalid e-mail address %s"), INVALID_ROLE("Error: Invalid Content. Invalid role %s"), INVALID_CONTENT("Error: Invalid content"), USER_NOT_FOUND("Error: User with %s ID is not found"), + INTERNAL_SERVER_ERROR("Error: Internal Server Error. Try later again"), ADMINISTARTOR_CAN_BE_DELETED("Error: Administrator can be deleted by other administrator only"), RESTRICTED_ACCESS("Error: Restricted access"); + + String value; + + private UserResponseMessageEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/WebSealUserDetails.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/WebSealUserDetails.java new file mode 100644 index 0000000000..609ebf22b7 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/users/WebSealUserDetails.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.users; + +public class WebSealUserDetails { + String firstName; + String lastName; + String userId; + String email; + + public WebSealUserDetails() { + super(); + } + + public WebSealUserDetails(String firstName, String lastName, String userId, String emailAddress) { + super(); + this.firstName = firstName; + this.lastName = lastName; + this.userId = userId; + this.email = emailAddress; + + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getEmailAddress() { + return email; + } + + public void setEmailAddress(String emailAddress) { + this.email = emailAddress; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ArtifactUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ArtifactUtils.java new file mode 100644 index 0000000000..12f8ffe984 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ArtifactUtils.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils; + +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; + +public class ArtifactUtils { + + public static ArtifactDefinition convertArtifactReqToDefinition(ArtifactReqDetails artifactReq) { + ArtifactDefinition artifact = new ArtifactDefinition(); + artifact.setArtifactLabel(artifactReq.getArtifactLabel()); + artifact.setArtifactDisplayName(artifactReq.getArtifactDisplayName()); + artifact.setArtifactGroupType(ArtifactGroupTypeEnum.findType(artifactReq.getArtifactGroupType())); + artifact.setArtifactType(artifactReq.getArtifactType().toUpperCase()); + artifact.setArtifactName(artifactReq.getArtifactName()); + artifact.setDescription(artifactReq.getDescription()); + artifact.setUniqueId(artifactReq.getUniqueId()); + artifact.setTimeout(artifactReq.getTimeout()); + artifact.setEsId(artifactReq.getUniqueId()); + + return artifact; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/CsarParserUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/CsarParserUtils.java new file mode 100644 index 0000000000..69c8b2fe2f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/CsarParserUtils.java @@ -0,0 +1,174 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.openecomp.sdc.ci.tests.datatypes.GroupHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.PropertyHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.datatypes.TypeHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.utils.validation.CsarValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CsarParserUtils { + private static Logger log = LoggerFactory.getLogger(CsarValidationUtils.class.getName()); + + public static List getListTypeHeatMetaDefinition(File csarUUID) throws Exception { + + String artifactHeatMetaLocation = "Artifacts/HEAT.meta"; + JSONParser parser = new JSONParser(); + String csarPayload = CsarValidationUtils.getCsarPayload(csarUUID, artifactHeatMetaLocation); + if (csarPayload != null) { + Object parse = parser.parse(csarPayload); + JSONObject jsonObject = (JSONObject) parse; + JSONObject jsonObjectImportStructure = (JSONObject) jsonObject.get("importStructure"); + List listHeatMetaDefenition = new ArrayList(); + listHeatMetaDefenition = getArtifactsByGroup(jsonObjectImportStructure, listHeatMetaDefenition); + return listHeatMetaDefenition; + } + return null; + + } + + public static List getListTypeHeatMetaDefinition(String csarUUID) throws Exception { + + String artifactHeatMetaLocation = "Artifacts/HEAT.meta"; + JSONParser parser = new JSONParser(); + String csarPayload = CsarValidationUtils.getCsarPayload(csarUUID, artifactHeatMetaLocation); + if (csarPayload != null) { + Object parse = parser.parse(csarPayload); + JSONObject jsonObject = (JSONObject) parse; + JSONObject jsonObjectImportStructure = (JSONObject) jsonObject.get("importStructure"); + List listHeatMetaDefenition = new ArrayList(); + listHeatMetaDefenition = getArtifactsByGroup(jsonObjectImportStructure, listHeatMetaDefenition); + return listHeatMetaDefenition; + } + return null; + + } + + protected static List getArtifactsByGroup(JSONObject jsonObjectImportStructure, List listHeatMetaDefenition) { + + @SuppressWarnings("unchecked") + Set typeSet = jsonObjectImportStructure.keySet(); + for (Object type : typeSet) { + TypeHeatMetaDefinition heatMetaDefenition = new TypeHeatMetaDefinition(); + log.debug(type.toString()); + log.debug("{}", jsonObjectImportStructure.get(type)); + JSONArray array = (JSONArray) jsonObjectImportStructure.get(type); + heatMetaDefenition.setTypeName((String) type); + List groupHeatMetaDefinitions = new ArrayList(); + heatMetaDefenition.setGroupHeatMetaDefinition(fetchArtifactByGroupFromJsonArray(array, groupHeatMetaDefinitions, true, false)); + listHeatMetaDefenition.add(heatMetaDefenition); + } + return listHeatMetaDefenition; + } + + protected static List fetchArtifactByGroupFromJsonArray(JSONArray array, List listGroupHeatMetaDefinition, Boolean openNewGroup, Boolean isNested) { + + GroupHeatMetaDefinition groupHeatMetaDefinition; + + if (array != null) { + for (int i = 0; i < array.size(); i++) { + if (openNewGroup) { + groupHeatMetaDefinition = new GroupHeatMetaDefinition(); + int groupNumber = listGroupHeatMetaDefinition.size() + 1; + log.debug("groupName={}", groupNumber); + groupHeatMetaDefinition.setGroup(groupNumber); + listGroupHeatMetaDefinition.add(groupHeatMetaDefinition); + PropertyHeatMetaDefinition propertyHeatMetaDefinition = new PropertyHeatMetaDefinition(); + propertyHeatMetaDefinition.setName("isBase"); + propertyHeatMetaDefinition.setValue(false); + groupHeatMetaDefinition.setPropertyHeatMetaDefinition(propertyHeatMetaDefinition); + } + groupHeatMetaDefinition = listGroupHeatMetaDefinition.get(listGroupHeatMetaDefinition.size() - 1); + JSONObject jsonObject = (JSONObject) array.get(i); + fetchArtifactByGroupFromJsonObject(listGroupHeatMetaDefinition, groupHeatMetaDefinition, jsonObject, isNested); + } + } + return listGroupHeatMetaDefinition; + } + + + public static void fetchArtifactByGroupFromJsonObject(List listGroupHeatMetaDefinition, GroupHeatMetaDefinition groupHeatMetaDefinition, JSONObject jsonObject, Boolean isNested) { + @SuppressWarnings("unchecked") + Set groupsKey = jsonObject.keySet(); + for (Object groupKey : groupsKey) { + String groupKeyStr = (String) groupKey; + if (groupKeyStr.equals("isBase")) { + PropertyHeatMetaDefinition propertyHeatMetaDefinition = new PropertyHeatMetaDefinition(); + propertyHeatMetaDefinition.setName(groupKeyStr); + propertyHeatMetaDefinition.setValue((boolean) jsonObject.get(groupKeyStr)); + if (!groupHeatMetaDefinition.getPropertyHeatMetaDefinition().equals(propertyHeatMetaDefinition)) { + groupHeatMetaDefinition.getPropertyHeatMetaDefinition().setValue((boolean) jsonObject.get(groupKeyStr)); + } + } + if (groupKeyStr.equals("fileName")) { + String artifactName = (String) jsonObject.get(groupKeyStr); + String artifactType = ArtifactTypeEnum.HEAT_ARTIFACT.getType(); + if(isNested){ + artifactType = ArtifactTypeEnum.HEAT_NESTED.getType(); + } + if(jsonObject.get("type") != null && isNested == false){ + artifactType = (String) jsonObject.get("type"); + } + HeatMetaFirstLevelDefinition heatMetaFirstLevelDefinition = new HeatMetaFirstLevelDefinition(artifactName, artifactType, null); + List listArtifactNames = groupHeatMetaDefinition.getArtifactList(); + listArtifactNames.add(heatMetaFirstLevelDefinition); + groupHeatMetaDefinition.setArtifactList(listArtifactNames); + } else { + if((groupKeyStr.equals("env"))){ + if (jsonObject.get(groupKeyStr) instanceof JSONObject){ + fetchArtifactByGroupFromJsonObject(listGroupHeatMetaDefinition, groupHeatMetaDefinition, (JSONObject) jsonObject.get(groupKeyStr), false); + }else{ + assertTrue("Expected object is JSONObject, but actual: " + jsonObject.get(groupKeyStr).getClass(), jsonObject.get(groupKeyStr).getClass().equals("JSONObject")); + } + } + if((groupKeyStr.equals("nested"))){ + if (jsonObject.get(groupKeyStr) instanceof JSONArray){ + fetchArtifactByGroupFromJsonArray((JSONArray) jsonObject.get(groupKeyStr), listGroupHeatMetaDefinition, false, true); + }else{ + assertTrue("Expected object is JSONArray, but actual: " + jsonObject.get(groupKeyStr).getClass(), jsonObject.get(groupKeyStr).getClass().equals("JSONArray")); + } + + }else if (!(groupKeyStr.equals("isBase") || groupKeyStr.equals("type") || groupKeyStr.equals("env"))) { + if (jsonObject.get(groupKeyStr) instanceof JSONArray){ + fetchArtifactByGroupFromJsonArray((JSONArray) jsonObject.get(groupKeyStr), listGroupHeatMetaDefinition, false, false); + }else{ + assertTrue("Expected object is JSONArray, but actual: " + jsonObject.get(groupKeyStr).getClass(), jsonObject.get(groupKeyStr).getClass().equals("JSONArray")); + } + } + } + } + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/DbUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/DbUtils.java new file mode 100644 index 0000000000..8e611a32d7 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/DbUtils.java @@ -0,0 +1,293 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.thinkaurelius.titan.core.TitanEdge; +import com.thinkaurelius.titan.core.TitanFactory; +import com.thinkaurelius.titan.core.TitanGraph; +import com.thinkaurelius.titan.core.TitanVertex; + +import fj.data.Either; + +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.util.ElementHelper; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.users.UserAuditJavaObject; +import org.openecomp.sdc.ci.tests.utils.cassandra.CassandraUtils; +import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.Property; + +public class DbUtils { + + private static String titanConfigFilePath; + private static TitanGraph titanGraph; + + + public static void cleanAllAudits() throws IOException { + CassandraUtils.truncateAllTables("sdcaudit"); + } + + public static RestResponse deleteFromEsDbByPattern(String patternToDelete) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_SEARCH_DATA_FROM_ES, config.getEsHost(), config.getEsPort(), + patternToDelete); + HttpRequest httpRequest = new HttpRequest(); + RestResponse restResponse = httpRequest.httpSendDelete(url, null); + restResponse.getErrorCode(); + cleanAllAudits(); + + return restResponse; + } + + public static RestResponse getFromEsByPattern(String patternToGet) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_SEARCH_DATA_FROM_ES, config.getEsHost(), config.getEsPort(), patternToGet); + HttpRequest httpRequest = new HttpRequest(); + RestResponse restResponse = httpRequest.httpSendGet(url, null); + restResponse.getErrorCode(); + + return restResponse; + } + + public Either getVertexByUId(String uid) { + TitanGraph titanGraph = getTitanGraph(); + Either result = Either.right(false); + // Iterator vertexItr = titanGraph.getVertices().iterator(); + + Iterator vertexItr = titanGraph.query().vertices().iterator(); + while (vertexItr.hasNext()) { + Vertex vertex = vertexItr.next(); + // String uidFoundVal = vertex.getProperty("uid"); + String uidFoundVal = vertex.value("uid"); + if (uid.equals(uidFoundVal)) { + result = Either.left(vertex); + } + } + return result; + } + + public static TitanState getCurrentTitanState() { + TitanGraph titanGraph = getTitanGraph(); + List vertices = new ArrayList<>(); + List edges = new ArrayList<>(); + // Iterator edgesItr = titanGraph.getEdges().iterator(); + Iterator edgesItr = titanGraph.query().edges().iterator(); + // Iterator verticesItr = titanGraph.getVertices().iterator(); + Iterator verticesItr = titanGraph.query().vertices().iterator(); + while (edgesItr.hasNext()) { + edges.add(edgesItr.next()); + } + while (verticesItr.hasNext()) { + vertices.add(verticesItr.next()); + } + + TitanState currState = new TitanState(edges, vertices); + return currState; + + } + + // + private static TitanGraph getTitanGraph() { + if (titanGraph == null) { + titanGraph = TitanFactory.open(titanConfigFilePath); + } + return titanGraph; + } + + public void restoreToTitanState(TitanState titanStateToRestoreTo) { + List verticesToRemove = new ArrayList<>(), verticesToAdd = new ArrayList<>(); + List edgesToRemove = new ArrayList<>(), edgesToAdd = new ArrayList<>(); + + TitanState currentTitanState = getCurrentTitanState(); + + List joinedEdges = new ArrayList<>(); + joinedEdges.addAll(titanStateToRestoreTo.edges); + joinedEdges.retainAll(currentTitanState.edges); + + List joinedVertices = new ArrayList<>(); + joinedVertices.addAll(titanStateToRestoreTo.vertices); + joinedVertices.retainAll(currentTitanState.vertices); + + edgesToRemove.addAll(currentTitanState.edges); + edgesToRemove.removeAll(joinedEdges); + + verticesToRemove.addAll(currentTitanState.vertices); + verticesToRemove.removeAll(joinedVertices); + + edgesToAdd.addAll(titanStateToRestoreTo.edges); + edgesToAdd.removeAll(joinedEdges); + + verticesToAdd.addAll(titanStateToRestoreTo.vertices); + verticesToAdd.removeAll(joinedVertices); + + modifyGraphAccordingToDelta(verticesToRemove, verticesToAdd, edgesToRemove, edgesToAdd); + + } + + private void modifyGraphAccordingToDelta(List verticesToRemove, List verticesToAdd, + List edgesToRemove, List edgesToAdd) { + + TitanGraph titanGraph = getTitanGraph(); + + for (Vertex vertex : verticesToRemove) { + // titanGraph.removeVertex(vertex); + vertex.remove(); + } + for (Vertex vertex : verticesToAdd) { + TitanVertex titanVertex = titanGraph.addVertex(); + copyProperties(vertex, titanVertex); + } + + for (Edge edge : edgesToRemove) { + // titanGraph.removeEdge(edge); + edge.remove(); + } + + for (Edge edge : edgesToAdd) { + // Element addedEdge = titanGraph.addEdge(edge.getId(), + // edge.getVertex(Direction.OUT), edge.getVertex(Direction.IN), + // edge.getLabel()); + + // Edge edge = tGraph.addEdge(null, fromV.left().value(), + // toV.left().value(), type); + + Element addedEdge = edge.outVertex().addEdge(edge.label(), edge.inVertex()); + + copyProperties(edge, addedEdge); + + } + + // titanGraph.commit(); + titanGraph.tx().commit(); + + } + + private void copyProperties(Element copyFrom, Element copyTo) { + // Set properties = copyFrom.getPropertyKeys(); + Set properties = copyFrom.keys(); + for (String propertyKey : properties) { + // copyTo.setProperty(propertyKey, + // copyFrom.getProperty(propertyKey)); + copyTo.property(propertyKey, copyFrom.value(propertyKey)); + } + + } + + public static class TitanState { + private List edges; + private List vertices; + + private TitanState(List edges, List vertices) { + this.edges = edges; + this.vertices = vertices; + } + + @Override + public String toString() { + return "TitanState [edges=" + edges.size() + ", vertices=" + vertices.size() + "]"; + } + + } + + public void shutDowntitan() { + if (titanGraph != null) { + // titanGraph.shutdown(); + titanGraph.close(); + } + } + + public static void setProperties(Element element, Map properties) { + + if (properties != null && false == properties.isEmpty()) { + + Object[] propertyKeyValues = new Object[properties.size() * 2]; + int i = 0; + for (Entry entry : properties.entrySet()) { + propertyKeyValues[i++] = entry.getKey(); + propertyKeyValues[i++] = entry.getValue(); + } + + ElementHelper.attachProperties(element, propertyKeyValues); + + } + + } + + public static UserAuditJavaObject parseAuditRespByAction(String action) throws Exception { + + // String index = "auditingevents*"; + // String type = "useradminevent"; + // String pattern = "/_search?q=action:\""+action+"\""; + // String auditingMessage = retrieveAuditMessageByIndexType(index, type, + // pattern); + UserAuditJavaObject auditParsedResp = new UserAuditJavaObject(); + Gson gson = new Gson(); + + String pattern = "/_search?q=ACTION:\"" + action + "\""; + String auditingMessage = retrieveAuditMessagesByPattern(pattern); + JsonElement jElement = new JsonParser().parse(auditingMessage); + JsonObject jObject = jElement.getAsJsonObject(); + JsonObject hitsObject = (JsonObject) jObject.get("hits"); + JsonArray hitsArray = (JsonArray) hitsObject.get("hits"); + // for (int i = 0; i < hitsArray.size();){ + if (hitsArray.size() == 0) { + return auditParsedResp; + } + JsonObject jHitObject = (JsonObject) hitsArray.get(0); + JsonObject jSourceObject = (JsonObject) jHitObject.get("_source"); + + auditParsedResp = gson.fromJson(jSourceObject, UserAuditJavaObject.class); + + return auditParsedResp; + + } + + public static String retrieveAuditMessagesByPattern(String pattern) throws IOException { + + Config config = Utils.getConfig(); + HttpRequest getAuditingMessage = new HttpRequest(); + String url = String.format(Urls.GET_SEARCH_DATA_FROM_ES, config.getEsHost(), config.getEsPort(), pattern); + RestResponse restResponse = getAuditingMessage.httpSendGet(url, null); + + return restResponse.getResponse(); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/Decoder.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/Decoder.java new file mode 100644 index 0000000000..7d90eb0b6d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/Decoder.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +import org.apache.commons.codec.binary.Base64; + +public class Decoder { + + public static String encode(byte[] byteArrayToEncode) { + + byte[] bytesEncoded = Base64.encodeBase64(byteArrayToEncode); + String strEncoded = new String(bytesEncoded); + return strEncoded; + } + + public static String decode(String strEncoded) throws IOException { + + byte[] byteDecoded = Base64.decodeBase64(strEncoded); + String decoded = new String(byteDecoded); + + return decoded; + + } + + public static String readFileToString(String file) throws IOException { + + BufferedReader reader = new BufferedReader(new FileReader(file)); + String line = null; + StringBuilder stringBuilder = new StringBuilder(); + String ls = System.getProperty("line.separator"); + + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + stringBuilder.append(ls); + } + reader.close(); + return stringBuilder.toString(); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/DistributionUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/DistributionUtils.java new file mode 100644 index 0000000000..4838d55a3d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/DistributionUtils.java @@ -0,0 +1,144 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils; + +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.ci.tests.datatypes.ServiceDistributionStatus; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; + + public class DistributionUtils { + + final static String serviceDistributionSuffix = "/sdc/v1/catalog/services/"; + + public static ServiceDistributionStatus getLatestServiceDistributionObject(Service service) throws IOException, ParseException { + ServiceDistributionStatus serviceDistributionStatus = null; + RestResponse distributionServiceList = ServiceRestUtils.getDistributionServiceList(service, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + Map serviveDistributionStatusMap = ResponseParser.convertServiceDistributionStatusToObject(distributionServiceList.getResponse()); + if(serviveDistributionStatusMap.size() != 0){ + serviceDistributionStatus = getLatestServiceDistributionObjectFromMap(serviveDistributionStatusMap); + return serviceDistributionStatus; + } + + return null; + } + + public static ServiceDistributionStatus getLatestServiceDistributionObjectFromMap(Map serviceDistributionStatusMap) { + + ServiceDistributionStatus serviceDistributionStatus = null; + if (serviceDistributionStatusMap.size() == 1 ){ + for (Entry entry : serviceDistributionStatusMap.entrySet()) { + return entry.getValue(); + } + } + else{ + serviceDistributionStatus = getFilteredServiceDistributionObject(serviceDistributionStatusMap); + } + + return serviceDistributionStatus; + } + + private static ServiceDistributionStatus getFilteredServiceDistributionObject(Map serviceDistributionStatusMap) { + + List list = new ArrayList(); + list.addAll(serviceDistributionStatusMap.keySet()); + Collections.sort(list); + return serviceDistributionStatusMap.get(list.get(list.size() - 1)); + } + + public static Map getArtifactsMapOfDistributedService(Service service) throws Exception{ + + Map expectedDistributionArtifactMap = new HashMap(); + expectedDistributionArtifactMap = addServiceDeploymentArtifactToMap(service, expectedDistributionArtifactMap); + expectedDistributionArtifactMap = addComponentInstancesDeploymentArtifactToMap(service, expectedDistributionArtifactMap); + + return expectedDistributionArtifactMap; + } + + + public static Map addServiceDeploymentArtifactToMap(Service service, Map distributionArtifactMap){ + + Map deploymentArtifacts = service.getDeploymentArtifacts(); + if (deploymentArtifacts != null && deploymentArtifacts.size() > 0){ + for(Entry artifact : deploymentArtifacts.entrySet()){ + String url = buildServiceDeploymentUrl(service, artifact.getValue().getArtifactName(), artifact.getValue().getArtifactUUID()); + distributionArtifactMap.put(artifact.getKey(), url); + } + } + + return distributionArtifactMap; + } + + private static String buildServiceDeploymentUrl(Service service, String artifactName, String artifactUUID) { +// format "/sdc/v1/catalog/services/" + service.getSystemName() + "/" + service.getVersion() + "/artifacts/AAI-" + service.getName() + "-service-1.xml" + return serviceDistributionSuffix + service.getSystemName() + "/" + service.getVersion() + "/artifacts/" + artifactName; + } + + public static String buildResourceInstanceDeploymentUrl(Service service, String artifactName, String artifactUUID){ + +// /sdc/v1/catalog/services/Servicefordistribution/1.0 /resourceInstances/nestedfrommarina2 /artifacts/FEAdd_On_Module_vProbeLauncher.yaml + String resourceInstanceNormalizedName = getResourceInstanceNormalizeName(service, artifactName, artifactUUID ); + return serviceDistributionSuffix + service.getSystemName() + "/" + service.getVersion() + "/resourceInstances/" + resourceInstanceNormalizedName +"/artifacts/" + artifactName; + } + + public static String getResourceInstanceNormalizeName(Service service, String artifactName, String artifactUUID) { + for (ComponentInstance componentInstance : service.getComponentInstances()){ + for(String key : componentInstance.getDeploymentArtifacts().keySet()){ + if(componentInstance.getDeploymentArtifacts().get(key).getArtifactUUID().equals(artifactUUID)) { + return componentInstance.getNormalizedName(); + } + } + } + return null; + } + + public static Map addComponentInstancesDeploymentArtifactToMap(Service service, Map distributionArtifactMap){ +// TODO Andrey create correct method to build RI url + if(service.getComponentInstances() != null && service.getComponentInstances().size() != 0){ + for(ComponentInstance componentInstance : service.getComponentInstances()){ + if (componentInstance.getDeploymentArtifacts() != null && componentInstance.getDeploymentArtifacts().size() != 0){ + for(Entry artifact : componentInstance.getDeploymentArtifacts().entrySet()){ + String url = buildResourceInstanceDeploymentUrl(service, artifact.getValue().getArtifactName(), artifact.getValue().getArtifactUUID());; + distributionArtifactMap.put(artifact.getKey(), url); + } + } + } + } + + return distributionArtifactMap; + } + + + } diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ReqCap.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ReqCap.java new file mode 100644 index 0000000000..3f000d750a --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ReqCap.java @@ -0,0 +1,630 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Function; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.Assert; + +public class ReqCap { + + public static Map> expectedContainerCapabilities; + public static Map> expectedContainerRequirements; + public static Map removedRequirements; + public static Map>, Map>>> expectedContInstReqCap; + + public static void verifyVFReqCap(String componentId) throws Exception { + RestResponse restResponse = ResourceRestUtils.getResource(componentId); + Resource resource = ResponseParser.parseToObject(restResponse.getResponse(), Resource.class); + verifyReqCap(resource); + } + + public static void verifyServiceReqCap(String componentId, User sdncDesignerDetails) throws Exception { + RestResponse restResponse = ServiceRestUtils.getService(componentId, sdncDesignerDetails); + Service service = ResponseParser.parseToObject(restResponse.getResponse(), Service.class); + verifyReqCap(service); + } + + public static void verifyProductReqCap(String componentId, User sdncPsDetails1) throws Exception { + RestResponse restResponse = ProductRestUtils.getProduct(componentId, sdncPsDetails1.getUserId()); + Product product = ResponseParser.parseToObject(restResponse.getResponse(), Product.class); + verifyReqCap(product); + } + + public static void verifyReqCap(Component actualComponent) { + verifyContainerReqCap(actualComponent); + verifyCompInstReqCap(actualComponent); + } + + public RestResponse changeServiceInstanceVersion(String componentUniqueId, String serviceInstanceToReplaceUniqueId, + String serviceUniqueId, User sdncModifierDetails, ComponentTypeEnum componentType, boolean isHighestLevel) + throws Exception { + RestResponse changeResourceInstanceVersion = ProductRestUtils.changeServiceInstanceVersion(componentUniqueId, + serviceInstanceToReplaceUniqueId, serviceUniqueId, sdncModifierDetails, componentType); + if (changeResourceInstanceVersion.getErrorCode().equals(BaseRestUtils.STATUS_CODE_SUCCESS) && isHighestLevel) { + /* + * // Add RI Capabilities and Requirements to expected MAP --> + * expectedVfCapabilities and expectedVfRequirements + * + * ComponentInstance componentInstance = + * ResponseParser.parseToObjectUsingMapper( + * changeResourceInstanceVersion.getResponse(), + * ComponentInstance.class); + * addCompInstReqCapToExpected(componentInstance, componentType); + */ + } + return changeResourceInstanceVersion; + } + + public static void updateExpectedReqCapAfterChangeLifecycleState(String oldContainerUniqueIdToReplace, + String newContainerUniqueId) { + + // Update of container req/cap + + Set compInstKeysToChange = new HashSet<>(); + + for (String expKey : expectedContainerCapabilities.keySet()) { + List expCapList = expectedContainerCapabilities.get(expKey); + for (CapabilityDefinition cap : expCapList) { + String ownerId = cap.getOwnerId(); + + if (ownerId.contains(oldContainerUniqueIdToReplace)) { + compInstKeysToChange.add(ownerId); + cap.setOwnerId(cap.getOwnerId().replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId)); + } + } + } + + for (String expKey : expectedContainerRequirements.keySet()) { + List expCapList = expectedContainerRequirements.get(expKey); + for (RequirementDefinition cap : expCapList) { + String ownerId = cap.getOwnerId(); + if (ownerId.contains(oldContainerUniqueIdToReplace)) { + compInstKeysToChange.add(ownerId); + cap.setOwnerId(cap.getOwnerId().replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId)); + } + } + } + + // Update of internal comp instances req/cap + for (String oldKey : compInstKeysToChange) { + ImmutablePair>, Map>> immutablePair = expectedContInstReqCap + .get(oldKey); + if (immutablePair != null) { + expectedContInstReqCap.remove(oldKey); + String newKey = oldKey.replaceAll(oldContainerUniqueIdToReplace, newContainerUniqueId); + expectedContInstReqCap.put(newKey, immutablePair); + } + } + } + + private static void verifyCompInstReqCap(Component actualComponent) { + List componentInstances = actualComponent.getComponentInstances(); + if (componentInstances != null) { + assertEquals(expectedContInstReqCap.size(), componentInstances.size()); + for (ComponentInstance compInst : componentInstances) { + String uniqueId = compInst.getUniqueId(); + // System.out.println("Verifying req/cap of component instance + // "+ uniqueId); + Map> actualCompInstReq = compInst.getRequirements(); + if (actualCompInstReq == null) { + actualCompInstReq = new HashMap<>(); + } + Map> actualCompInstCap = compInst.getCapabilities(); + if (actualCompInstCap == null) { + actualCompInstCap = new HashMap<>(); + } + ImmutablePair>, Map>> expReqCap = expectedContInstReqCap + .get(uniqueId); + assertNotNull(expReqCap); + // System.out.println("expected instance requirements: + // "+expReqCap.right); + // System.out.println("expected instance capabilities: + // "+expReqCap.left); + // System.out.println("actual instance requirements: + // "+actualCompInstReq); + // System.out.println("actual instance capabilities: + // "+actualCompInstCap); + + // REQ comparison + compareReqCapMaps(expReqCap.right, actualCompInstReq); + + // CAP comparison + compareReqCapMaps(expReqCap.left, actualCompInstCap); + } + + } else { + assertTrue(expectedContInstReqCap.isEmpty()); + } + } + + private static void verifyContainerReqCap(Component actualComponent) { + Map> actualContainerRequirements = actualComponent.getRequirements(); + if (actualContainerRequirements == null) { + actualContainerRequirements = new HashMap<>(); + } + Map> actualContainerCapabilities = actualComponent.getCapabilities(); + if (actualContainerCapabilities == null) { + actualContainerCapabilities = new HashMap<>(); + } + // System.out.println("Verifying req/cap of container component "+ + // actualComponent.getUniqueId()); + // System.out.println("expected container requirements: + // "+expectedContainerRequirements); + // System.out.println("expected container capabilities: + // "+expectedContainerCapabilities); + // System.out.println("actual container requirements: + // "+actualContainerRequirements); + // System.out.println("actual container capabilities: + // "+actualContainerCapabilities); + + // REQ comparison + compareReqCapMaps(expectedContainerRequirements, actualContainerRequirements); + + // CAP comparison + compareReqCapMaps(expectedContainerCapabilities, actualContainerCapabilities); + } + + private static void compareReqCapMaps(Map> expectedMap, Map> actualMap) { + assertEquals(expectedMap.size(), actualMap.size()); + for (String expKey : expectedMap.keySet()) { + List expCapList = expectedMap.get(expKey); + List actCapList = actualMap.get(expKey); + assertEquals(expCapList.size(), actCapList.size()); + assertEquals(new HashSet<>(expCapList), new HashSet<>(actCapList)); + } + } + + public static void addCompInstReqCapToExpected(ComponentInstance componentInstance, + ComponentTypeEnum containerComponentType, User sdncDesignerDetails) throws Exception { + + sdncDesignerDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String uniqueId = componentInstance.getUniqueId(); + String name = componentInstance.getName(); + String originComponentId = componentInstance.getComponentUid(); + RestResponse getResponse = null; + ComponentTypeEnum compInstType = getCompInstTypeByContainerType(containerComponentType); + Component component = null; + if (compInstType == ComponentTypeEnum.RESOURCE) { + getResponse = ResourceRestUtils.getResource(sdncDesignerDetails, originComponentId); + ResourceRestUtils.checkSuccess(getResponse); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Resource.class); + } else if (compInstType == ComponentTypeEnum.SERVICE) { + getResponse = ServiceRestUtils.getService(originComponentId, sdncDesignerDetails); + ResourceRestUtils.checkSuccess(getResponse); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Service.class); + } else { + Assert.fail("Unsupported type - " + containerComponentType); + } + + Map> resourceRequirements = component.getRequirements(); + if (resourceRequirements == null) { + resourceRequirements = new HashMap<>(); + } + + Function>, List> requirementDefinitionMapper = e -> new ArrayList<>(e.getValue().stream().map(item -> new RequirementDefinition(item)).collect(Collectors.toList())); + Map> reqCopy = resourceRequirements.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), requirementDefinitionMapper)); + + Map> resourceCapabilities = component.getCapabilities(); + if (resourceCapabilities == null) { + resourceCapabilities = new HashMap<>(); + } + + Function>, List> capabilityDefinitionMapper = e -> new ArrayList<>(e.getValue().stream().map(item -> new CapabilityDefinition(item)).collect(Collectors.toList())); + Map> capCopy = resourceCapabilities.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), capabilityDefinitionMapper)); + + setupContainerExpectedReqCap(uniqueId, name, resourceRequirements, resourceCapabilities); + if (component.getComponentType().equals(ComponentTypeEnum.RESOURCE) + && ((Resource) component).getResourceType() != ResourceTypeEnum.VF) { + setupConstInstExpectedReqCap(uniqueId, name, reqCopy, capCopy); + } + + // adding entry for expected componentInstance + ImmutablePair>, Map>> compInstReqCapPair = new ImmutablePair>, Map>>( + capCopy, reqCopy); + expectedContInstReqCap.put(uniqueId, compInstReqCapPair); + } + + private static void setupContainerExpectedReqCap(String uniqueId, String name, + Map> componentRequirements, + Map> componentCapabilities) { + for (Entry> resReq : componentRequirements.entrySet()) { + List reqListToAdd = resReq.getValue(); + for (RequirementDefinition requirementDefinition : reqListToAdd) { + requirementDefinition.setOwnerId(uniqueId); + requirementDefinition.setOwnerName(name); + } + List expectedReqList = expectedContainerRequirements.get(resReq.getKey()); + if (expectedReqList == null) { + expectedReqList = reqListToAdd; + } else { + expectedReqList.addAll(reqListToAdd); + } + expectedContainerRequirements.put(resReq.getKey(), expectedReqList); + } + + for (Entry> resCap : componentCapabilities.entrySet()) { + List capListToAdd = resCap.getValue(); + for (CapabilityDefinition capDefinition : capListToAdd) { + capDefinition.setOwnerId(uniqueId); + capDefinition.setOwnerName(name); + } + List expectedCapList = expectedContainerCapabilities.get(resCap.getKey()); + if (expectedCapList == null) { + expectedCapList = capListToAdd; + } else { + expectedCapList.addAll(capListToAdd); + } + expectedContainerCapabilities.put(resCap.getKey(), expectedCapList); + } + } + + private static void setupConstInstExpectedReqCap(String uniqueId, String name, + Map> componentRequirements, + Map> componentCapabilities) { + for (Entry> resReq : componentRequirements.entrySet()) { + List reqListToAdd = resReq.getValue(); + for (RequirementDefinition requirementDefinition : reqListToAdd) { + requirementDefinition.setOwnerId(uniqueId); + requirementDefinition.setOwnerName(name); + } + } + + for (Entry> resCap : componentCapabilities.entrySet()) { + List capListToAdd = resCap.getValue(); + for (CapabilityDefinition capDefinition : capListToAdd) { + capDefinition.setOwnerId(uniqueId); + capDefinition.setOwnerName(name); + } + } + } + + private static ComponentTypeEnum getCompInstTypeByContainerType(ComponentTypeEnum componentType) { + switch (componentType) { + case RESOURCE: + return ComponentTypeEnum.RESOURCE; + case SERVICE: + return ComponentTypeEnum.RESOURCE; + case PRODUCT: + return ComponentTypeEnum.SERVICE; + default: + break; + } + return null; + } + + public static void deleteCompInstReqCapFromExpected(String componentInstanceId) { + List entriesRequirementsToRemove = new ArrayList<>(); + List entriesCapabilitiesToRemove = new ArrayList<>(); + for (Entry> reqEntry : expectedContainerRequirements.entrySet()) { + List reqList = reqEntry.getValue(); + List reqListToDelete = new ArrayList<>(); + for (RequirementDefinition requirementDefinition : reqList) { + if (requirementDefinition.getOwnerId().equals(componentInstanceId)) { + reqListToDelete.add(requirementDefinition); + } + } + reqList.removeAll(reqListToDelete); + if (reqList.isEmpty()) { + entriesRequirementsToRemove.add(reqEntry.getKey()); + } + } + + for (String ekey : entriesRequirementsToRemove) { + expectedContainerRequirements.remove(ekey); + } + + for (Entry> capEntry : expectedContainerCapabilities.entrySet()) { + List capList = capEntry.getValue(); + List capListToDelete = new ArrayList<>(); + for (CapabilityDefinition capabilityDefinition : capList) { + if (capabilityDefinition.getOwnerId().equals(componentInstanceId)) { + capListToDelete.add(capabilityDefinition); + } + } + capList.removeAll(capListToDelete); + if (capList.isEmpty()) { + entriesCapabilitiesToRemove.add(capEntry.getKey()); + } + } + for (String ekey : entriesCapabilitiesToRemove) { + expectedContainerCapabilities.remove(ekey); + } + + expectedContInstReqCap.remove(componentInstanceId); + + } + + // Automatically updates the expected req/cap of the container + public static RestResponse createAtomicInstanceForVF(Resource containerDetails, Resource compInstOriginDetails, + User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.RESOURCE, + true); + } + + // Automatically updates the expected req/cap of the container + public static RestResponse createAtomicInstanceForService(Service containerDetails, Resource compInstOriginDetails, + User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, + true); + } + + // Automatically updates the expected req/cap of the container + public static RestResponse createVFInstance(Service containerDetails, Resource compInstOriginDetails, User modifier) + throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, + true); + } + + // Automatically updates the expected req/cap of the container + public static RestResponse createServiceInstance(Product containerDetails, Service compInstOriginDetails, + User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.PRODUCT, + true); + } + + // Automatically updates the expected req/cap of the container + public static RestResponse deleteAtomicInstanceForVF(String compInstUniqueId, Resource containerDetails, + User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.RESOURCE, true); + } + + // Automatically updates the expected req/cap of the container + public static RestResponse deleteAtomicInstanceForService(String compInstUniqueId, Service containerDetails, + User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.SERVICE, true); + } + + // Automatically updates the expected req/cap of the container + public static RestResponse deleteVFInstance(String compInstUniqueId, Service containerDetails, User modifier) + throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.SERVICE, true); + + } + + // Automatically updates the expected req/cap of the container + public static RestResponse deleteServiceInstance(String compInstUniqueId, Product containerDetails, User modifier) + throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.PRODUCT, true); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + public static RestResponse createAtomicInstanceForVFDuringSetup(Resource containerDetails, + Resource compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.RESOURCE, + false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + public static RestResponse createAtomicInstanceForServiceDuringSetup(Service containerDetails, + Resource compInstOriginDetails, User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, + false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + public static RestResponse createVFInstanceDuringSetup(Service containerDetails, Resource compInstOriginDetails, + User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.SERVICE, + false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + public static RestResponse createServiceInstanceDuringSetup(Product containerDetails, Service compInstOriginDetails, + User modifier) throws Exception { + return createComponentInstance(containerDetails, compInstOriginDetails, modifier, ComponentTypeEnum.PRODUCT, + false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + public static RestResponse deleteAtomicInstanceForVFDuringSetup(String compInstUniqueId, Resource containerDetails, + User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.RESOURCE, false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + public static RestResponse deleteAtomicInstanceForServiceDuringSetup(String compInstUniqueId, + Service containerDetails, User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.SERVICE, false); + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + public static RestResponse deleteVFInstanceDuringSetup(String compInstUniqueId, Service containerDetails, + User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.SERVICE, false); + + } + + // Setup of lower components - Doesn't affect req/cap of the container (for + // example, setup of VF for testing a Product) + public static RestResponse deleteServiceInstanceDuringSetup(String compInstUniqueId, Product containerDetails, + User modifier) throws IOException, Exception { + return deleteComponentInstance(compInstUniqueId, containerDetails, modifier, ComponentTypeEnum.PRODUCT, false); + } + + public static Component getComponentAndValidateRIs(Component componentDetails, int numberOfRIs, + int numberOfRelations, User sdncAdminDetails) throws IOException, Exception { + + RestResponse getResponse = null; + Component component = null; + if (componentDetails instanceof Resource) { + getResponse = ResourceRestUtils.getResource(sdncAdminDetails, componentDetails.getUniqueId()); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Resource.class); + } else if (componentDetails instanceof Service) { + getResponse = ServiceRestUtils.getService((componentDetails.getUniqueId()), sdncAdminDetails); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Service.class); + } else if (componentDetails instanceof Product) { + getResponse = ProductRestUtils.getProduct(componentDetails.getUniqueId(), sdncAdminDetails.getUserId()); + component = ResponseParser.parseToObjectUsingMapper(getResponse.getResponse(), Product.class); + } else { + Assert.fail("Unsupported type of componentDetails - " + componentDetails.getClass().getSimpleName()); + } + ResourceRestUtils.checkSuccess(getResponse); + int numberOfActualRIs = component.getComponentInstances() != null ? component.getComponentInstances().size() + : 0; + int numberOfActualRelations = component.getComponentInstancesRelations() != null + ? component.getComponentInstancesRelations().size() : 0; + assertEquals("Check number of RIs meet the expected number", numberOfRIs, numberOfActualRIs); + assertEquals("Check number of RI relations meet the expected number", numberOfRelations, + numberOfActualRelations); + verifyReqCap(component); + + return component; + } + + public static void getComponentAndValidateRIsAfterChangeLifecycleState(String oldComponentUniqueIdToReplace, + Component componentDetails, int numOfRIs, int numOfRelations, User sdncAdminDetails) + throws IOException, Exception { + updateExpectedReqCapAfterChangeLifecycleState(oldComponentUniqueIdToReplace, componentDetails.getUniqueId()); + getComponentAndValidateRIs(componentDetails, numOfRIs, numOfRelations, sdncAdminDetails); + } + + private static RestResponse createComponentInstance(Component containerDetails, Component compInstOriginDetails, + User modifier, ComponentTypeEnum containerComponentTypeEnum, boolean isHighestLevel) + throws IOException, Exception { + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentInstance(compInstOriginDetails); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, modifier, containerDetails.getUniqueId(), containerComponentTypeEnum); + if (createResourceInstanceResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_CREATED) && isHighestLevel) { + // Add RI Capabilities and Requirements to expected MAP --> + // expectedVfCapabilities and expectedVfRequirements + ComponentInstance componentInstance = ResponseParser + .parseToObjectUsingMapper(createResourceInstanceResponse.getResponse(), ComponentInstance.class); + addCompInstReqCapToExpected(componentInstance, containerComponentTypeEnum, modifier); + } + return createResourceInstanceResponse; + } + + private static RestResponse deleteComponentInstance(String compInstUniqueId, Component containerDetails, + User modifier, ComponentTypeEnum componentTypeEnum, boolean isHighestLevel) throws Exception { + RestResponse deleteResourceInstanceResponse = ComponentInstanceRestUtils.deleteComponentInstance(modifier, + containerDetails.getUniqueId(), compInstUniqueId, componentTypeEnum); + if (deleteResourceInstanceResponse.getErrorCode().equals(BaseRestUtils.STATUS_CODE_DELETE) && isHighestLevel) { + deleteCompInstReqCapFromExpected(compInstUniqueId); + } + return deleteResourceInstanceResponse; + } + + public static RestResponse associateComponentInstancesForService(RequirementCapabilityRelDef requirementDef, + ComponentReqDetails containerDetails, User user) throws IOException { + + RestResponse associateInstances = ComponentInstanceRestUtils.associateInstances(requirementDef, user, + containerDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(associateInstances); + deleteAssociatedFromExpected(requirementDef); + return associateInstances; + } + + private static void deleteAssociatedFromExpected(RequirementCapabilityRelDef requirementDef) { + // removing from requirements + RequirementAndRelationshipPair relationship = requirementDef.getRelationships().get(0); + String type = relationship.getRelationship().getType(); + String fromId = requirementDef.getFromNode(); + List reqList = expectedContainerRequirements.get(type); + RequirementDefinition toDelete = null; + if (reqList != null) { + for (RequirementDefinition reqDef : reqList) { + if (reqDef.getOwnerId().equals(fromId)) { + toDelete = reqDef; + } + } + if (toDelete != null) { + reqList.remove(toDelete); + if (reqList.isEmpty()) { + expectedContainerRequirements.remove(type); + } + removedRequirements.put(toDelete.getCapability() + " " + toDelete.getOwnerId(), toDelete); + } + } + } + + public static void dissociateComponentInstancesForService(RequirementCapabilityRelDef requirementDef, + ComponentReqDetails containerDetails, User user) throws IOException { + + RestResponse dissociateInstances = ComponentInstanceRestUtils.dissociateInstances(requirementDef, user, + containerDetails.getUniqueId(), ComponentTypeEnum.SERVICE); + ResourceRestUtils.checkSuccess(dissociateInstances); + addDissociatedToExpected(requirementDef); + } + + private static void addDissociatedToExpected(RequirementCapabilityRelDef requirementDef) { + // adding to requirements + RequirementAndRelationshipPair relationship = requirementDef.getRelationships().get(0); + String type = relationship.getRelationship().getType(); + String fromId = requirementDef.getFromNode(); + String key = type + " " + fromId; + RequirementDefinition requirementDefinition = removedRequirements.get(key); + if (requirementDefinition != null) { + List reqList = expectedContainerRequirements.get(type); + if (reqList == null) { + reqList = new ArrayList<>(); + expectedContainerRequirements.put(type, reqList); + } + reqList.add(requirementDefinition); + } + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ToscaParserUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ToscaParserUtils.java new file mode 100644 index 0000000000..26fac7fd6e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/ToscaParserUtils.java @@ -0,0 +1,361 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils; + +import static org.testng.AssertJUnit.assertNotNull; + +import java.io.File; +import java.io.FileInputStream; +import java.util.Map; +import java.util.Set; + +import org.openecomp.sdc.ci.tests.datatypes.enums.ToscaKeysEnum; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaDefinition; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaGroupsTopologyTemplateDefinition; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaNodeTemplatesTopologyTemplateDefinition; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaSubstitutionMappingsDefinition; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaTopologyTemplateDefinition; +import org.openecomp.sdc.ci.tests.utils.validation.CsarValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.TypeDescription; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.constructor.Constructor; +import org.yaml.snakeyaml.introspector.PropertyUtils; + +public class ToscaParserUtils { + + private static Logger log = LoggerFactory.getLogger(ToscaParserUtils.class.getName()); + + public static ToscaDefinition parseToscaYamlToJavaObject(String csarUUID) throws Exception { + + ToscaDefinition toscaDefinition = null; + String TOSCAMetaLocation = "TOSCA-Metadata/TOSCA.meta"; + Map map = getToscaYamlMap(csarUUID, TOSCAMetaLocation); + assertNotNull("Tosca Entry-Definitions is null", map); + if (map != null) { + File definitionYamlLocation = (File) map.get("Entry-Definitions"); + toscaDefinition = parseToscaYamlToJavaObject(definitionYamlLocation); + } + return toscaDefinition; + + } + + public static ToscaDefinition parseToscaYamlToJavaObject(File path) throws Exception { + + ToscaDefinition toscaDefinition = null; + +// File path = new File("C:/Data/D2.0/TOSCA_Ex/Definitions/tosca_definition_version.yaml"); + FileInputStream fis = null; + try { + fis = new FileInputStream(path); + + } catch (Exception e) { + System.out.println("Exception: " + e); + } + + Constructor constructor = getConstructor(); + + Yaml yaml = new Yaml(constructor); + try { + toscaDefinition = (ToscaDefinition) yaml.load(fis); + } catch (Exception e) { + log.debug("Failed to parse tosca yaml file"); + System.out.println("Exception: " + e); + } finally { + fis.close(); + } + return toscaDefinition; + + } + + public static ToscaDefinition parseToscaYamlPayloadToJavaObject(String payload){ + + ToscaDefinition toscaDefinition = null; + Constructor constructor = getConstructor(); + + Yaml yaml = new Yaml(constructor); + try { + toscaDefinition = (ToscaDefinition) yaml.load(payload); + } catch (Exception e) { + log.debug("Failed to parse tosca yaml file"); + System.out.println("Exception: " + e); + } + return toscaDefinition; + + } + + + public static Constructor getConstructor() { + Constructor constructor = new Constructor(ToscaDefinition.class); + constructor.addTypeDescription(ToscaDefinition.getTypeDescription()); + constructor.addTypeDescription(ToscaTopologyTemplateDefinition.getTypeDescription()); + constructor.addTypeDescription(ToscaNodeTemplatesTopologyTemplateDefinition.getTypeDescription()); + constructor.addTypeDescription(ToscaGroupsTopologyTemplateDefinition.getTypeDescription()); + constructor.addTypeDescription(ToscaSubstitutionMappingsDefinition.getTypeDescription()); + +// Skip properties which are found in YAML, but not found in POJO + PropertyUtils propertyUtils = new PropertyUtils(); + propertyUtils.setSkipMissingProperties(true); + constructor.setPropertyUtils(propertyUtils); + return constructor; + } + + public static Map getToscaYamlMap(String csarUUID, String fileLocation) throws Exception { + String csarPayload = CsarValidationUtils.getCsarPayload(csarUUID, fileLocation); + if (csarPayload != null) { + Yaml yaml = new Yaml(); + Map map = (Map) yaml.load(csarPayload); + return map; + } + return null; + } + +/* public static Map getToscaYamlMap(String csarUUID, String fileLocation) throws Exception { + String csarPayload = CsarValidationUtils.getCsarPayload(csarUUID, fileLocation); + if (csarPayload != null) { + Yaml yaml = new Yaml(); + Map map = (Map) yaml.load(csarPayload); + return map; + } + return null; + } + + public static ToscaDefinition getToscaDefinitionObjectByCsarUuid(String csarUUID) throws Exception { + + String TOSCAMetaLocation = "TOSCA-Metadata/TOSCA.meta"; + Map map = getToscaYamlMap(csarUUID, TOSCAMetaLocation); + assertNotNull("Tosca Entry-Definitions is null", map); + if (map != null) { + String definitionYamlLocation = (String) map.get("Entry-Definitions"); + Map toscaMap = getToscaYamlMap(csarUUID, definitionYamlLocation); + assertNotNull("Tosca definition is null", toscaMap); + if (toscaMap != null) { + ToscaDefinition toscaDefinition = new ToscaDefinition(); + Set keySet = toscaMap.keySet(); + for (Object key : keySet) { + ToscaKeysEnum toscaKey = ToscaKeysEnum.findToscaKey((String) key); + switch (toscaKey) { + case TOSCA_DEFINITION_VERSION: + getToscaDefinitionVersion(toscaMap, toscaDefinition); + break; + case NODE_TYPES: + getToscaNodeTypes(toscaMap, toscaDefinition); + break; + case TOPOLOGY_TEMPLATE: + getToscaTopologyTemplate(toscaMap, toscaDefinition); + break; + case IMPORTS: + // toscaMap.get("imports"); + break; + default: + break; + } + } + return toscaDefinition; + } + } + return null; + + } + + public static void getToscaDefinitionVersion(Map toscaMap, ToscaDefinition toscaDefinition) { + if (toscaMap.get("tosca_definitions_version") != null) { + toscaDefinition.setTosca_definitions_version((String) toscaMap.get("tosca_definitions_version")); + } + } + + // spec 90 page + public static void getToscaNodeTypes(Map toscaMap, ToscaDefinition toscaDefinition) { + @SuppressWarnings("unchecked") + Map> nodeTypes = (Map>) toscaMap.get("node_types"); + Map listToscaNodeTypes = new HashMap(); + if (nodeTypes != null) { + for (Map.Entry> entry : nodeTypes.entrySet()) { + ToscaNodeTypesDefinition toscaNodeTypes = new ToscaNodeTypesDefinition(); + String toscaNodeName = entry.getKey(); + toscaNodeTypes.setName(toscaNodeName); + + Map toscaNodeType = entry.getValue(); + if (toscaNodeType != null) { + Set> entrySet = toscaNodeType.entrySet(); + if (entrySet != null) { + // boolean found = false; + for (Entry toscaNodeTypeMap : entrySet) { + String key = toscaNodeTypeMap.getKey(); + if (key.equals("derived_from")) { + String derivedFrom = toscaNodeTypeMap.getValue(); + toscaNodeTypes.setDerived_from(derivedFrom); + // found = true; + break; + } else { + continue; + } + + } + // if (found == false) { + // System.out.println("Tosca file not valid, + // derived_from not found"); + // } + } + + } +// listToscaNodeTypes.add(toscaNodeTypes); + listToscaNodeTypes.put(toscaNodeName, toscaNodeTypes); + } + toscaDefinition.setNode_types(listToscaNodeTypes); + } + } + + public static void getToscaTopologyTemplate(Map toscaMap, ToscaDefinition toscaDefinition) { + ToscaTopologyTemplateDefinition toscaTopologyTemplate = new ToscaTopologyTemplateDefinition(); + @SuppressWarnings("unchecked") + Map> topologyTemplateMap = (Map>) toscaMap.get("topology_template"); +// List listToscaNodeTemplates = new ArrayList<>(); + Map mapToscaNodeTemplates = new HashMap(); + + if (topologyTemplateMap != null) { + getToscaNodeTemplates(topologyTemplateMap, mapToscaNodeTemplates); + } +// toscaTopologyTemplate.setToscaNodeTemplatesTopologyTemplateDefinition(listToscaNodeTemplates); + toscaTopologyTemplate.setNode_templates(mapToscaNodeTemplates); + toscaDefinition.setTopology_template(toscaTopologyTemplate); + } + + public static void getToscaNodeTemplates(Map> topologyTemplateMap, Map mapToscaNodeTemplates) { + Map nodeTemplatesMap = topologyTemplateMap.get("node_templates"); + if (nodeTemplatesMap != null) { + + for (Entry nodeTemplates : nodeTemplatesMap.entrySet()) { + ToscaNodeTemplatesTopologyTemplateDefinition toscaNodeTemplates = new ToscaNodeTemplatesTopologyTemplateDefinition(); + getToscaNodeTemplatesName(nodeTemplates, toscaNodeTemplates); + + @SuppressWarnings("unchecked") + Map node = (Map) nodeTemplates.getValue(); + getNodeTemplatesType(toscaNodeTemplates, node); + getToscaNodeTemplateProperties(toscaNodeTemplates, node); + getToscaNodeTemplateRequirements(toscaNodeTemplates, node); + mapToscaNodeTemplates.putAll(mapToscaNodeTemplates); + } + } + } + + public static void getToscaNodeTemplateRequirements(ToscaNodeTemplatesTopologyTemplateDefinition toscaNodeTemplates, Map node) { +//// List toscaRequirements = new ArrayList<>(); +// List> toscaRequirements = new ArrayList<>(); +// if (node.get("requirements") != null) { +// @SuppressWarnings("unchecked") +// List> requirementList = (List>) node.get("requirements"); +// for (int i = 0; i < requirementList.size(); i++) { +// for (Map.Entry requirement : requirementList.get(i).entrySet()) { +// ToscaRequirementsNodeTemplatesDefinition toscaRequirement = new ToscaRequirementsNodeTemplatesDefinition(); +// if (requirement.getKey() != null) { +// String requirementName = requirement.getKey(); +// toscaRequirement.setName(requirementName); +// } else { +// log.debug("Tosca file not valid, requirements should contain name"); +// } +// +// @SuppressWarnings("unchecked") +// Map requirementMap = (Map) requirement.getValue(); +// Set> entrySet = requirementMap.entrySet(); +// if (entrySet != null) { +// for (Entry requirementField : entrySet) { +// String key = requirementField.getKey(); +// switch (key) { +// case "capability": +// if (requirementMap.get(key) != null) { +// String capability = (String) requirementMap.get(key); +// toscaRequirement.setCapability(capability); +// break; +// } else { +// continue; +// } +// case "node": +// if (requirementMap.get(key) != null) { +// String requirementNode = (String) requirementMap.get(key); +// toscaRequirement.setNode(requirementNode); +// break; +// } else { +// continue; +// } +// case "relationship": +// if (requirementMap.get(key) != null) { +// String relationship = (String) requirementMap.get(key); +// toscaRequirement.setRelationship(relationship); +// break; +// } else { +// continue; +// } +// default: +// break; +// } +// } +// } +//// toscaRequirements.add(toscaRequirement); +// toscaRequirements.add(requirementMap); +// } +// } +// } +//// toscaNodeTemplates.setRequirements(toscaRequirements); +// toscaNodeTemplates.setRequirements(requirements); + + } + + public static void getToscaNodeTemplateProperties(ToscaNodeTemplatesTopologyTemplateDefinition toscaNodeTemplates, + Map node) { +// List listToscaProperties = new ArrayList<>(); + Map mapToscaProperties = new HashMap<>(); + if (node.get("properties") != null) { + @SuppressWarnings("unchecked") + Map properties = (Map) node.get("properties"); + for (Map.Entry property : properties.entrySet()) { + ToscaPropertiesNodeTemplatesDefinition toscaProperty = new ToscaPropertiesNodeTemplatesDefinition(); + String propertyName = property.getKey(); + Object propertyValue = property.getValue(); + toscaProperty.setName(propertyName); + toscaProperty.setValue(propertyValue); +// mapToscaProperties.add(toscaProperty); + mapToscaProperties.put(propertyName, propertyValue); + } + } + toscaNodeTemplates.setProperties(mapToscaProperties); + } + + protected static void getNodeTemplatesType(ToscaNodeTemplatesTopologyTemplateDefinition toscaNodeTemplates, + Map node) { + if (node.get("type") != null) { + String type = (String) node.get("type"); + toscaNodeTemplates.setType(type); + } else { + log.debug("Tosca file not valid, nodeTemplate should contain type"); + } + } + + protected static void getToscaNodeTemplatesName(Entry nodeTemplates, + ToscaNodeTemplatesTopologyTemplateDefinition toscaNodeTemplates) { + String name = nodeTemplates.getKey(); + toscaNodeTemplates.setName(name); + }*/ + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/Utils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/Utils.java new file mode 100644 index 0000000000..3515191433 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/Utils.java @@ -0,0 +1,689 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; +import org.apache.log4j.Logger; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.common.api.ToscaNodeTypeInfo; +import org.openecomp.sdc.common.api.YamlConstants; +import org.yaml.snakeyaml.Yaml; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public final class Utils { + + Gson gson = new Gson(); + + static Logger logger = Logger.getLogger(Utils.class.getName()); + + String contentTypeHeaderData = "application/json"; + String acceptHeaderDate = "application/json"; + + public Utils() { + /* + * super(); + * + * StartTest.enableLogger(); logger = + * Logger.getLogger(Utils.class.getName()); + */ + + } + + // public String serviceTopologyPattern = "/topology/topology/%s"; + // public String serviceTopologyTemplatePattern = + // "/topologytemplate/topologytemplate/%s"; + // + // public String serviceTopologySearchPattern = + // "topology/topology/_search?q=%s"; + // public String serviceTopologyTemplateSearchPattern = + // "topologytemplate/topologytemplate/_search?q=%s"; + // + // public ArtifactTypeEnum getFileTypeByExtension(String fileName) { + // + // String fileExtension = null; + // if (fileName.matches("(.*)\\.(.*)")) { + // System.out.println(fileName.substring(fileName.lastIndexOf(".") + 1)); + // fileExtension = fileName.substring(fileName.lastIndexOf(".") + 1); + // } + // + // switch (fileExtension) { + // case "sh": + // return ArtifactTypeEnum.SHELL_SCRIPT; + // case "png": + // return ArtifactTypeEnum.ICON; + // case "ppp": + // return ArtifactTypeEnum.PUPPET; + // case "yang": + // return ArtifactTypeEnum.YANG; + // default: + // return ArtifactTypeEnum.UNKNOWN; + // } + // + // } + // + // public ArrayList getScriptList (List + // artifactsList){ + // + // ArrayList scriptNameArray = new ArrayList<>(); + // if (artifactsList != null){ + // for (UploadArtifactInfo fileInArtifactsList : artifactsList){ + // String artifactFileName = fileInArtifactsList.getArtifactName(); + // ArtifactTypeEnum artifactFileType = + // fileInArtifactsList.getArtifactType(); + // if (! artifactFileType.equals(ArtifactTypeEnum.ICON)){ + // scriptNameArray.add(artifactFileName); + // } + // continue; + // } + // return scriptNameArray; + // } + // return null; + // } + // + // + // public String getYamlFileLocation(File testResourcesPath) { + // File[] files = testResourcesPath.listFiles(); + // if (files.length == 0){ + // return null; + // }else{ + // for (int i = 0; i < files.length; i++){ + // if (files[i].isFile()){ + // return files[i].getAbsoluteFile().toString(); + // } + // } + // } + // return null; + // } + // + // public String readFileContentToString (String fileName) throws + // IOException { + // + // Path path = Paths.get(fileName); + // String stringFromFile = new String(Files.readAllBytes(path)); + // return stringFromFile; + // + // + // } + // + @SuppressWarnings("unchecked") + public ToscaNodeTypeInfo parseToscaNodeYaml(String fileContent) { + + ToscaNodeTypeInfo result = new ToscaNodeTypeInfo(); + Object templateVersion = null; + Object templateName = null; + + if (fileContent != null) { + Yaml yaml = new Yaml(); + + Map yamlObject = (Map) yaml.load(fileContent); + + templateVersion = yamlObject.get(YamlConstants.TEMPLATE_VERSION); + if (templateVersion != null) { + result.setTemplateVersion(templateVersion.toString()); + } + templateName = yamlObject.get(YamlConstants.TEMPLATE_NAME); + if (templateName != null) { + result.setTemplateName(templateName.toString()); + } + Object nodeTypes = yamlObject.get(YamlConstants.NODE_TYPES); + + if (nodeTypes != null) { + Map nodeTypesMap = (Map) nodeTypes; + for (Entry entry : nodeTypesMap.entrySet()) { + + String nodeName = entry.getKey(); + if (nodeName != null) { + result.setNodeName(nodeName); + } + + break; + + } + } + + } + + return result; + } + + // + // + // public ArtifactsMetadata getArtifactsMetadata(String response){ + // ArtifactsMetadata artifactsMetadata = new ArtifactsMetadata(); + // + // artifactsMetadata.setId(getJsonObjectValueByKey(response, "id")); + // artifactsMetadata.setName(getJsonObjectValueByKey(response, "name")); + // artifactsMetadata.setType(getJsonObjectValueByKey(response, "type")); + // + // artifactsMetadata.setCreator(getJsonObjectValueByKey(response, + // "creator")); + // artifactsMetadata.setCreationTime(getJsonObjectValueByKey(response, + // "creationTime")); + // artifactsMetadata.setLastUpdateTime(getJsonObjectValueByKey(response, + // "lastUpdateTime")); + // artifactsMetadata.setChecksum(getJsonObjectValueByKey(response, + // "checksum")); + // artifactsMetadata.setDescription(getJsonObjectValueByKey(response, + // "description")); + // artifactsMetadata.setLastUpdater(getJsonObjectValueByKey(response, + // "lastUpdater")); + // + // return artifactsMetadata; + // } + // + public static String getJsonObjectValueByKey(String metadata, String key) { + JsonElement jelement = new JsonParser().parse(metadata); + + JsonObject jobject = jelement.getAsJsonObject(); + Object obj = jobject.get(key); + if (obj == null) { + return null; + } else { + String value; + value = (String) jobject.get(key).getAsString(); + return value; + } + } + + public static Config getConfig() throws FileNotFoundException { + Config config = Config.instance(); + return config; + } + + // public void uploadNormativeTypes() throws IOException{ + // Config config = getConfig(); + // String[] normativeTypes = {"root", "compute", "blockStorage", + // "softwareComponent", "DBMS", "database", "network", "objectStorage", + // "webServer", "webApplication"}; + // for( String normativeType : normativeTypes ){ + // uploadComponent(config.getComponentsConfigDir()+File.separator+"normativeTypes"+File.separator+normativeType); + // } + // + // } + // + // public void uploadApacheComponent() throws IOException{ + // Config config = getConfig(); + // uploadComponent(config.getComponentsConfigDir()+File.separator+"apache"); + // } + // + // public void uploadComponent(String componentDir) throws IOException{ + // + // //*********************************************upload************************************************************* + // Config config = getConfig(); + // ZipDirectory zipDirectory = new ZipDirectory(); + // System.out.println(config.getEsHost()); + // + // List artifactsList = new + // ArrayList(); + // + //// read test resources and zip it as byte array + // byte[] zippedAsByteArray = zipDirectory.zip(componentDir, artifactsList); + // + //// encode zipped directory using base64 + // String payload = Decoder.encode(zippedAsByteArray); + // + //// zip name build as testName with ".zip" extension + // String payloadZipName = getPayloadZipName(componentDir); + // + //// build json + // UploadResourceInfo resourceInfo = new UploadResourceInfo(payload, + // payloadZipName, "description", "category/mycategory", null, + // artifactsList); + // String json = new Gson().toJson(resourceInfo); + // + //// calculate md5 on the content of json + // String jsonMd5 = + // org.apache.commons.codec.digest.DigestUtils.md5Hex(json); + // + //// encode the md5 to base64, sent as header in post http request + // String encodedMd5 = Decoder.encode(jsonMd5.getBytes()); + // + //// upload component to Elastic Search DB + // String url = null; + // HttpRequest http = new HttpRequest(); + // + // url = String.format(Urls.UPLOAD_ZIP_URL, config.getCatalogFeHost(), + // config.getCatalogFePort()); + // + //// Prepare headers to post upload component request + // HeaderData headerData = new HeaderData(encodedMd5, "application/json", + // "att", "test", "testIvanovich", "RoyalSeal", "Far_Far_Away", + // "getResourceArtifactListTest"); + // + // MustHeaders headers = new MustHeaders(headerData); + // System.out.println("headers:"+headers.getMap()); + // + // RestResponse response = http.httpSendPost(url, json, headers.getMap()); + // + // assertEquals("upload component failed with code " + + // response.getErrorCode().intValue(),response.getErrorCode().intValue(), + // 204); + // } + // + // private String getPayloadZipName(String componentDir) { + // String payloadName; + // if( componentDir.contains( File.separator) ){ + // String delimiter = null; + // if( File.separator.equals("\\")){ + // delimiter ="\\\\"; + // } + // else{ + // delimiter = File.separator; + // } + // String[] split = componentDir.split(delimiter); + // payloadName = split[split.length-1]; + // } + // else{ + // payloadName = componentDir; + // } + // return payloadName+".zip"; + // } + // + // + // + // public List createArtifactsList(String srcDir) { + // + // List artifactsList = new + // ArrayList(); + // File srcFile = new File(srcDir); + // addFileToList(srcFile, artifactsList); + // + // return artifactsList; + // } + // + // public void addFileToList(File srcFile, List + // artifactsList) { + // + // File[] files = srcFile.listFiles(); + // + // for (int i = 0; i < files.length; i++) { + // // if the file is directory, use recursion + // if (files[i].isDirectory()) { + // addFileToList(files[i], artifactsList); + // continue; + // } + // + // String fileName = files[i].getName(); + // String artifactPath = fileName; + // + // if ( ! files[i].getName().matches("(.*)\\.y(?)ml($)")) { + // UploadArtifactInfo uploadArtifactInfo = new UploadArtifactInfo(); + // uploadArtifactInfo.setArtifactName(files[i].getName()); + // String parent = files[i].getParent(); + // + // if (parent != null) { + // System.out.println(parent); + // int lastSepartor = parent.lastIndexOf(File.separator); + // if (lastSepartor > -1) { + // String actualParent = parent.substring(lastSepartor + 1); + // artifactPath = actualParent + "/" + artifactPath; + // } + // } + // + // uploadArtifactInfo.setArtifactPath(artifactPath); + // uploadArtifactInfo.setArtifactType(getFileTypeByExtension(fileName)); + // uploadArtifactInfo.setArtifactDescription("description"); + // artifactsList.add(uploadArtifactInfo); + // + // System.out.println("artifact list: " + artifactsList); + // + // } + // + // } + // } + // + // + // public String buildArtifactListUrl (String nodesType, String + // templateVersion, String artifactName) throws FileNotFoundException{ + // //"http://172.20.43.132/sdc2/v1/catalog/resources/tosca.nodes.Root/1.0.0.wd03-SNAPSHOT/artifacts/wxs_baseline_compare.sh" + // Config config = getConfig(); + // return "\"http://" + config.getCatalogBeHost() + ":" + + // config.getCatalogBePort() + "/sdc2/v1/catalog/resources/" +nodesType + + // "/" + templateVersion + "/artifacts/" + artifactName +"\""; + // } + // + // + // public void addTopologyToES(String testFolder, String + // serviceTopologyPattern) throws IOException{ + // Config config = getConfig(); + // String url = String.format(Urls.ES_URL, config.getEsHost(), + // config.getEsPort()) + serviceTopologyPattern; + // String sourceDir = + // config.getResourceConfigDir()+File.separator+testFolder; + // Path filePath = FileSystems.getDefault().getPath(sourceDir, + // "topology.txt"); + // postFileContentsToUrl(url, filePath); + // } + // + // public void addTopologyTemplateToES(String testFolder, String + // serviceTopologyTemplatePattern) throws IOException{ + // Config config = getConfig(); + // String url = String.format(Urls.ES_URL, config.getEsHost(), + // config.getEsPort()) + serviceTopologyTemplatePattern; + // String sourceDir = + // config.getResourceConfigDir()+File.separator+testFolder; + // Path filePath = FileSystems.getDefault().getPath(sourceDir, + // "topologyTemplate.txt"); + // postFileContentsToUrl(url, filePath); + // } + // + // + // public void postFileContentsToUrl(String url, Path filePath) throws + // IOException { + // HttpClientContext localContext = HttpClientContext.create(); + // CloseableHttpResponse response = null; + // + // byte[] fileContent = Files.readAllBytes(filePath); + // + // try(CloseableHttpClient httpClient = HttpClients.createDefault()){ + // HttpPost httpPost = new HttpPost(url); + // StringEntity entity = new StringEntity(new String(fileContent) , + // ContentType.APPLICATION_JSON); + // httpPost.setEntity(entity); + // response = httpClient.execute(httpPost, localContext); + // + // } + // finally{ + // response.close(); + // } + // + // + // } + // + // + //// public boolean isPatternInEsDb(String patternToSearch)throws + // IOException{ + //// Config config = getConfig(); + //// String url = String.format(Urls.GET_SEARCH_DATA_FROM_ES, + // config.getEsHost(), config.getEsPort(),patternToSearch); + //// HttpRequest httpRequest = new HttpRequest(); + //// RestResponse restResponse = httpRequest.httpSendGet(url); + //// if (restResponse.getErrorCode() == 200){ + //// return true; + //// } + //// if (restResponse.getErrorCode() == 404){ + //// return false; + //// } + //// + //// return false; + //// } + // + // public static RestResponse deleteAllDataFromEs() throws IOException{ + // return deleteFromEsDbByPattern("_all"); + // } + // + + // + // public List buildIdArrayListByTypesIndex (String index, String + // types) throws IOException{ + // + // Config config = getConfig(); + // HttpRequest http = new HttpRequest(); + // RestResponse getResponce = + // http.httpSendGet(String.format(Urls.GET_ID_LIST_BY_INDEX_FROM_ES, + // config.getEsHost(), config.getEsPort(), index, types), null); + // + // List idArray = new ArrayList(); + // + // JsonElement jelement = new JsonParser().parse(getResponce.getResponse()); + // JsonObject jobject = jelement.getAsJsonObject(); + // JsonObject hitsObject = (JsonObject) jobject.get("hits"); + // JsonArray hitsArray = (JsonArray) hitsObject.get("hits"); + // for (int i = 0; i < hitsArray.size(); i ++){ + // JsonObject idObject = (JsonObject) hitsArray.get(i); + // String id = idObject.get("_id").toString(); + // id = id.replace("\"", ""); + // idArray.add(id); + // } + // + // return idArray; + // } + // + // public List buildCategoriesTagsListFromJson(String + // categoriesTagsJson){ + // + // ArrayList categoriesTagsArray = new ArrayList<>(); + // JsonElement jelement = new JsonParser().parse(categoriesTagsJson); + // JsonArray jArray = jelement.getAsJsonArray(); + // for (int i = 0; i < jArray.size(); i ++){ + // JsonObject categoriesTagsObject = (JsonObject) jArray.get(i); + // String categories = categoriesTagsObject.get("name").toString(); + // categoriesTagsArray.add(categories); + // } + // + // return categoriesTagsArray; + // } + // + // public ArrayList getCategoriesFromDb() throws Exception{ + // + // ArrayList categoriesFromDbArrayList = new ArrayList<>(); + // RestResponse restResponse = new RestResponse(); + // String contentTypeHeaderData = "application/json"; + // String acceptHeaderDate = "application/json"; + // + // Map headersMap = new HashMap(); + // headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(),contentTypeHeaderData); + // headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + // + // HttpRequest httpRequest = new HttpRequest(); + // String url = String.format(Urls.QUERY_NEO4J, + // Config.instance().getNeoHost(), Config.instance().getNeoPort()); + // String body = "{\"statements\" : [ { \"statement\" : \"MATCH + // (category:category) return (category)\"} ]}"; + // restResponse = httpRequest.httpSendPostWithAuth(url, body, headersMap, + // Config.instance().getNeoDBusername(), + // Config.instance().getNeoDBpassword()); + // + // if (restResponse.getResponse()==null){ + // return categoriesFromDbArrayList; + // }else{ + // JsonElement jelement = new + // JsonParser().parse(restResponse.getResponse()); + // JsonObject jobject = jelement.getAsJsonObject(); + // JsonArray resultsArray = (JsonArray) jobject.get("results"); + // JsonObject resObject = (JsonObject) resultsArray.get(0); + // JsonArray dataArray = (JsonArray) resObject.get("data"); + // for (int i = 0; i < dataArray.size(); i ++){ + // JsonObject rowObject = (JsonObject) dataArray.get(i); + // JsonArray rowArray = (JsonArray) rowObject.get("row"); + // JsonObject nameObject = (JsonObject) rowArray.get(0); + // String name = nameObject.get("name").toString(); + //// name = name.replace("\"", ""); + // categoriesFromDbArrayList.add(name); + // } + // + // + // } + // + // return categoriesFromDbArrayList; + // } + // + public static void compareArrayLists(List actualArraylList, List expectedArrayList, + String message) { + + ArrayList actual = new ArrayList(actualArraylList); + ArrayList expected = new ArrayList(expectedArrayList); + // assertEquals(message + " count got by rest API not match to " + + // message + " expected count", expected.size(),actual.size()); + expected.removeAll(actual); + assertEquals(message + " content got by rest API not match to " + message + " actual content", 0, + expected.size()); + } + + public static Object parseYamlConfig(String pattern) throws FileNotFoundException { + + Yaml yaml = new Yaml(); + Config config = getConfig(); + String configurationFile = config.getConfigurationFile(); + File file = new File(configurationFile); + // File file = new + // File("../catalog-be/src/main/resources/config/configuration.yaml"); + InputStream inputStream = new FileInputStream(file); + Map map = (Map) yaml.load(inputStream); + Object patternMap = (Object) map.get(pattern); + + return patternMap; + } + + public static String getDepArtLabelFromConfig(ArtifactTypeEnum artifactTypeEnum) throws FileNotFoundException { + + @SuppressWarnings("unchecked") + Map mapOfDepResArtTypesObjects = (Map) parseYamlConfig( + "deploymentResourceArtifacts"); + for (Map.Entry iter : mapOfDepResArtTypesObjects.entrySet()) { + if (iter.getValue().toString().contains(artifactTypeEnum.getType())) { + return iter.getKey().toLowerCase(); + } + } + + return "defaultLabelName"; + } + + + public static String multipleChar(String ch, int repeat) { + return StringUtils.repeat(ch, repeat); + } + + public static List getListOfDepResArtLabels(Boolean isLowerCase) throws FileNotFoundException { + + List listOfResDepArtTypesFromConfig = new ArrayList(); + @SuppressWarnings("unchecked") + Map resourceDeploymentArtifacts = (Map) parseYamlConfig( + "deploymentResourceArtifacts"); + if (resourceDeploymentArtifacts != null) { + + if (isLowerCase) { + for (Map.Entry iter : resourceDeploymentArtifacts.entrySet()) { + listOfResDepArtTypesFromConfig.add(iter.getKey().toLowerCase()); + } + } else { + + for (Map.Entry iter : resourceDeploymentArtifacts.entrySet()) { + listOfResDepArtTypesFromConfig.add(iter.getKey()); + } + } + } + return listOfResDepArtTypesFromConfig; + } + + public static List getListOfToscaArtLabels(Boolean isLowerCase) throws FileNotFoundException { + + List listOfToscaArtTypesFromConfig = new ArrayList(); + @SuppressWarnings("unchecked") + Map toscaArtifacts = (Map) parseYamlConfig("toscaArtifacts"); + if (toscaArtifacts != null) { + + if (isLowerCase) { + for (Map.Entry iter : toscaArtifacts.entrySet()) { + listOfToscaArtTypesFromConfig.add(iter.getKey().toLowerCase()); + } + } else { + for (Map.Entry iter : toscaArtifacts.entrySet()) { + listOfToscaArtTypesFromConfig.add(iter.getKey()); + } + } + } + return listOfToscaArtTypesFromConfig; + } + + // + // public static List getListOfResDepArtTypes() throws + // FileNotFoundException { + // + // List listOfResDepArtTypesFromConfig = new ArrayList(); + // @SuppressWarnings("unchecked") + // Map resourceDeploymentArtifacts = (Map) + // parseYamlConfig("resourceDeploymentArtifacts"); + // for (Map.Entry iter : + // resourceDeploymentArtifacts.entrySet()) { + // listOfResDepArtTypesFromConfig.add(iter.getKey()); + // } + // + // return listOfResDepArtTypesFromConfig; + // } + // + // public static List getListOfDepResInstArtTypes() throws + // FileNotFoundException { + // + // List listOfResInstDepArtTypesFromConfig = new + // ArrayList(); + // @SuppressWarnings("unchecked") + // Map resourceDeploymentArtifacts = (Map) + // parseYamlConfig("deploymentResourceInstanceArtifacts"); + // for (Map.Entry iter : + // resourceDeploymentArtifacts.entrySet()) { + // listOfResInstDepArtTypesFromConfig.add(iter.getKey().toLowerCase()); + // } + // + // return listOfResInstDepArtTypesFromConfig; + // } + // + public static List getListOfResPlaceHoldersDepArtTypes() throws FileNotFoundException { + List listResDepArtTypesFromConfig = new ArrayList(); + List listOfResDepArtLabelsFromConfig = getListOfDepResArtLabels(false); + assertNotNull("deployment artifact types list is null", listOfResDepArtLabelsFromConfig); + Object parseYamlConfig = Utils.parseYamlConfig("deploymentResourceArtifacts"); + Map mapOfDepResArtTypesObjects = (Map) Utils + .parseYamlConfig("deploymentResourceArtifacts"); + + // assertNotNull("deployment artifact types list is null", + // mapOfDepResArtTypesObjects); + if (listOfResDepArtLabelsFromConfig != null) { + for (String resDepArtType : listOfResDepArtLabelsFromConfig) { + Object object = mapOfDepResArtTypesObjects.get(resDepArtType); + if (object instanceof Map) { + Map map = (Map) object; + listResDepArtTypesFromConfig.add((String) map.get("type")); + } else { + assertTrue("return object does not instance of map", false); + } + } + } + return listResDepArtTypesFromConfig; + } + + public static Long getEpochTimeFromUTC(String time) throws ParseException { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS zzz"); + java.util.Date date = df.parse(time); + long epoch = date.getTime(); + return epoch; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/cassandra/CassandraUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/cassandra/CassandraUtils.java new file mode 100644 index 0000000000..e89c6be5df --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/cassandra/CassandraUtils.java @@ -0,0 +1,220 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.cassandra; + +import com.datastax.driver.core.*; +import com.datastax.driver.core.querybuilder.QueryBuilder; +import com.datastax.driver.core.querybuilder.Select; +import com.datastax.driver.core.querybuilder.Select.Where; + +import org.javatuples.Pair; +import org.openecomp.sdc.be.resources.data.auditing.AuditingTypesConstants; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public final class CassandraUtils { + private static Logger logger = LoggerFactory.getLogger(CassandraUtils.class.getName()); + + protected static Cluster cluster = null; + protected static Session session; + + protected static void initConnection(String keyspace) throws FileNotFoundException { + + String cassandraHost = Utils.getConfig().getCassandraHost(); + Boolean cassandraAuthenticate = Utils.getConfig().getCassandraAuthenticate(); + String cassandraUsername = Utils.getConfig().getCassandraUsername(); + String cassandraPassword = Utils.getConfig().getCassandraPassword(); + Boolean cassandraSsl = Utils.getConfig().getCassandraSsl(); + String cassandraTruststorePath = Utils.getConfig().getCassandraTruststorePath(); + String cassandraTruststorePassword = Utils.getConfig().getCassandraTruststorePassword(); + /* + * String cassandraAuditKeySpace= + * Utils.getConfig().getCassandraAuditKeySpace(); String + * cassandraArtifactKeySpace= + * Utils.getConfig().getCassandraArtifactKeySpace(); + */ + + Cluster.Builder clusterBuilder = Cluster.builder().addContactPoint(cassandraHost); + if (cassandraAuthenticate) { + // authantication + clusterBuilder.withCredentials(cassandraUsername, cassandraPassword); + } + + if (cassandraSsl) { + // ssl + System.setProperty("javax.net.ssl.trustStore", cassandraTruststorePath); + System.setProperty("javax.net.ssl.trustStorePassword", cassandraTruststorePassword); + clusterBuilder.withSSL(); + } + + cluster = clusterBuilder.build(); + session = cluster.connect(keyspace); + + } + + public static void truncateTable(String keyspace, String tableName) throws FileNotFoundException { + + if (session == null || session.isClosed()) { + initConnection(keyspace); + } + + try { + + if (session != null) { + session.execute(QueryBuilder.truncate(keyspace, tableName)); + logger.debug("The table {}.{} was cleaned",keyspace,tableName); + } else { + throw new RuntimeException("Keyspace " + keyspace + " not connected"); + } + } finally { + // if (cluster != null) { + // cluster.close(); + // } + } + } + + public static void close() { + if (cluster != null) { + cluster.close(); + } + } + + public static void truncateAllKeyspaces() throws FileNotFoundException { + // truncateAllTables(AuditingTypesConstants.ARTIFACT_KEYSPACE); + truncateAllTables(AuditingTypesConstants.AUDIT_KEYSPACE); + } + + public static void truncateAllTables(String keyspace) throws FileNotFoundException { + + if (session == null || session.isClosed()) { + initConnection(keyspace); + } + try { + + if (session != null) { + Metadata metadata = cluster.getMetadata(); + KeyspaceMetadata keyspaceMetadata = metadata.getKeyspace(keyspace); + if (keyspaceMetadata != null) { + Collection tables = keyspaceMetadata.getTables(); + tables.forEach(table -> { + session.execute(QueryBuilder.truncate(table)); + logger.debug("Table trunceted - {}", table.getName()); + }); + } + } else { + throw new RuntimeException("Keyspace " + keyspace + " not connected"); + } + + } finally { + // if (cluster != null) { + // cluster.close(); + // } + } + } + + public static List fetchFromTable(String keyspace, String tableName, + List> fields) throws FileNotFoundException { + + List> fieldsConverted = new ArrayList<>(); + +// fields.forEach(pair -> { +// Pair newPair = new Pair(pair.getValue0().getDisplayName(), pair.getValue1()); +// fieldsConverted.add(newPair); +// }); + + fields.forEach(pair ->{ + Pair newPair; + if(pair.getValue0() == AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL ){ + newPair = new Pair("RESOURE_URL", pair.getValue1()); + + }else{ + newPair = new Pair(pair.getValue0().getDisplayName(), pair.getValue1()); + } + fieldsConverted.add(newPair); + + }); + + return fetchFromTableQuery(keyspace, tableName, fieldsConverted); + } + + public static List fetchFromTableQuery(String keyspace, String tableName, List> fields) + throws FileNotFoundException { + + if (session == null || session.isClosed()) { + initConnection(keyspace); + } + try { + + if (session != null) { + Select select = QueryBuilder.select().all().from(keyspace, tableName); + if (fields != null) { + // Set> entrySet = + // fields.entrySet(); + // fields. + boolean multiple = (fields.size() > 1) ? true : false; + Where where = null; + int size = 0; + + for (Pair pair : fields) { + ++size; + if (size == 1) { + where = select.where(QueryBuilder.eq(pair.getValue0(), pair.getValue1())); + } else { + where.and(QueryBuilder.eq(pair.getValue0(), pair.getValue1())); + } + } + if (multiple) { + select.allowFiltering(); + } + + } + + List rows = session.execute(select).all(); + for (Row row : rows) { + logger.debug("{}", row); + } + return rows; + } + } finally { + // if (cluster != null) { + // cluster.close(); + // } + } + return null; + } + // + // public static void main(String[] args) throws FileNotFoundException { + // Map map = new HashMap<>(); + // map.put(AuditingFieldsKeysEnum.AUDIT_ACTION, "Access"); + // map.put(AuditingFieldsKeysEnum.AUDIT_STATUS, "200"); + // // CassandraUtils.truncateTable("sdcartifact", "resources"); + //// CassandraUtils.truncateAllTables("sdcaudit"); + // CassandraUtils.fetchFromTable("sdcaudit", "useraccessevent", map ); + // } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/cassandra/CassandraUtils2.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/cassandra/CassandraUtils2.java new file mode 100644 index 0000000000..024389609d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/cassandra/CassandraUtils2.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.cassandra; + +import com.datastax.driver.core.*; +import com.datastax.driver.core.querybuilder.QueryBuilder; +import com.datastax.driver.core.querybuilder.Select; +import com.datastax.driver.core.querybuilder.Select.Where; +import org.javatuples.Pair; +import org.openecomp.sdc.be.resources.data.auditing.AuditingTypesConstants; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileNotFoundException; +import java.util.Collection; +import java.util.List; + +public final class CassandraUtils2 { + private static Logger logger = LoggerFactory.getLogger(CassandraUtils2.class.getName()); + + public static void truncateTable(String keyspace, String tableName) throws FileNotFoundException { + + String cassandraHost = Utils.getConfig().getCassandraHost(); + + Cluster cluster = null; + Session session; + + try { + Cluster.Builder clusterBuilder = Cluster.builder().addContactPoint(cassandraHost); + // authantication + // clusterBuilder.withCredentials(username,password); + // ssl + // System.setProperty("javax.net.ssl.trustStore",truststorePath); + // System.setProperty("javax.net.ssl.trustStorePassword",truststorePassword); + // clusterBuilder.withSSL(); + cluster = clusterBuilder.build(); + session = cluster.connect(keyspace); + if (session != null) { + session.execute(QueryBuilder.truncate(keyspace, tableName)); + logger.debug("The table {}.{} was cleaned",keyspace,tableName); + } else { + throw new RuntimeException("Keyspace " + keyspace + " not connected"); + } + } finally { + if (cluster != null) { + cluster.close(); + } + } + } + + public static void truncateAllKeyspaces() throws FileNotFoundException { + truncateAllTables(AuditingTypesConstants.ARTIFACT_KEYSPACE); + truncateAllTables(AuditingTypesConstants.AUDIT_KEYSPACE); + } + + public static void truncateAllTables(String keyspace) throws FileNotFoundException { + String cassandraHost = Utils.getConfig().getCassandraHost(); + + Cluster cluster = null; + Session session; + + try { + cluster = Cluster.builder().addContactPoint(cassandraHost).build(); + session = cluster.connect(keyspace); + if (session != null) { + Metadata metadata = cluster.getMetadata(); + KeyspaceMetadata keyspaceMetadata = metadata.getKeyspace(keyspace); + if (keyspaceMetadata != null) { + Collection tables = keyspaceMetadata.getTables(); + tables.forEach(table -> { + session.execute(QueryBuilder.truncate(table)); + logger.debug("Table trunceted - {}", table.getName()); + }); + } + } else { + throw new RuntimeException("Keyspace " + keyspace + " not connected"); + } + + } finally { + if (cluster != null) { + cluster.close(); + } + } + } + + public static List fetchFromTable(String keyspace, String tableName, + List> fields) throws FileNotFoundException { + + // List> + // Map + + Cluster cluster = null; + Session session; + String cassandraHost = Utils.getConfig().getCassandraHost(); + + try { + cluster = Cluster.builder().addContactPoint(cassandraHost).build(); + session = cluster.connect(keyspace); + if (session != null) { + Select select = QueryBuilder.select().all().from(keyspace, tableName); + if (fields != null) { + // Set> entrySet = + // fields.entrySet(); + // fields. + boolean multiple = (fields.size() > 1) ? true : false; + Where where = null; + int size = 0; + + for (Pair pair : fields) { + ++size; + if (size == 1) { + where = select.where(QueryBuilder.eq(pair.getValue0().getDisplayName(), pair.getValue1())); + } else { + where.and(QueryBuilder.eq(pair.getValue0().getDisplayName(), pair.getValue1())); + } + } + if (multiple) { + select.allowFiltering(); + } + + } + + List rows = session.execute(select).all(); + for (Row row : rows) { + logger.debug("{}", row); + } + return rows; + } + } finally { + if (cluster != null) { + cluster.close(); + } + } + return null; + } + // + // public static void main(String[] args) throws FileNotFoundException { + // Map map = new HashMap<>(); + // map.put(AuditingFieldsKeysEnum.AUDIT_ACTION, "Access"); + // map.put(AuditingFieldsKeysEnum.AUDIT_STATUS, "200"); + // // CassandraUtils.truncateTable("sdcartifact", "resources"); + //// CassandraUtils.truncateAllTables("sdcaudit"); + // CassandraUtils.fetchFromTable("sdcaudit", "useraccessevent", map ); + // } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/AtomicOperationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/AtomicOperationUtils.java new file mode 100644 index 0000000000..207c4bbe02 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/AtomicOperationUtils.java @@ -0,0 +1,732 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.general; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.bind.helpers.AbstractUnmarshallerImpl; +import javax.xml.ws.Response; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.tuple.Pair; +import org.aspectj.apache.bcel.classfile.Code; +import org.json.JSONException; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.PropertyReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ComponentInstanceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ConsumerRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.PropertyRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.testng.SkipException; + +import com.google.gson.Gson; + +import fj.data.Either; + +public final class AtomicOperationUtils { + + static final String basicAuthentication = "Basic Y2k6MTIzNDU2"; + + private AtomicOperationUtils() { + throw new UnsupportedOperationException(); + } + + // *********** RESOURCE **************** + /** + * Import a vfc From tosca file + * + * @param filePath + * @param fileName + * @return + * @throws IOException + * @throws JSONException + */ + public static Either importResource(String filePath, String fileName) { + try { + User designer = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ImportReqDetails importReqDetails = ElementFactory.getDefaultImportResource("ciTmpVFC"); + importReqDetails = ImportUtils.getImportResourceDetailsByPathAndName(importReqDetails, filePath, fileName); + RestResponse importResourceResponse = ResourceRestUtils.createImportResource(importReqDetails, designer, null); + return buildResourceFromResponse(importResourceResponse); + } catch (Exception e) { + throw new AtomicOperationException(e); + } + } + + public static Either createResourceByType(ResourceTypeEnum resourceType, UserRoleEnum userRole, Boolean validateState) { + try { + User defaultUser = ElementFactory.getDefaultUser(userRole); + ResourceReqDetails defaultResource = ElementFactory.getDefaultResourceByType(resourceType, defaultUser); + RestResponse resourceResp = ResourceRestUtils.createResource(defaultResource, defaultUser); + + if (validateState) { + assertTrue(resourceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED); + } + + if (resourceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED) { + Resource resourceResponseObject = ResponseParser.convertResourceResponseToJavaObject(resourceResp.getResponse()); + return Either.left(resourceResponseObject); + } + return Either.right(resourceResp); + } catch (Exception e) { + throw new AtomicOperationException(e); + } + } + + public static Either createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum resourceType, NormativeTypesEnum normativeTypes, ResourceCategoryEnum resourceCategory, UserRoleEnum userRole, Boolean validateState) + throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + ResourceReqDetails defaultResource = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(resourceType, normativeTypes, resourceCategory, defaultUser); + RestResponse resourceResp = ResourceRestUtils.createResource(defaultResource, defaultUser); + + if (validateState) { + assertTrue("Actual Response Code is: " + resourceResp.getErrorCode(), resourceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED); + } + + if (resourceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED) { + // Resource resourceResponseObject = ResponseParser + // .convertResourceResponseToJavaObject(resourceResp.getResponse()); + Resource resourceResponseObject = ResponseParser.parseToObjectUsingMapper(resourceResp.getResponse(), Resource.class); + return Either.left(resourceResponseObject); + } + return Either.right(resourceResp); + } + + public static Either createResourcesByCustomNormativeTypeAndCatregory(ResourceTypeEnum resourceType, Resource resourceNormativeType, ResourceCategoryEnum resourceCategory, UserRoleEnum userRole, Boolean validateState) + throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + ResourceReqDetails defaultResource = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(resourceType, resourceNormativeType, resourceCategory, defaultUser); + RestResponse resourceResp = ResourceRestUtils.createResource(defaultResource, defaultUser); + + if (validateState) { + assertTrue("actual result: " + resourceResp.getResponseMessage(), resourceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED); + } + + if (resourceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED) { + // Resource resourceResponseObject = ResponseParser + // .convertResourceResponseToJavaObject(resourceResp.getResponse()); + Resource resourceResponseObject = ResponseParser.parseToObjectUsingMapper(resourceResp.getResponse(), Resource.class); + return Either.left(resourceResponseObject); + } + return Either.right(resourceResp); + } + + // *********** SERVICE **************** + + public static Either createDefaultService(UserRoleEnum userRole, Boolean validateState) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(defaultUser); + RestResponse createServiceResp = ServiceRestUtils.createService(serviceDetails, defaultUser); + + if (validateState) { + assertTrue(createServiceResp.getErrorCode() == ServiceRestUtils.STATUS_CODE_CREATED); + } + + if (createServiceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED) { + Service serviceResponseObject = ResponseParser.convertServiceResponseToJavaObject(createServiceResp.getResponse()); + return Either.left(serviceResponseObject); + } + return Either.right(createServiceResp); + } + + public static Either createServiceByCategory(ServiceCategoriesEnum category, UserRoleEnum userRole, Boolean validateState) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(category, defaultUser); + RestResponse createServiceResp = ServiceRestUtils.createService(serviceDetails, defaultUser); + + if (validateState) { + assertTrue(createServiceResp.getErrorCode() == ServiceRestUtils.STATUS_CODE_CREATED); + } + + if (createServiceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED) { + Service serviceResponseObject = ResponseParser.convertServiceResponseToJavaObject(createServiceResp.getResponse()); + return Either.left(serviceResponseObject); + } + return Either.right(createServiceResp); + } + + // *********** PRODUCT **************** + + public static Either createDefaultProduct(UserRoleEnum userRole, Boolean validateState) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + ProductReqDetails defaultProduct = ElementFactory.getDefaultProduct(); + RestResponse createProductResp = ProductRestUtils.createProduct(defaultProduct, defaultUser); + + if (validateState) { + assertTrue(createProductResp.getErrorCode() == ProductRestUtils.STATUS_CODE_CREATED); + } + + if (createProductResp.getErrorCode() == ProductRestUtils.STATUS_CODE_CREATED) { + Product productResponseJavaObject = ResponseParser.convertProductResponseToJavaObject(createProductResp.getResponse()); + return Either.left(productResponseJavaObject); + } + return Either.right(createProductResp); + } + + // public static ComponentReqDetails + // convertCompoentToComponentReqDetails(Component component){ + // + // ComponentReqDetails componentReqDetails = + // ElementFactory.getDefaultService(); + // componentReqDetails.setName(component.getName()); + // componentReqDetails.setDescription(component.getDescription()); + // componentReqDetails.setTags(component.getTags()); + // componentReqDetails.setContactId(component.getContactId()); + // componentReqDetails.setIcon(component.getIcon()); + // componentReqDetails.setUniqueId(component.getUniqueId()); + // componentReqDetails.setCreatorUserId(component.getCreatorUserId()); + // componentReqDetails.setCreatorFullName(component.getCreatorFullName()); + // componentReqDetails.setLastUpdaterUserId(component.getLastUpdaterUserId()); + // componentReqDetails.setLastUpdaterFullName(component.getLastUpdaterFullName()); + // componentReqDetails.setCreationDate(component.getCreationDate()); + // componentReqDetails.setLastUpdateDate(component.getLastUpdateDate()); + // componentReqDetails.setLifecycleState(component.getLifecycleState()); + // componentReqDetails.setVersion(component.getVersion()); + // componentReqDetails.setUuid(component.getUUID()); + // componentReqDetails.setCategories(component.getCategories()); + // componentReqDetails.setProjectCode(component.getProjectCode()); + // + // return componentReqDetails; + // } + + // *********** LIFECYCLE *************** + + public static Pair changeComponentState(Component component, UserRoleEnum userRole, LifeCycleStatesEnum targetState, Boolean validateState) throws Exception { + + Boolean isValidationFailed = false; + RestResponse lifeCycleStatesResponse = null; + User defaultUser = ElementFactory.getDefaultUser(userRole); + + LifeCycleStatesEnum curentCompState = LifeCycleStatesEnum.findByCompState(component.getLifecycleState().toString()); + + if (curentCompState == targetState) { + component = getCompoenntObject(component, userRole); + return Pair.of(component, null); + } + // List lifeCycleStatesEnumOrigList = new + // ArrayList(EnumSet.allOf(LifeCycleStatesEnum.class)); + + ArrayList lifeCycleStatesEnumList = new ArrayList(); + if (curentCompState.equals(LifeCycleStatesEnum.CHECKIN) && targetState.equals(LifeCycleStatesEnum.CHECKOUT)) { + lifeCycleStatesEnumList.add(LifeCycleStatesEnum.CHECKIN.toString()); + lifeCycleStatesEnumList.add(LifeCycleStatesEnum.CHECKOUT.toString()); + } else { + lifeCycleStatesEnumList.add(LifeCycleStatesEnum.CHECKOUT.toString()); + lifeCycleStatesEnumList.add(LifeCycleStatesEnum.CHECKIN.toString()); + lifeCycleStatesEnumList.add(LifeCycleStatesEnum.CERTIFICATIONREQUEST.toString()); + lifeCycleStatesEnumList.add(LifeCycleStatesEnum.STARTCERTIFICATION.toString()); + lifeCycleStatesEnumList.add(LifeCycleStatesEnum.CERTIFY.toString()); + } + for (int i = 0; i < lifeCycleStatesEnumList.size(); i++) { + if (lifeCycleStatesEnumList.get(i).equals(curentCompState.name())) { + int a; + a = (i == lifeCycleStatesEnumList.size() - 1) ? 0 : i + 1; + + for (int n = a; n < lifeCycleStatesEnumList.size(); n++) { + if (lifeCycleStatesEnumList.get(n).equals(LifeCycleStatesEnum.STARTCERTIFICATION.name()) || lifeCycleStatesEnumList.get(n).equals(LifeCycleStatesEnum.CERTIFY.name())) { + defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + } else + defaultUser = ElementFactory.getDefaultUser(userRole); + + lifeCycleStatesResponse = LifecycleRestUtils.changeComponentState(component, defaultUser, LifeCycleStatesEnum.findByState(lifeCycleStatesEnumList.get(n))); + if (lifeCycleStatesResponse.getErrorCode() != LifecycleRestUtils.STATUS_CODE_SUCCESS) + isValidationFailed = true; + if (lifeCycleStatesEnumList.get(n).equals(targetState.toString()) || isValidationFailed == true) { + break; + } + } + } + + } + Component componentJavaObject = getCompoenntObject(component, userRole); + + if (validateState == true && isValidationFailed == true) { + assertTrue("change state failed" + lifeCycleStatesResponse.getResponse(), false); + + return Pair.of(componentJavaObject, lifeCycleStatesResponse); + } + + if (isValidationFailed == true) { + return Pair.of(componentJavaObject, lifeCycleStatesResponse); + } + + return Pair.of(componentJavaObject, lifeCycleStatesResponse); + } + + public static RestResponse distributeService(Component component, Boolean validateState) throws Exception { + + Service service = (Service) component; + + User opsUser = ElementFactory.getDefaultUser(UserRoleEnum.OPS); + User governotUser = ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR); + + ServiceReqDetails serviceDetails = new ServiceReqDetails(service); + RestResponse distributionService = null; + + RestResponse approveDistribution = LifecycleRestUtils.changeDistributionStatus(serviceDetails, null, governotUser, "approveService", DistributionStatusEnum.DISTRIBUTION_APPROVED); + if (approveDistribution.getErrorCode() == 200) { + distributionService = LifecycleRestUtils.changeDistributionStatus(serviceDetails, null, opsUser, "approveService", DistributionStatusEnum.DISTRIBUTED); + } + + if (validateState) { + assertTrue(approveDistribution.getErrorCode() == ProductRestUtils.STATUS_CODE_SUCCESS); + assertTrue(distributionService.getErrorCode() == ProductRestUtils.STATUS_CODE_SUCCESS); + return distributionService; + } + + return distributionService; + + } + + // *********** ARTIFACTS ***************** + + public static Either uploadArtifactByType(ArtifactTypeEnum artifactType, Component component, UserRoleEnum userRole, Boolean deploymentTrue, Boolean validateState) throws Exception { + + User defaultUser = ElementFactory.getDefaultUser(userRole); + ArtifactReqDetails artifactDetails = ElementFactory.getArtifactByType(null, artifactType, deploymentTrue); + if (deploymentTrue == false) + artifactDetails.setArtifactGroupType(ArtifactGroupTypeEnum.INFORMATIONAL.getType()); + RestResponse uploadArtifactResp = ArtifactRestUtils.uploadArtifact(artifactDetails, component, defaultUser); + + if (validateState) { + assertTrue("artifact upload failed: " + artifactDetails.getArtifactName(), uploadArtifactResp.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + if (uploadArtifactResp.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS) { + ArtifactDefinition artifactJavaObject = ResponseParser.convertArtifactDefinitionResponseToJavaObject(uploadArtifactResp.getResponse()); + return Either.left(artifactJavaObject); + } + return Either.right(uploadArtifactResp); + } + + // *********** CONTAINERS ***************** + /** + * Adds Component instance to Component + * + * @param compInstParent + * @param compContainer + * @return + */ + public static Either addComponentInstanceToComponentContainer(Component compInstParent, Component compContainer) { + return addComponentInstanceToComponentContainer(compInstParent, compContainer, UserRoleEnum.DESIGNER, false); + } + + public static Either addComponentInstanceToComponentContainer(Component compInstParent, Component compContainer, UserRoleEnum userRole, Boolean validateState) { + try { + User defaultUser = ElementFactory.getDefaultUser(userRole); + ComponentInstanceReqDetails componentInstanceDetails = ElementFactory.getComponentInstance(compInstParent); + RestResponse createComponentInstance = ComponentInstanceRestUtils.createComponentInstance(componentInstanceDetails, defaultUser, compContainer); + + if (validateState) { + if (createComponentInstance.getErrorCode() == ServiceRestUtils.STATUS_CODE_NOT_FOUND) + { + throw new SkipException("Open bug DE262001"); + } + else{ + assertTrue("error - " + createComponentInstance.getErrorCode() + "instead - " + ServiceRestUtils.STATUS_CODE_CREATED, createComponentInstance.getErrorCode() == ServiceRestUtils.STATUS_CODE_CREATED); + } + } + + if (createComponentInstance.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED) { + ComponentInstance componentInstance = ResponseParser.convertComponentInstanceResponseToJavaObject(createComponentInstance.getResponse()); + return Either.left(componentInstance); + } + return Either.right(createComponentInstance); + } catch (Exception e) { + throw new AtomicOperationException(e); + } + } + + public static Resource getResourceObject(Component containerDetails, UserRoleEnum userRole) throws Exception { + // User defaultUser = ElementFactory.getDefaultUser(userRole); + RestResponse restResponse = ResourceRestUtils.getResource(containerDetails.getUniqueId()); + Resource container = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + return container; + } + + public static Resource getResourceObject(String uniqueId) throws Exception { + RestResponse restResponse = ResourceRestUtils.getResource(uniqueId); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + return resource; + } + + public static Resource getResourceObjectByNameAndVersion(UserRoleEnum sdncModifierDetails, String resourceName, String resourceVersion) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(sdncModifierDetails); + RestResponse resourceResponse = ResourceRestUtils.getResourceByNameAndVersion(defaultUser.getUserId(), resourceName, resourceVersion); + Resource container = ResponseParser.convertResourceResponseToJavaObject(resourceResponse.getResponse()); + return container; + } + + public static Service getServiceObject(Component containerDetails, UserRoleEnum userRole) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + RestResponse serviceResponse = ServiceRestUtils.getService(containerDetails.getUniqueId(), defaultUser); + Service container = ResponseParser.convertServiceResponseToJavaObject(serviceResponse.getResponse()); + return container; + } + + public static Service getServiceObjectByNameAndVersion(UserRoleEnum sdncModifierDetails, String serviceName, String serviceVersion) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(sdncModifierDetails); + RestResponse serviceResponse = ServiceRestUtils.getServiceByNameAndVersion(defaultUser, serviceName, serviceVersion); + Service container = ResponseParser.convertServiceResponseToJavaObject(serviceResponse.getResponse()); + return container; + } + + public static Product getProductObject(Component containerDetails, UserRoleEnum userRole) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + RestResponse productRest = ProductRestUtils.getProduct(containerDetails.getUniqueId(), defaultUser.getUserId()); + Product container = ResponseParser.convertProductResponseToJavaObject(productRest.getResponse()); + return container; + } + + public static Component getCompoenntObject(Component containerDetails, UserRoleEnum userRole) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + + switch (containerDetails.getComponentType()) { + case RESOURCE: + RestResponse restResponse = ResourceRestUtils.getResource(containerDetails.getUniqueId()); + containerDetails = ResponseParser.convertResourceResponseToJavaObject(restResponse.getResponse()); + break; + case SERVICE: + RestResponse serviceResponse = ServiceRestUtils.getService(containerDetails.getUniqueId(), defaultUser); + containerDetails = ResponseParser.convertServiceResponseToJavaObject(serviceResponse.getResponse()); + break; + case PRODUCT: + RestResponse productRest = ProductRestUtils.getProduct(containerDetails.getUniqueId(), defaultUser.getUserId()); + containerDetails = ResponseParser.convertProductResponseToJavaObject(productRest.getResponse()); + break; + default: + break; + } + return containerDetails; + } + + public static Component convertReposnseToComponentObject(Component containerDetails, RestResponse restresponse) throws Exception { + + switch (containerDetails.getComponentType()) { + case RESOURCE: + containerDetails = ResponseParser.convertResourceResponseToJavaObject(restresponse.getResponse()); + break; + case SERVICE: + containerDetails = ResponseParser.convertServiceResponseToJavaObject(restresponse.getResponse()); + break; + case PRODUCT: + containerDetails = ResponseParser.convertProductResponseToJavaObject(restresponse.getResponse()); + break; + default: + break; + } + return containerDetails; + } + + public static Either associate2ResourceInstances(Component containerDetails, ComponentInstance fromNode, ComponentInstance toNode, String assocType, UserRoleEnum userRole, Boolean validateState) throws Exception { + + User defaultUser = ElementFactory.getDefaultUser(userRole); + RestResponse associate2ResourceInstancesResponse = ResourceRestUtils.associate2ResourceInstances(containerDetails, fromNode, toNode, assocType, defaultUser); + + if (validateState) { + assertTrue(associate2ResourceInstancesResponse.getErrorCode() == ServiceRestUtils.STATUS_CODE_SUCCESS); + } + + if (associate2ResourceInstancesResponse.getErrorCode() == ResourceRestUtils.STATUS_CODE_SUCCESS) { + + switch (containerDetails.getComponentType()) { + case RESOURCE: + containerDetails = ResponseParser.convertResourceResponseToJavaObject(associate2ResourceInstancesResponse.getResponse()); + break; + case SERVICE: + containerDetails = ResponseParser.convertServiceResponseToJavaObject(associate2ResourceInstancesResponse.getResponse()); + break; + case PRODUCT: + containerDetails = ResponseParser.convertProductResponseToJavaObject(associate2ResourceInstancesResponse.getResponse()); + break; + default: + break; + } + + return Either.left(containerDetails); + } + return Either.right(associate2ResourceInstancesResponse); + + } + + public static Either, RestResponse> changeComponentInstanceVersion(Component containerDetails, ComponentInstance componentInstanceToReplace, Component newInstance, UserRoleEnum userRole, Boolean validateState) + throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + + RestResponse changeComponentInstanceVersionResp = ComponentInstanceRestUtils.changeComponentInstanceVersion(containerDetails, componentInstanceToReplace, newInstance, defaultUser); + if (validateState) { + assertTrue("change ComponentInstance version failed: " + changeComponentInstanceVersionResp.getResponseMessage(), changeComponentInstanceVersionResp.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + if (changeComponentInstanceVersionResp.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS) { + + Component compoenntObject = AtomicOperationUtils.getCompoenntObject(containerDetails, userRole); + ComponentInstance componentInstanceJavaObject = ResponseParser.convertComponentInstanceResponseToJavaObject(changeComponentInstanceVersionResp.getResponse()); + + return Either.left(Pair.of(compoenntObject, componentInstanceJavaObject)); + } + + return Either.right(changeComponentInstanceVersionResp); + } + + // *********** PROPERTIES ***************** + + public static Either addCustomPropertyToResource(PropertyReqDetails propDetails, Resource resourceDetails, UserRoleEnum userRole, Boolean validateState) throws Exception { + + User defaultUser = ElementFactory.getDefaultUser(userRole); + Map propertyToSend = new HashMap(); + propertyToSend.put(propDetails.getName(), propDetails); + Gson gson = new Gson(); + RestResponse addPropertyResponse = PropertyRestUtils.createProperty(resourceDetails.getUniqueId(), gson.toJson(propertyToSend), defaultUser); + + if (validateState) { + assertTrue("add property to resource failed: " + addPropertyResponse.getErrorCode(), addPropertyResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_CREATED); + } + + if (addPropertyResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_CREATED) { + ComponentInstanceProperty compInstProp = null; + String property = ResponseParser.getJsonObjectValueByKey(addPropertyResponse.getResponse(), propDetails.getName()); + compInstProp = (ResponseParser.convertPropertyResponseToJavaObject(property)); + return Either.left(compInstProp); + } + return Either.right(addPropertyResponse); + } + + // Benny + public static Either updatePropertyOfResource(PropertyReqDetails propDetails, Resource resourceDetails, String propertyUniqueId, UserRoleEnum userRole, Boolean validateState) throws Exception { + + User defaultUser = ElementFactory.getDefaultUser(userRole); + Map propertyToSend = new HashMap(); + propertyToSend.put(propDetails.getName(), propDetails); + Gson gson = new Gson(); + RestResponse addPropertyResponse = PropertyRestUtils.updateProperty(resourceDetails.getUniqueId(), propertyUniqueId, gson.toJson(propertyToSend), defaultUser); + + if (validateState) { + assertTrue("add property to resource failed: " + addPropertyResponse.getResponseMessage(), addPropertyResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + } + + if (addPropertyResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_SUCCESS) { + ComponentInstanceProperty compInstProp = null; + String property = ResponseParser.getJsonObjectValueByKey(addPropertyResponse.getResponse(), propDetails.getName()); + compInstProp = (ResponseParser.convertPropertyResponseToJavaObject(property)); + return Either.left(compInstProp); + } + return Either.right(addPropertyResponse); + } + + public static RestResponse deletePropertyOfResource(String resourceId, String propertyId, UserRoleEnum userRole) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(userRole); + return PropertyRestUtils.deleteProperty(resourceId, propertyId, defaultUser); + } + + public static Either addDefaultPropertyToResource(PropertyTypeEnum propertyType, Resource resourceDetails, UserRoleEnum userRole, Boolean validateState) throws Exception { + + User defaultUser = ElementFactory.getDefaultUser(userRole); + PropertyReqDetails propDetails = ElementFactory.getPropertyDetails(propertyType); + Map propertyToSend = new HashMap(); + propertyToSend.put(propDetails.getName(), propDetails); + Gson gson = new Gson(); + RestResponse addPropertyResponse = PropertyRestUtils.createProperty(resourceDetails.getUniqueId(), gson.toJson(propertyToSend), defaultUser); + + if (validateState) { + assertTrue("add property to resource failed: " + addPropertyResponse.getResponseMessage(), addPropertyResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_CREATED); + } + + if (addPropertyResponse.getErrorCode() == BaseRestUtils.STATUS_CODE_CREATED) { + ComponentInstanceProperty compInstProp = null; + String property = ResponseParser.getJsonObjectValueByKey(addPropertyResponse.getResponse(), propDetails.getName()); + compInstProp = (ResponseParser.convertPropertyResponseToJavaObject(property)); + + return Either.left(compInstProp); + } + return Either.right(addPropertyResponse); + } + + public static RestResponse createDefaultConsumer(Boolean validateState) { + try { + ConsumerDataDefinition defaultConsumerDefinition = ElementFactory.getDefaultConsumerDetails(); + RestResponse createResponse = ConsumerRestUtils.createConsumer(defaultConsumerDefinition, ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)); + BaseRestUtils.checkCreateResponse(createResponse); + + if (validateState) { + assertTrue(createResponse.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED); + } + return createResponse; + } catch (Exception e) { + throw new AtomicOperationException(e); + } + } + + /** + * Builds Resource From rest response + * + * @param resourceResp + * @return + */ + public static Either buildResourceFromResponse(RestResponse resourceResp) { + Either result; + if (resourceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED) { + Resource resourceResponseObject = ResponseParser.convertResourceResponseToJavaObject(resourceResp.getResponse()); + result = Either.left(resourceResponseObject); + } else { + result = Either.right(resourceResp); + } + return result; + } + + private static class AtomicOperationException extends RuntimeException { + private AtomicOperationException(Exception e) { + super(e); + } + + private static final long serialVersionUID = 1L; + }; + + /** + * Import resource from CSAR + * + * @param resourceType + * @param userRole + * @param fileName + * @param filePath + * @return Resource + * @throws Exception + */ + public static Resource importResourceFromCSAR(ResourceTypeEnum resourceType, UserRoleEnum userRole, String fileName, String... filePath) throws Exception { + // Get the CSARs path + String realFilePath = System.getProperty("user.dir") + File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator + "CI" + File.separator + "csars" ; + if (filePath != null && filePath.length > 0) { + realFilePath = filePath.toString(); + } + + // Create default import resource & user + ImportReqDetails resourceDetails = ElementFactory.getDefaultImportResource(); + User sdncModifierDetails = ElementFactory.getDefaultUser(userRole); + + byte[] data = null; + Path path = Paths.get(realFilePath + File.separator + fileName); + data = Files.readAllBytes(path); + String payloadName = fileName; + String payloadData = Base64.encodeBase64String(data); + resourceDetails.setPayloadData(payloadData); + resourceDetails.setCsarUUID(payloadName); + resourceDetails.setPayloadName(payloadName); + resourceDetails.setResourceType(resourceType.name()); + + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncModifierDetails); + BaseRestUtils.checkCreateResponse(createResource); + return ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + }; + + public static Either importResourceByFileName(ResourceTypeEnum resourceType, UserRoleEnum userRole, String fileName, Boolean validateState, String... filePath) throws IOException { + + String realFilePath = System.getProperty("user.dir") + File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator + "CI" + File.separator + "csars" ; + if (filePath != null && filePath.length > 0) { + realFilePath = filePath.toString(); + } + + try { + User defaultUser = ElementFactory.getDefaultUser(userRole); + ResourceReqDetails defaultResource = ElementFactory.getDefaultResource(defaultUser); + ImportReqDetails defaultImportResource = ElementFactory.getDefaultImportResource(defaultResource); + ImportUtils.getImportResourceDetailsByPathAndName(defaultImportResource, realFilePath, fileName); + RestResponse resourceResp = ResourceRestUtils.createResource(defaultImportResource, defaultUser); + + if (validateState) { + assertTrue(resourceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED); + } + + if (resourceResp.getErrorCode() == ResourceRestUtils.STATUS_CODE_CREATED) { + Resource resourceResponseObject = ResponseParser.convertResourceResponseToJavaObject(resourceResp.getResponse()); + return Either.left(resourceResponseObject); + } + return Either.right(resourceResp); + } catch (Exception e) { + throw new AtomicOperationException(e); + } + } + + public static Either getServiceToscaArtifactPayload(Service service, String artifactType) throws Exception { + + String url = String.format(Urls.UI_DOWNLOAD_SERVICE_ARTIFACT, "localhost", "8080", service.getUniqueId(), service.getToscaArtifacts().get(artifactType).getUniqueId()); + String userId = service.getLastUpdaterUserId(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.CACHE_CONTROL.getValue(), "no-cache"); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), basicAuthentication); + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); +// headersMap.put("X-ECOMP-InstanceID", "test"); + if (userId != null) { + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), userId); + } + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendGet(url, headersMap); + if (response.getErrorCode() != 200 && response.getResponse().getBytes() == null && response.getResponse().getBytes().length == 0) { + return Either.right(response); + } + return Either.left(response.getResponse()); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/Convertor.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/Convertor.java new file mode 100644 index 0000000000..619d279b62 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/Convertor.java @@ -0,0 +1,344 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.general; + +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_CREATED; +import static org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils.STATUS_CODE_SUCCESS; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceRespJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedProductAudit; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedUserCRUDAudit; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.api.Constants; + +public class Convertor { + // ***** resource ***** + public static ResourceRespJavaObject constructFieldsForRespValidation(ResourceReqDetails resourceDetails, + String resourceVersion) { + return convertToRespObject(resourceDetails, resourceVersion, UserRoleEnum.ADMIN.getUserId(), + UserRoleEnum.ADMIN.getUserName()); + + } + + public static ResourceRespJavaObject constructFieldsForRespValidation(ResourceReqDetails resourceDetails) { + return convertToRespObject(resourceDetails, resourceDetails.getVersion(), UserRoleEnum.ADMIN.getUserId(), + UserRoleEnum.ADMIN.getUserName()); + + } + + public static ResourceRespJavaObject constructFieldsForRespValidation(ResourceReqDetails resourceDetails, + String resourceVersion, User user) { + return convertToRespObject(resourceDetails, resourceVersion, user.getUserId(), user.getFullName()); + + } + + private static ResourceRespJavaObject convertToRespObject(ResourceReqDetails resourceDetails, + String resourceVersion, String userId, String userName) { + ResourceRespJavaObject resourceRespJavaObject = new ResourceRespJavaObject(); + + resourceRespJavaObject.setUniqueId(resourceDetails.getUniqueId()); + resourceRespJavaObject.setName(resourceDetails.getName()); + resourceRespJavaObject.setCreatorUserId(resourceDetails.getCreatorUserId()); + resourceRespJavaObject.setCreatorFullName(resourceDetails.getCreatorFullName()); + resourceRespJavaObject.setLastUpdaterUserId(userId); + resourceRespJavaObject.setLastUpdaterFullName(userName); + resourceRespJavaObject.setDescription(resourceDetails.getDescription()); + resourceRespJavaObject.setIcon(resourceDetails.getIcon()); + resourceRespJavaObject.setTags(resourceDetails.getTags()); + resourceRespJavaObject.setIsHighestVersion("true"); + resourceRespJavaObject.setCategories(resourceDetails.getCategories()); + resourceRespJavaObject.setLifecycleState( + resourceDetails.getLifecycleState() != null ? resourceDetails.getLifecycleState().toString() + : LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + // resourceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceRespJavaObject.setDerivedFrom(resourceDetails.getDerivedFrom()); + resourceRespJavaObject.setVendorName(resourceDetails.getVendorName()); + resourceRespJavaObject.setVendorRelease(resourceDetails.getVendorRelease()); + resourceRespJavaObject.setContactId(resourceDetails.getContactId()); + resourceRespJavaObject.setAbstractt("false"); + resourceRespJavaObject.setVersion(resourceVersion); + resourceRespJavaObject.setCost(resourceDetails.getCost()); + resourceRespJavaObject.setLicenseType(resourceDetails.getLicenseType()); + resourceRespJavaObject.setResourceType(resourceDetails.getResourceType()); + + return resourceRespJavaObject; + + } + + // ********** service ************** + + // public static ServiceRespJavaObject + // constructFieldsForRespValidation(ServiceReqDetails serviceDetails, String + // serviceVersion, User user) { + // return convertToRespObject(serviceDetails, serviceVersion, + // user.getUserId(), user.getFullName()); + // + // } + // + // private static ServiceRespJavaObject + // convertToRespObject(ServiceReqDetails serviceDetails, String + // serviceVersion, String userId, String userName) { + // ServiceRespJavaObject serviceRespJavaObject = new + // ServiceRespJavaObject(); + // + // serviceRespJavaObject.setUniqueId(serviceDetails.getUniqueId()); + // serviceRespJavaObject.setName(serviceDetails.getName()); + // serviceRespJavaObject.setCreatorUserId(userId); + // serviceRespJavaObject.setCreatorFullName(userName); + // serviceRespJavaObject.setLastUpdaterUserId(userId); + // serviceRespJavaObject.setLastUpdaterFullName(userName); + // serviceRespJavaObject.setDescription(serviceDetails.getDescription()); + // serviceRespJavaObject.setIcon(serviceDetails.getIcon()); + // serviceRespJavaObject.setCategory(serviceDetails.getCategory()); + // serviceRespJavaObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + // serviceRespJavaObject.setContactId(serviceDetails.getContactId()); + // serviceRespJavaObject.setVersion(serviceVersion); + // + // return serviceRespJavaObject; + // } + + // ********** product ************** + + public static Product constructFieldsForRespValidation(ProductReqDetails productDetails, String productVersion, + User user) { + return convertToRespObject(productDetails, productVersion, user.getUserId(), user.getFullName()); + } + + private static Product convertToRespObject(ProductReqDetails productDetails, String productVersion, String userId, + String userName) { + Product expectedProduct = new Product(); + + expectedProduct.setUniqueId(productDetails.getUniqueId()); + expectedProduct.setName(productDetails.getName()); + expectedProduct.setFullName(productDetails.getFullName()); + expectedProduct.setCreatorUserId(productDetails.getCreatorUserId()); + expectedProduct.setCreatorFullName(productDetails.getCreatorFullName()); + expectedProduct.setLastUpdaterUserId(userId); + expectedProduct.setLastUpdaterFullName(userName); + expectedProduct.setDescription(productDetails.getDescription()); + // expectedProduct.setIcon(resourceDetails.getIcon()); + expectedProduct.setTags(productDetails.getTags()); + expectedProduct.setHighestVersion(true); + List categories = productDetails.getCategories(); + if (categories == null) { + categories = new ArrayList<>(); + } + expectedProduct.setCategories(categories); + expectedProduct.setState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + expectedProduct.setVersion(productVersion); + expectedProduct.setContacts(productDetails.getContacts()); + return expectedProduct; + } + + // ***** audit ***** + + public static ExpectedResourceAuditJavaObject constructFieldsForAuditValidation(ResourceReqDetails resourceDetails, + String resourceVersion) { + return convertToAuditObject(resourceDetails, resourceVersion, UserRoleEnum.ADMIN.getUserId(), + UserRoleEnum.ADMIN.getUserName()); + } + + public static ExpectedResourceAuditJavaObject constructFieldsForAuditValidation( + ResourceReqDetails resourceDetails) { + return convertToAuditObject(resourceDetails, resourceDetails.getVersion(), UserRoleEnum.ADMIN.getUserId(), + UserRoleEnum.ADMIN.getUserName()); + } + + public static ExpectedResourceAuditJavaObject constructFieldsForAuditValidation(ResourceReqDetails resourceDetails, + String resourceVersion, User user) { + return convertToAuditObject(resourceDetails, resourceVersion, user.getUserId(), user.getFullName()); + } + + private static ExpectedResourceAuditJavaObject convertToAuditObject(ResourceReqDetails resourceDetails, + String resourceVersion, String userId, String userName) { + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + + expectedResourceAuditJavaObject.setAction("Checkout"); + expectedResourceAuditJavaObject.setModifierName(userName); + expectedResourceAuditJavaObject.setModifierUid(userId); + expectedResourceAuditJavaObject.setStatus("200.0"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setResourceName(resourceDetails.getName()); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setPrevVersion(String.valueOf(Float.parseFloat(resourceVersion) - 0.1f)); + expectedResourceAuditJavaObject.setCurrVersion(resourceVersion); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setComment(null); + + return expectedResourceAuditJavaObject; + } + + public static ExpectedProductAudit constructFieldsForAuditValidation(Product productDetails, String action, + User user, ActionStatus actionStatus, String prevVersion, String currVersion, LifecycleStateEnum prevState, + LifecycleStateEnum currState, String uuid, String... errorMessageParams) throws FileNotFoundException { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(actionStatus.name()); + return convertToAuditObject(productDetails, action, user, errorInfo, prevVersion, currVersion, prevState, + currState, uuid, errorMessageParams); + } + + private static ExpectedProductAudit convertToAuditObject(Product productDetails, String action, User user, + ErrorInfo errorInfo, String prevVersion, String currVersion, LifecycleStateEnum prevState, + LifecycleStateEnum currState, String uuid, String... errorMessageParams) { + ExpectedProductAudit expectedProductAudit = new ExpectedProductAudit(); + + expectedProductAudit.setACTION(action); + String userUserId = user.getUserId(); + String userFullName; + if (StringUtils.isEmpty(user.getFirstName()) && StringUtils.isEmpty(user.getLastName())) { + userFullName = ""; + } else { + userFullName = user.getFullName(); + } + if (StringUtils.isEmpty(userUserId)) { + userUserId = "UNKNOWN"; + } + expectedProductAudit.setMODIFIER( + !StringUtils.isEmpty(userFullName) ? userFullName + "(" + userUserId + ")" : "(" + userUserId + ")"); + expectedProductAudit.setSTATUS(Integer.toString(errorInfo.getCode())); + expectedProductAudit.setDESC(errorInfo.getAuditDesc((Object[]) (errorMessageParams))); + expectedProductAudit + .setRESOURCE_NAME(productDetails != null ? productDetails.getName() : Constants.EMPTY_STRING); + expectedProductAudit.setRESOURCE_TYPE("Product"); + expectedProductAudit.setPREV_VERSION(prevVersion); + expectedProductAudit.setCURR_VERSION(currVersion); + expectedProductAudit.setPREV_STATE(prevState != null ? prevState.name() : Constants.EMPTY_STRING); + expectedProductAudit.setCURR_STATE(currState != null ? currState.name() : Constants.EMPTY_STRING); + expectedProductAudit.setSERVICE_INSTANCE_ID(uuid); + return expectedProductAudit; + } + + //////////////// + // Convertor.constructFieldsForAuditValidationSuccess(addUser, + //////////////// sdncAdminUser, mechIdUser, null, STATUS_CODE_CREATED); + public static ExpectedUserCRUDAudit constructFieldsForAuditValidation(String action, User userModifier, + ActionStatus actionStatus, User userAfter, User userBefore, Object... variables) throws Exception { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(actionStatus.name()); + ExpectedUserCRUDAudit expectedAddUserAuditJavaObject = new ExpectedUserCRUDAudit(); + expectedAddUserAuditJavaObject.setAction(action); + expectedAddUserAuditJavaObject.setModifier( + userModifier.getFirstName() != null ? userModifier.getFullName() + "(" + userModifier.getUserId() + ")" + : "(" + userModifier.getUserId() + ")"); + String status = Integer.toString(errorInfo.getCode()); + expectedAddUserAuditJavaObject.setStatus(status); + if (errorInfo.getCode() == STATUS_CODE_SUCCESS || errorInfo.getCode() == STATUS_CODE_CREATED) { + expectedAddUserAuditJavaObject.setDesc("OK"); + } else { + expectedAddUserAuditJavaObject.setDesc(errorInfo.getAuditDesc(variables)); + } + expectedAddUserAuditJavaObject.setUserBefore(userBefore != null + ? userBefore.getUserId() + ", " + userBefore.getFirstName() + " " + userBefore.getLastName() + ", " + + userBefore.getEmail() + ", " + userBefore.getRole() + : Constants.EMPTY_STRING); + expectedAddUserAuditJavaObject.setUserAfter(userAfter != null + ? userAfter.getUserId() + ", " + userAfter.getFirstName() + " " + userAfter.getLastName() + ", " + + userAfter.getEmail() + ", " + userAfter.getRole() + : Constants.EMPTY_STRING); + return expectedAddUserAuditJavaObject; + } + + // For RESOURCE and SERVICE same Audit + public static ExpectedResourceAuditJavaObject constructFieldsForAuditValidation( + ComponentReqDetails componentDetails, String action, User userModifier, ActionStatus actionStatus, + String currVersion, String prevVersion, String curState, String prevState, String uuid, String comment, + Object... variables) throws Exception { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(actionStatus.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(action); + expectedResourceAuditJavaObject.setMODIFIER( + userModifier.getFirstName() != null ? userModifier.getFullName() + "(" + userModifier.getUserId() + ")" + : "(" + userModifier.getUserId() + ")"); + String status = Integer.toString(errorInfo.getCode()); + expectedResourceAuditJavaObject.setStatus(status); + if (errorInfo.getCode() == STATUS_CODE_SUCCESS || errorInfo.getCode() == STATUS_CODE_CREATED) { + expectedResourceAuditJavaObject.setDesc("OK"); + } else { + expectedResourceAuditJavaObject.setDesc(errorInfo.getAuditDesc(variables)); + } + expectedResourceAuditJavaObject.setCurrState(curState); + expectedResourceAuditJavaObject.setPrevState(prevState); + expectedResourceAuditJavaObject.setCurrVersion(currVersion); + expectedResourceAuditJavaObject.setPrevVersion(prevVersion); + expectedResourceAuditJavaObject.setComment(comment); + expectedResourceAuditJavaObject.setSERVICE_INSTANCE_ID(uuid); + if (componentDetails instanceof ServiceReqDetails) { + expectedResourceAuditJavaObject.setResourceName(((ServiceReqDetails) componentDetails).getName()); + expectedResourceAuditJavaObject.setResourceType("Service"); + } + if (componentDetails instanceof ResourceReqDetails) { + expectedResourceAuditJavaObject.setResourceName(((ResourceReqDetails) componentDetails).getName()); + expectedResourceAuditJavaObject.setResourceType("Resource"); + } + return expectedResourceAuditJavaObject; + } + + // Distribution Service Audit + public static ExpectedResourceAuditJavaObject constructFieldsForDistributionAuditValidation( + ComponentReqDetails componentDetails, String action, User userModifier, ActionStatus actionStatus, + String currVersion, String distCurrStatus, String distProvStatus, String curState, String uuid, + String comment, Object... variables) throws Exception { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(actionStatus.name()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(action); + expectedResourceAuditJavaObject.setMODIFIER( + userModifier.getFirstName() != null ? userModifier.getFullName() + "(" + userModifier.getUserId() + ")" + : "(" + userModifier.getUserId() + ")"); + String status = Integer.toString(errorInfo.getCode()); + expectedResourceAuditJavaObject.setStatus(status); + if (errorInfo.getCode() == STATUS_CODE_SUCCESS || errorInfo.getCode() == STATUS_CODE_CREATED) { + expectedResourceAuditJavaObject.setDesc("OK"); + } else { + expectedResourceAuditJavaObject.setDesc(errorInfo.getAuditDesc(variables)); + } + expectedResourceAuditJavaObject.setCurrState(curState); + expectedResourceAuditJavaObject.setCurrVersion(currVersion); + expectedResourceAuditJavaObject.setDcurrStatus(distCurrStatus); + expectedResourceAuditJavaObject.setDprevStatus(distProvStatus); + expectedResourceAuditJavaObject.setComment(comment); + expectedResourceAuditJavaObject.setSERVICE_INSTANCE_ID(uuid); + if (componentDetails instanceof ServiceReqDetails) { + expectedResourceAuditJavaObject.setResourceName(((ServiceReqDetails) componentDetails).getName()); + expectedResourceAuditJavaObject.setResourceType("Service"); + } + return expectedResourceAuditJavaObject; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/ElementFactory.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/ElementFactory.java new file mode 100644 index 0000000000..5c23b5f3fe --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/ElementFactory.java @@ -0,0 +1,997 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.general; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.lang.StringUtils; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.RelationshipImpl; +import org.openecomp.sdc.be.model.RequirementAndRelationshipPair; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.PropertyReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceExternalReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedExternalAudit; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.util.ValidationUtils; + +public class ElementFactory { + + private static final String CI_SERVICE = "ciService"; + private static final String CI_RES = "ciRes"; + private static final String CI_PRODUCT = "CiProduct"; + private static String DEFAULT_ARTIFACT_LABEL = "artifact1"; + private static final String RESOURCE_INSTANCE_POS_X = "20"; + private static final String RESOURCE_INSTANCE_POS_Y = "20"; + private static final String RESOURCE_INSTANCE_DESCRIPTION = "description"; + + // *** RESOURCE *** + + public static ResourceReqDetails getDefaultResource() { + return getDefaultResource(CI_RES, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, "jh0003"); + } + + public static ResourceReqDetails getDefaultResource(ResourceCategoryEnum category) { + return getDefaultResource(CI_RES, NormativeTypesEnum.ROOT, category, "jh0003"); + } + + public static ResourceReqDetails getDefaultResource(String contactId) { + return getDefaultResource(CI_RES, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, contactId); + } + + public static ResourceReqDetails getDefaultResource(User modifier) { + return getDefaultResource(CI_RES, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, modifier.getUserId()); + } + + public static ResourceReqDetails getDefaultResource(NormativeTypesEnum derivedFrom, ResourceCategoryEnum category) { + return getDefaultResource(CI_RES, derivedFrom, category, "jh0003"); + } + + public static ResourceReqDetails getDefaultResource(NormativeTypesEnum derivedFrom) { + return getDefaultResource(CI_RES, derivedFrom, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, "jh0003"); + } + + public static ResourceReqDetails getDefaultResource(String resourceName, NormativeTypesEnum derivedFrom) { + return getDefaultResource(resourceName, derivedFrom, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, "jh0003"); + } + + public static ResourceReqDetails getDefaultResource(NormativeTypesEnum derivedFrom, String contactId) { + return getDefaultResource(CI_RES, derivedFrom, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, contactId); + } + + // New + public static ResourceReqDetails getDefaultResourceByType(ResourceTypeEnum ResourceType, String resourceName) { + return getDefaultResourceByType(resourceName, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, "jh0003", ResourceType.toString()); + } + + public static ResourceReqDetails getDefaultResourceByType(ResourceTypeEnum ResourceType, User user) { + return getDefaultResourceByType(CI_RES, NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_LOAD_BALANCER, user.getUserId(), ResourceType.toString()); + } + + public static ResourceReqDetails getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum resourceType, NormativeTypesEnum normativeTypes, ResourceCategoryEnum resourceCategory, User user) { + return getDefaultResourceByType(CI_RES, normativeTypes, resourceCategory, user.getUserId(), resourceType.toString()); + } + + public static PropertyReqDetails getDefaultMapProperty(PropertyTypeEnum innerType) { + return getPropertyDetails(innerType); + } + + public static PropertyReqDetails getDefaultMapProperty() { + return getPropertyDetails(PropertyTypeEnum.STRING_MAP); + } + + public static ResourceReqDetails getDefaultResource(String resourceName, NormativeTypesEnum derived, ResourceCategoryEnum category, String contactId) { + resourceName = (resourceName + generateUUIDforSufix()); + String description = "Represents a generic software component that can be managed and run by a Compute Node Type."; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(derived.normativeName); + String vendorName = "ATT Tosca"; + String vendorRelease = "1.0.0.wd03"; + String icon = "defaulticon"; + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, null, derivedFrom, vendorName, vendorRelease, contactId, icon); + resourceDetails.addCategoryChain(category.getCategory(), category.getSubCategory()); + + return resourceDetails; + + } + + public static ResourceReqDetails getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum resourceType, Resource normativeTypes, ResourceCategoryEnum resourceCategory, User user) { + return getDefaultResource(CI_RES + resourceType, normativeTypes, resourceCategory, user.getUserId()); + } + + public static ResourceReqDetails getDefaultResource(String resourceName, Resource derived, ResourceCategoryEnum category, String contactId) { + resourceName = (resourceName + generateUUIDforSufix()); + String description = "Represents a generic software component that can be managed and run by a Compute Node Type."; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + + ArrayList derivedFrom = new ArrayList(); + derivedFrom.add(derived.getToscaResourceName()); + String vendorName = "ATT Tosca"; + String vendorRelease = "1.0.0.wd03"; + String icon = "defaulticon"; + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, null, derivedFrom, vendorName, vendorRelease, contactId, icon); + resourceDetails.addCategoryChain(category.getCategory(), category.getSubCategory()); + + return resourceDetails; + + } + + public static ResourceReqDetails getDefaultResourceByType(String resourceName, NormativeTypesEnum derived, ResourceCategoryEnum category, String contactId, ResourceTypeEnum resourceType) { + return getDefaultResourceByType(resourceName, derived, category, contactId, resourceType.toString()); + } + + // New + public static ResourceReqDetails getDefaultResourceByType(String resourceName, NormativeTypesEnum derived, ResourceCategoryEnum category, String contactId, String resourceType) { + resourceName = (resourceName + resourceType + generateUUIDforSufix()); + String description = "Represents a generic software component that can be managed and run by a Compute Node Type."; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + ArrayList derivedFrom = null; + if (derived != null) { + derivedFrom = new ArrayList(); + derivedFrom.add(derived.normativeName); + } + String vendorName = "ATT Tosca"; + String vendorRelease = "1.0.0.wd03"; + String icon = "defaulticon"; + ResourceReqDetails resourceDetails = new ResourceReqDetails(resourceName, description, resourceTags, null, derivedFrom, vendorName, vendorRelease, contactId, icon, resourceType.toString()); + resourceDetails.addCategoryChain(category.getCategory(), category.getSubCategory()); + return resourceDetails; + } + + public static ResourceExternalReqDetails getDefaultResourceByType(String resourceName, ResourceCategoryEnum category, String contactId, String resourceType) { + resourceName = (resourceName + resourceType + generateUUIDforSufix()); + String description = "Represents a generic software component that can be managed and run by a Compute Node Type."; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + String vendorName = "ATT Tosca"; + String vendorRelease = "1.0.0.wd03"; + String icon = "defaulticon"; + ResourceExternalReqDetails resourceDetails = new ResourceExternalReqDetails(resourceName, description, resourceTags, + vendorName, vendorRelease, contactId, icon, + resourceType.toString(), category.getCategory(), category.getSubCategory()); + return resourceDetails; + } + + // New + public static ImportReqDetails getDefaultImportResourceByType(String resourceName, NormativeTypesEnum derived, ResourceCategoryEnum category, String contactId, String resourceType) { + resourceName = (resourceName + resourceType + generateUUIDforSufix()); + String description = "Represents a generic software component that can be managed and run by a Compute Node Type."; + ArrayList resourceTags = new ArrayList(); + resourceTags.add(resourceName); + ArrayList derivedFrom = null; + if (derived != null) { + derivedFrom = new ArrayList(); + derivedFrom.add(derived.normativeName); + } + String vendorName = "ATT Tosca"; + String vendorRelease = "1.0.0.wd03"; + String icon = "defaulticon"; + ImportReqDetails resourceDetails = new ImportReqDetails(resourceName, description, resourceTags, derivedFrom, vendorName, vendorRelease, contactId, icon); + resourceDetails.addCategoryChain(category.getCategory(), category.getSubCategory()); + return resourceDetails; + } + //// + + public static ImportReqDetails getDefaultImportResource(ResourceReqDetails resourceReqDetails) { + ImportReqDetails importReqDetails = new ImportReqDetails(resourceReqDetails.getName(), resourceReqDetails.getDescription(), resourceReqDetails.getTags(), resourceReqDetails.getDerivedFrom(), resourceReqDetails.getVendorName(), + resourceReqDetails.getVendorRelease(), resourceReqDetails.getContactId(), resourceReqDetails.getIcon()); + importReqDetails.setPayloadName("myCompute.yaml"); + importReqDetails.setCategories(resourceReqDetails.getCategories()); + importReqDetails.setPayloadData( + "dG9zY2FfZGVmaW5pdGlvbnNfdmVyc2lvbjogdG9zY2Ffc2ltcGxlX3lhbWxfMV8wXzANCm5vZGVfdHlwZXM6IA0KICBjb20uYXR0LmQyLnJlc291cmNlLk15Q29tcHV0ZToNCiAgICBkZXJpdmVkX2Zyb206IHRvc2NhLm5vZGVzLlJvb3QNCiAgICBhdHRyaWJ1dGVzOg0KICAgICAgcHJpdmF0ZV9hZGRyZXNzOg0KICAgICAgICB0eXBlOiBzdHJpbmcNCiAgICAgIHB1YmxpY19hZGRyZXNzOg0KICAgICAgICB0eXBlOiBzdHJpbmcNCiAgICAgIG5ldHdvcmtzOg0KICAgICAgICB0eXBlOiBtYXANCiAgICAgICAgZW50cnlfc2NoZW1hOg0KICAgICAgICAgIHR5cGU6IHRvc2NhLmRhdGF0eXBlcy5uZXR3b3JrLk5ldHdvcmtJbmZvDQogICAgICBwb3J0czoNCiAgICAgICAgdHlwZTogbWFwDQogICAgICAgIGVudHJ5X3NjaGVtYToNCiAgICAgICAgICB0eXBlOiB0b3NjYS5kYXRhdHlwZXMubmV0d29yay5Qb3J0SW5mbw0KICAgIHJlcXVpcmVtZW50czoNCiAgICAgIC0gbG9jYWxfc3RvcmFnZTogDQogICAgICAgICAgY2FwYWJpbGl0eTogdG9zY2EuY2FwYWJpbGl0aWVzLkF0dGFjaG1lbnQNCiAgICAgICAgICBub2RlOiB0b3NjYS5ub2Rlcy5CbG9ja1N0b3JhZ2UNCiAgICAgICAgICByZWxhdGlvbnNoaXA6IHRvc2NhLnJlbGF0aW9uc2hpcHMuQXR0YWNoZXNUbw0KICAgICAgICAgIG9jY3VycmVuY2VzOiBbMCwgVU5CT1VOREVEXSAgDQogICAgY2FwYWJpbGl0aWVzOg0KICAgICAgaG9zdDogDQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5Db250YWluZXINCiAgICAgICAgdmFsaWRfc291cmNlX3R5cGVzOiBbdG9zY2Eubm9kZXMuU29mdHdhcmVDb21wb25lbnRdIA0KICAgICAgZW5kcG9pbnQgOg0KICAgICAgICB0eXBlOiB0b3NjYS5jYXBhYmlsaXRpZXMuRW5kcG9pbnQuQWRtaW4gDQogICAgICBvczogDQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5PcGVyYXRpbmdTeXN0ZW0NCiAgICAgIHNjYWxhYmxlOg0KICAgICAgICB0eXBlOiB0b3NjYS5jYXBhYmlsaXRpZXMuU2NhbGFibGUNCiAgICAgIGJpbmRpbmc6DQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5uZXR3b3JrLkJpbmRhYmxlDQo="); + return importReqDetails; + } + + public static ImportReqDetails getDefaultImportResource() { + ResourceReqDetails resourceReqDetails = getDefaultResource(); + ImportReqDetails importReqDetails = new ImportReqDetails(resourceReqDetails.getName(), resourceReqDetails.getDescription(), resourceReqDetails.getTags(), resourceReqDetails.getDerivedFrom(), resourceReqDetails.getVendorName(), + resourceReqDetails.getVendorRelease(), resourceReqDetails.getContactId(), resourceReqDetails.getIcon()); + importReqDetails.setPayloadName("myCompute.yaml"); + importReqDetails.setCategories(resourceReqDetails.getCategories()); + importReqDetails.setPayloadData( + "dG9zY2FfZGVmaW5pdGlvbnNfdmVyc2lvbjogdG9zY2Ffc2ltcGxlX3lhbWxfMV8wXzANCm5vZGVfdHlwZXM6IA0KICBjb20uYXR0LmQyLnJlc291cmNlLk15Q29tcHV0ZToNCiAgICBkZXJpdmVkX2Zyb206IHRvc2NhLm5vZGVzLlJvb3QNCiAgICBhdHRyaWJ1dGVzOg0KICAgICAgcHJpdmF0ZV9hZGRyZXNzOg0KICAgICAgICB0eXBlOiBzdHJpbmcNCiAgICAgIHB1YmxpY19hZGRyZXNzOg0KICAgICAgICB0eXBlOiBzdHJpbmcNCiAgICAgIG5ldHdvcmtzOg0KICAgICAgICB0eXBlOiBtYXANCiAgICAgICAgZW50cnlfc2NoZW1hOg0KICAgICAgICAgIHR5cGU6IHRvc2NhLmRhdGF0eXBlcy5uZXR3b3JrLk5ldHdvcmtJbmZvDQogICAgICBwb3J0czoNCiAgICAgICAgdHlwZTogbWFwDQogICAgICAgIGVudHJ5X3NjaGVtYToNCiAgICAgICAgICB0eXBlOiB0b3NjYS5kYXRhdHlwZXMubmV0d29yay5Qb3J0SW5mbw0KICAgIHJlcXVpcmVtZW50czoNCiAgICAgIC0gbG9jYWxfc3RvcmFnZTogDQogICAgICAgICAgY2FwYWJpbGl0eTogdG9zY2EuY2FwYWJpbGl0aWVzLkF0dGFjaG1lbnQNCiAgICAgICAgICBub2RlOiB0b3NjYS5ub2Rlcy5CbG9ja1N0b3JhZ2UNCiAgICAgICAgICByZWxhdGlvbnNoaXA6IHRvc2NhLnJlbGF0aW9uc2hpcHMuQXR0YWNoZXNUbw0KICAgICAgICAgIG9jY3VycmVuY2VzOiBbMCwgVU5CT1VOREVEXSAgDQogICAgY2FwYWJpbGl0aWVzOg0KICAgICAgaG9zdDogDQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5Db250YWluZXINCiAgICAgICAgdmFsaWRfc291cmNlX3R5cGVzOiBbdG9zY2Eubm9kZXMuU29mdHdhcmVDb21wb25lbnRdIA0KICAgICAgZW5kcG9pbnQgOg0KICAgICAgICB0eXBlOiB0b3NjYS5jYXBhYmlsaXRpZXMuRW5kcG9pbnQuQWRtaW4gDQogICAgICBvczogDQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5PcGVyYXRpbmdTeXN0ZW0NCiAgICAgIHNjYWxhYmxlOg0KICAgICAgICB0eXBlOiB0b3NjYS5jYXBhYmlsaXRpZXMuU2NhbGFibGUNCiAgICAgIGJpbmRpbmc6DQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5uZXR3b3JrLkJpbmRhYmxlDQo="); + return importReqDetails; + } + + public static ImportReqDetails getDefaultImportResource(String name) { + ResourceReqDetails resourceReqDetails = getDefaultResourceByType(ResourceTypeEnum.VFC, name); + ImportReqDetails importReqDetails = new ImportReqDetails(resourceReqDetails.getName(), resourceReqDetails.getDescription(), resourceReqDetails.getTags(), resourceReqDetails.getDerivedFrom(), resourceReqDetails.getVendorName(), + resourceReqDetails.getVendorRelease(), resourceReqDetails.getContactId(), resourceReqDetails.getIcon()); + importReqDetails.setPayloadName("myCompute.yaml"); + importReqDetails.setCategories(resourceReqDetails.getCategories()); + importReqDetails.setPayloadData( + "dG9zY2FfZGVmaW5pdGlvbnNfdmVyc2lvbjogdG9zY2Ffc2ltcGxlX3lhbWxfMV8wXzANCm5vZGVfdHlwZXM6IA0KICBjb20uYXR0LmQyLnJlc291cmNlLk15Q29tcHV0ZToNCiAgICBkZXJpdmVkX2Zyb206IHRvc2NhLm5vZGVzLlJvb3QNCiAgICBhdHRyaWJ1dGVzOg0KICAgICAgcHJpdmF0ZV9hZGRyZXNzOg0KICAgICAgICB0eXBlOiBzdHJpbmcNCiAgICAgIHB1YmxpY19hZGRyZXNzOg0KICAgICAgICB0eXBlOiBzdHJpbmcNCiAgICAgIG5ldHdvcmtzOg0KICAgICAgICB0eXBlOiBtYXANCiAgICAgICAgZW50cnlfc2NoZW1hOg0KICAgICAgICAgIHR5cGU6IHRvc2NhLmRhdGF0eXBlcy5uZXR3b3JrLk5ldHdvcmtJbmZvDQogICAgICBwb3J0czoNCiAgICAgICAgdHlwZTogbWFwDQogICAgICAgIGVudHJ5X3NjaGVtYToNCiAgICAgICAgICB0eXBlOiB0b3NjYS5kYXRhdHlwZXMubmV0d29yay5Qb3J0SW5mbw0KICAgIHJlcXVpcmVtZW50czoNCiAgICAgIC0gbG9jYWxfc3RvcmFnZTogDQogICAgICAgICAgY2FwYWJpbGl0eTogdG9zY2EuY2FwYWJpbGl0aWVzLkF0dGFjaG1lbnQNCiAgICAgICAgICBub2RlOiB0b3NjYS5ub2Rlcy5CbG9ja1N0b3JhZ2UNCiAgICAgICAgICByZWxhdGlvbnNoaXA6IHRvc2NhLnJlbGF0aW9uc2hpcHMuQXR0YWNoZXNUbw0KICAgICAgICAgIG9jY3VycmVuY2VzOiBbMCwgVU5CT1VOREVEXSAgDQogICAgY2FwYWJpbGl0aWVzOg0KICAgICAgaG9zdDogDQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5Db250YWluZXINCiAgICAgICAgdmFsaWRfc291cmNlX3R5cGVzOiBbdG9zY2Eubm9kZXMuU29mdHdhcmVDb21wb25lbnRdIA0KICAgICAgZW5kcG9pbnQgOg0KICAgICAgICB0eXBlOiB0b3NjYS5jYXBhYmlsaXRpZXMuRW5kcG9pbnQuQWRtaW4gDQogICAgICBvczogDQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5PcGVyYXRpbmdTeXN0ZW0NCiAgICAgIHNjYWxhYmxlOg0KICAgICAgICB0eXBlOiB0b3NjYS5jYXBhYmlsaXRpZXMuU2NhbGFibGUNCiAgICAgIGJpbmRpbmc6DQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5uZXR3b3JrLkJpbmRhYmxlDQo="); + return importReqDetails; + } + + // *** SERVICE *** + public static ServiceReqDetails getDefaultService() { + return getDefaultService(CI_SERVICE, ServiceCategoriesEnum.MOBILITY, "al1976"); + } + + public static ServiceReqDetails getDefaultService(String contactId) { + return getDefaultService(CI_SERVICE, ServiceCategoriesEnum.MOBILITY, contactId); + } + + public static ServiceReqDetails getDefaultService(User user) { + return getDefaultService(CI_SERVICE, ServiceCategoriesEnum.MOBILITY, user.getUserId()); + } + + public static ServiceReqDetails getService(ServiceCategoriesEnum category) { + return getDefaultService(CI_SERVICE, category, "al1976"); + } + + public static ServiceReqDetails getDefaultService(ServiceCategoriesEnum category, User user) { + return getDefaultService(CI_SERVICE, category, user.getUserId()); + } + + public static ServiceReqDetails getDefaultService(String serviceName, ServiceCategoriesEnum category, String contactId) { + serviceName = (serviceName + generateUUIDforSufix()); + ArrayList tags = new ArrayList(); + tags.add("serviceTag"); + tags.add("serviceTag1"); + tags.add(serviceName); + String description = "service Description"; + String icon = "myIcon"; + + ServiceReqDetails serviceDetails = new ServiceReqDetails(serviceName, category.getValue(), tags, description, contactId, icon); + + return serviceDetails; + } + + // ***** PROPERTY *** + + public static PropertyReqDetails getDefaultProperty() { + return getDefaultProperty("disk_size"); + } + + public static PropertyReqDetails getDefaultProperty(String propertyName) { + PropertyReqDetails property = new PropertyReqDetails(); + property.setName(propertyName); + property.setPropertyType("integer"); + property.setPropertyRequired(false); + property.setPropertyDefaultValue("12345"); + property.setPropertyDescription("test property"); + property.setPropertyRangeMax("500"); + property.setPropertyRangeMin("100"); + property.setPropertyPassword(false); + return property; + } + + public static PropertyReqDetails getDefaultIntegerProperty() { + return getPropertyDetails(PropertyTypeEnum.INTEGER); + } + + public static PropertyReqDetails getDefaultStringProperty() { + return getPropertyDetails(PropertyTypeEnum.STRING); + } + + public static PropertyReqDetails getDefaultBooleanProperty() { + return getPropertyDetails(PropertyTypeEnum.BOOLEAN); + } + + public static PropertyReqDetails getDefaultListProperty() { + return getPropertyDetails(PropertyTypeEnum.STRING_LIST); + } + + public static PropertyReqDetails getDefaultListProperty(PropertyTypeEnum innerType) { + return getPropertyDetails(innerType); + } + + public static PropertyReqDetails getPropertyDetails(PropertyTypeEnum propType) { + return new PropertyReqDetails(propType.getName(), propType.getType(), propType.getValue(), propType.getDescription(), propType.getSchemaDefinition()); + } + + // ***** RESOURCE INSTANCE *** + public static ComponentInstanceReqDetails getDefaultComponentInstance() { + return getDefaultComponentInstance("resourceInstanceName"); + } + + public static ComponentInstanceReqDetails getDefaultComponentInstance(String name) { + String resourceUid = "resourceId"; + ComponentInstanceReqDetails resourceInstanceDetails = new ComponentInstanceReqDetails(resourceUid, RESOURCE_INSTANCE_DESCRIPTION, RESOURCE_INSTANCE_POS_X, RESOURCE_INSTANCE_POS_Y, name); + + return resourceInstanceDetails; + + } + + public static ComponentInstanceReqDetails getDefaultComponentInstance(String name, ComponentReqDetails componentReqDetails) { + String resourceUid = componentReqDetails.getUniqueId(); + ComponentInstanceReqDetails resourceInstanceDetails = new ComponentInstanceReqDetails(resourceUid, RESOURCE_INSTANCE_DESCRIPTION, RESOURCE_INSTANCE_POS_X, RESOURCE_INSTANCE_POS_Y, name); + + return resourceInstanceDetails; + + } + + public static ComponentInstanceReqDetails getComponentResourceInstance(ComponentReqDetails compInstOriginDetails) { + String compInstName = (compInstOriginDetails.getName() != null ? compInstOriginDetails.getName() : "resourceInstanceName"); + String resourceUid = compInstOriginDetails.getUniqueId(); + ComponentInstanceReqDetails resourceInstanceDetails = new ComponentInstanceReqDetails(resourceUid, RESOURCE_INSTANCE_DESCRIPTION, RESOURCE_INSTANCE_POS_X, RESOURCE_INSTANCE_POS_Y, compInstName); + return resourceInstanceDetails; + + } + + public static ComponentInstanceReqDetails getComponentInstance(Component compInstOriginDetails) { + String compInstName = (compInstOriginDetails.getName() != null ? compInstOriginDetails.getName() : "componentInstanceName"); + String compInsUid = compInstOriginDetails.getUniqueId(); + ComponentInstanceReqDetails componentInstanceDetails = new ComponentInstanceReqDetails(compInsUid, RESOURCE_INSTANCE_DESCRIPTION, RESOURCE_INSTANCE_POS_X, RESOURCE_INSTANCE_POS_Y, compInstName); + return componentInstanceDetails; + + } + + // ******* USER ********************** + public static User getDefaultUser(UserRoleEnum userRole) { + User sdncModifierDetails = new User(); + sdncModifierDetails.setUserId(userRole.getUserId()); + sdncModifierDetails.setFirstName(userRole.getFirstName()); + sdncModifierDetails.setLastName(userRole.getLastName()); + return sdncModifierDetails; + } + + public static User getDefaultMechUser() { + User sdncMechUserDetails = new User(); + sdncMechUserDetails.setUserId("m12345"); + sdncMechUserDetails.setFirstName("Fishi"); + sdncMechUserDetails.setLastName("Shifi"); + sdncMechUserDetails.setEmail("mechId@intl.sdc.com"); + sdncMechUserDetails.setRole("DESIGNER"); + return sdncMechUserDetails; + } + + // ******* CONSUMER ********************** + + public static ConsumerDataDefinition getDefaultConsumerDetails() { + ConsumerDataDefinition consumer = new ConsumerDataDefinition(); + consumer.setConsumerName("ci"); + consumer.setConsumerSalt("2a1f887d607d4515d4066fe0f5452a50"); + consumer.setConsumerPassword("0a0dc557c3bf594b1a48030e3e99227580168b21f44e285c69740b8d5b13e33b"); + return consumer; + } + + // *** ARTIFACT *** + public static ArtifactReqDetails getDefaultArtifact() throws IOException, Exception { + return getDefaultArtifact(DEFAULT_ARTIFACT_LABEL); + } + + public static ArtifactReqDetails getDefaultArtifact(String artifactLabel) throws IOException, Exception { + List artifactTypes = ResponseParser.getValuesFromJsonArray(ArtifactRestUtils.getArtifactTypesList()); + String artifactType = artifactTypes.get(0); + + return getDefaultArtifact(artifactLabel, artifactType); + } + + public static ArtifactReqDetails getDefaultArtifact(String artifactLabel, String artifactType) throws IOException, Exception { + + String artifactName = "testArtifact.sh"; + String artifactDescription = "descriptionTest"; + String payloadData = "dGVzdA=="; // content of file + + ArtifactReqDetails artifactDetails = new ArtifactReqDetails(artifactName, artifactType, artifactDescription, payloadData, artifactLabel); + artifactDetails.setUrl(""); + artifactDetails.setArtifactDisplayName(artifactLabel); + return artifactDetails; + } + + public static ArtifactReqDetails getServiceApiArtifactDetails(String artifactLabel) throws IOException, Exception { + ArtifactReqDetails defaultArtifact = getDefaultArtifact(artifactLabel, "OTHER"); + defaultArtifact.setUrl("http://www.apple.com"); + defaultArtifact.setServiceApi(true); + defaultArtifact.setArtifactDisplayName(StringUtils.capitalize(defaultArtifact.getArtifactLabel())); + return defaultArtifact; + } + + public static ArtifactReqDetails getDefaultDeploymentArtifactForType(String artifactType) throws IOException, Exception { + return getArtifactByType(DEFAULT_ARTIFACT_LABEL, artifactType, true, false); + } + + public static ArtifactReqDetails getArtifactByType(ArtifactTypeEnum artifactLabel, ArtifactTypeEnum artifactType, Boolean deploymentTrue) throws IOException, Exception { + return getArtifactByType(DEFAULT_ARTIFACT_LABEL, artifactType.toString(), deploymentTrue, false); + + } + + public static ArtifactReqDetails getArtifactByType(String artifactLabel, String artifactType, Boolean deploymentTrue, Boolean updatedPayload) throws IOException, Exception { + String artifactName; + String updatedPayloadData =null; + String payloadData = null; + Integer timeout = null; + String url = ""; + String artifactDescription = "descriptionTest"; + + // PLEASE NOTE!!! + // The non-default payloads here are real ones according to various + // types validations, + // Please don't change them unless you know what you are doing! + + ArtifactTypeEnum artifactTypeEnum = ArtifactTypeEnum.findType(artifactType); + + /* + * Missing file type: DCAE_JSON + */ + switch (artifactTypeEnum) { + case DCAE_INVENTORY_TOSCA: + case DCAE_EVENT: + case APPC_CONFIG: + case DCAE_DOC: + case DCAE_TOSCA: + case HEAT: + case HEAT_NET: + case HEAT_VOL: { + artifactName = generateUUIDforSufix() + artifactType + "_install_apache2.yaml"; + payloadData = "aGVhdF90ZW1wbGF0ZV92ZXJzaW9uOiAyMDEzLTA1LTIzDQoNCmRlc2NyaXB0aW9uOiBTaW1wbGUgdGVtcGxhdGUgdG8gZGVwbG95IGEgc3RhY2sgd2l0aCB0d28gdmlydHVhbCBtYWNoaW5lIGluc3RhbmNlcw0KDQpwYXJhbWV0ZXJzOg0KICBpbWFnZV9uYW1lXzE6DQogICAgdHlwZTogc3RyaW5nDQogICAgbGFiZWw6IEltYWdlIE5hbWUNCiAgICBkZXNjcmlwdGlvbjogU0NPSU1BR0UgU3BlY2lmeSBhbiBpbWFnZSBuYW1lIGZvciBpbnN0YW5jZTENCiAgICBkZWZhdWx0OiBjaXJyb3MtMC4zLjEteDg2XzY0DQogIGltYWdlX25hbWVfMjoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogSW1hZ2UgTmFtZQ0KICAgIGRlc2NyaXB0aW9uOiBTQ09JTUFHRSBTcGVjaWZ5IGFuIGltYWdlIG5hbWUgZm9yIGluc3RhbmNlMg0KICAgIGRlZmF1bHQ6IGNpcnJvcy0wLjMuMS14ODZfNjQNCiAgbmV0d29ya19pZDoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogTmV0d29yayBJRA0KICAgIGRlc2NyaXB0aW9uOiBTQ09ORVRXT1JLIE5ldHdvcmsgdG8gYmUgdXNlZCBmb3IgdGhlIGNvbXB1dGUgaW5zdGFuY2UNCiAgICBoaWRkZW46IHRydWUNCiAgICBjb25zdHJhaW50czoNCiAgICAgIC0gbGVuZ3RoOiB7IG1pbjogNiwgbWF4OiA4IH0NCiAgICAgICAgZGVzY3JpcHRpb246IFBhc3N3b3JkIGxlbmd0aCBtdXN0IGJlIGJldHdlZW4gNiBhbmQgOCBjaGFyYWN0ZXJzLg0KICAgICAgLSByYW5nZTogeyBtaW46IDYsIG1heDogOCB9DQogICAgICAgIGRlc2NyaXB0aW9uOiBSYW5nZSBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3ZhbHVlczoNCiAgICAgICAgLSBtMS5zbWFsbA0KICAgICAgICAtIG0xLm1lZGl1bQ0KICAgICAgICAtIG0xLmxhcmdlDQogICAgICAgIGRlc2NyaXB0aW9uOiBBbGxvd2VkIHZhbHVlcyBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbYS16QS1aMC05XSsiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IGNvbnNpc3Qgb2YgY2hhcmFjdGVycyBhbmQgbnVtYmVycyBvbmx5Lg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbQS1aXStbYS16QS1aMC05XSoiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IHN0YXJ0IHdpdGggYW4gdXBwZXJjYXNlIGNoYXJhY3Rlci4NCiAgICAgIC0gY3VzdG9tX2NvbnN0cmFpbnQ6IG5vdmEua2V5cGFpcg0KICAgICAgICBkZXNjcmlwdGlvbjogQ3VzdG9tIGRlc2NyaXB0aW9uDQoNCnJlc291cmNlczoNCiAgbXlfaW5zdGFuY2UxOg0KICAgIHR5cGU6IE9TOjpOb3ZhOjpTZXJ2ZXINCiAgICBwcm9wZXJ0aWVzOg0KICAgICAgaW1hZ2U6IHsgZ2V0X3BhcmFtOiBpbWFnZV9uYW1lXzEgfQ0KICAgICAgZmxhdm9yOiBtMS5zbWFsbA0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9DQogIG15X2luc3RhbmNlMjoNCiAgICB0eXBlOiBPUzo6Tm92YTo6U2VydmVyDQogICAgcHJvcGVydGllczoNCiAgICAgIGltYWdlOiB7IGdldF9wYXJhbTogaW1hZ2VfbmFtZV8yIH0NCiAgICAgIGZsYXZvcjogbTEudGlueQ0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9"; + updatedPayloadData = "dG9zY2FfZGVmaW5pdGlvbnNfdmVyc2lvbjogdG9zY2Ffc2ltcGxlX3lhbWxfMV8wXzANCg0Kbm9kZV90eXBlczoNCiAgY29tLmF0dC5kMi5yZXNvdXJjZS5jcC5DUDoNCiAgICBkZXJpdmVkX2Zyb206IHRvc2NhLm5vZGVzLm5ldHdvcmsuUG9ydA0KICAgIHByb3BlcnRpZXM6DQogICAgICBpc190YWdnZWQ6DQogICAgICAgIHR5cGU6IGJvb2xlYW4NCiAgICAgICAgcmVxdWlyZWQ6IGZhbHNlDQogICAgICAgIGRlZmF1bHQ6IGZhbHNlDQogICAgICAgIGRlc2NyaXB0aW9uOiANCg0KICAgIHJlcXVpcmVtZW50czoNCiAgICAgIC0gdmlydHVhbExpbms6DQogICAgICAgICAgY2FwYWJpbGl0eTogdG9zY2EuY2FwYWJpbGl0aWVzLm5ldHdvcmsuTGlua2FibGUNCiAgICAgICAgICByZWxhdGlvbnNoaXA6IHRvc2NhLnJlbGF0aW9uc2hpcHMubmV0d29yay5MaW5rc1RvDQogICAgICAtIHZpcnR1YWxCaW5kaW5nOg0KICAgICAgICAgIGNhcGFiaWxpdHk6IHRvc2NhLmNhcGFiaWxpdGllcy5uZXR3b3JrLkJpbmRhYmxlDQogICAgICAgICAgcmVsYXRpb25zaGlwOiB0b3NjYS5yZWxhdGlvbnNoaXBzLm5ldHdvcmsuQmluZHNUbw0KICAgIGNhcGFiaWxpdGllczoNCiAgICAgIGF0dGFjaG1lbnQ6DQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5BdHRhY2htZW50DQogICAgICAgIG9jY3VycmVuY2VzOg0KICAgICAgICAtIDENCiAgICAgICAgLSBVTkJPVU5ERUQNCiAgICAgICAgdHlwZTogdG9zY2EuY2FwYWJpbGl0aWVzLm5ldHdvcmsuQmluZGFibGUNCiAgICAgICAgb2NjdXJyZW5jZXM6DQogICAgICAgIC0gMQ0KICAgICAgICAtIFVOQk9VTkRFRA0KICAgICAgdmlydHVhbF9saW5rYWJsZToNCiAgICAgICAgdHlwZTogY29tLmF0dC5kMi5jYXBhYmlsaXRpZXMuTWV0cmljDQogICAgICBlbmRfcG9pbnQ6DQogICAgICAgIHR5cGU6IHRvc2NhLmNhcGFiaWxpdGllcy5FbmRwb2ludCAgICAgICA="; + timeout = 60; + artifactLabel = normalizeArtifactLabel(artifactName); + break; + } + case DCAE_INVENTORY_POLICY: + case DCAE_INVENTORY_BLUEPRINT: + case DCAE_INVENTORY_EVENT: { + artifactName = getDcaeArtifactName(artifactTypeEnum, artifactType); + payloadData = "will be override later"; + updatedPayloadData = "override"; + timeout = 60; + artifactLabel = normalizeArtifactLabel(artifactName); + break; + } + case MURANO_PKG: { + artifactName = artifactType + "org.openstack.Rally.zip"; + payloadData = "ODM4MTRjNzkxZjcwYTlkMjk4ZGQ2ODE4MThmNjg0N2Y="; + updatedPayloadData = "ODM4MTRjNzkxZjcwYTlkMjk4ZGQ2ODE4MThmMTAwN2Y="; + break; + } + case DCAE_POLICY: { + artifactName = artifactType + "dcae_policy.emf"; + payloadData = "will be override later"; + updatedPayloadData = "override"; + break; + } + case DCAE_INVENTORY_JSON: + case DCAE_JSON: { + artifactName = artifactType + "dcae_policy.json"; + payloadData = "ew0KICAiYXJ0aWZhY3RzIjogImRmc2FmIiwNCiAgIm5vcm1hbGl6ZWROYW1lIjogImNpc2VydmljZTBiYzY5ODk2OTQ4ZiIsDQogICJzeXN0ZW1OYW1lIjogIkNpc2VydmljZTBiYzY5ODk2OTQ4ZiIsDQogICJpbnZhcmlhbnRVVUlEIjogIjEzZmJkNzI3LWRjNzUtNDU1OS1iNzEyLWUwMjc5YmY4YTg2MSIsDQogICJhdHRDb250YWN0IjogImNzMDAwOCIsDQogICJuYW1lIjogImNpU2VydmljZTBiYzY5ODk2OTQ4ZiINCn0="; + updatedPayloadData = "ew0KICAiYXJ0aWZhY3RzIjogIjEyMzQzIiwNCiAgIm5vcm1hbGl6ZWROYW1lIjogIjU0MzUzNCIsDQogICJzeXN0ZW1OYW1lIjogIkNpc2VydmljZTBiYzY5ODk2OTQ4ZiIsDQogICJpbnZhcmlhbnRVVUlEIjogIjEzZmJkNzI3LWRjNzUtNDU1OS1iNzEyLWUwMjc5YmY4YTg2MSIsDQogICJhdHRDb250YWN0IjogImNzMDAwOCIsDQogICJuYW1lIjogImNpU2VydmljZTBiYzY5ODk2OTQ4ZiINCn0="; + break; + } + case PUPPET: + case CHEF: + case DG_XML: + case YANG: { + artifactName = generateUUIDforSufix() + artifactType + "yangXml.xml"; + payloadData = "PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8ZGF0YT4NCiAgPHNwb3J0cz4NCiAgICA8cGVyc29uPg0KICAgICAgPG5hbWU+TGlvbmVsIEFuZHJlcyBNZXNzaTwvbmFtZT4NCiAgICAgIDxiaXJ0aGRheT4xOTg3LTA2LTI0VDAwOjAwOjAwLTAwOjAwPC9iaXJ0aGRheT4NCiAgICA8L3BlcnNvbj4NCiAgICA8cGVyc29uPg0KICAgICAgPG5hbWU+Q3Jpc3RpYW5vIFJvbmFsZG88L25hbWU+DQogICAgICA8YmlydGhkYXk+MTk4NS0wMi0wNVQwMDowMDowMC0wMDowMDwvYmlydGhkYXk+DQogICAgPC9wZXJzb24+DQogICAgPHRlYW0+DQogICAgICA8bmFtZT5GQyBCYXJjZWxvbmE8L25hbWU+DQogICAgICA8cGxheWVyPg0KICAgICAgICA8bmFtZT5MaW9uZWwgQW5kcmVzIE1lc3NpPC9uYW1lPg0KICAgICAgICA8c2Vhc29uPkNoYW1waW9ucyBMZWFndWUgMjAxNC0yMDE1PC9zZWFzb24+DQogICAgICAgIDxudW1iZXI+MTA8L251bWJlcj4NCiAgICAgICAgPHNjb3Jlcz40Mzwvc2NvcmVzPg0KICAgICAgPC9wbGF5ZXI+DQogICAgPC90ZWFtPg0KICAgIDx0ZWFtPg0KICAgICAgPG5hbWU+UmVhbCBNYWRyaWQ8L25hbWU+DQogICAgICA8cGxheWVyPg0KICAgICAgICA8bmFtZT5DcmlzdGlhbm8gUm9uYWxkbzwvbmFtZT4NCiAgICAgICAgPHNlYXNvbj5DaGFtcGlvbnMgTGVhZ3VlIDIwMTQtMjAxNTwvc2Vhc29uPg0KICAgICAgICA8bnVtYmVyPjc8L251bWJlcj4NCiAgICAgICAgPHNjb3Jlcz40ODwvc2NvcmVzPg0KICAgICAgPC9wbGF5ZXI+DQogICAgPC90ZWFtPg0KICA8L3Nwb3J0cz4NCg0KPC9kYXRhPg=="; + updatedPayloadData = "PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8ZGF0YT4NCiAgPHNwb3J0cz4NCiAgICA8cGVyc29uPg0KICAgICAgPG5hbWU+TGlvbmVsIEFuZHJlcyBNZXNzaTwvbmFtZT4NCiAgICAgIDxiaXJ0aGRheT4xOTkwLTA2LTI0VDAwOjAwOjAwLTAwOjExPC9iaXJ0aGRheT4NCiAgICA8L3BlcnNvbj4NCiAgICA8cGVyc29uPg0KICAgICAgPG5hbWU+Q3Jpc3RpYW5vIFJvbmFsZG88L25hbWU+DQogICAgICA8YmlydGhkYXk+MTk4NS0wMi0wNVQwMDowMDowMC0wMDowMDwvYmlydGhkYXk+DQogICAgPC9wZXJzb24+DQogICAgPHRlYW0+DQogICAgICA8bmFtZT5GQyBCYXJjZWxvbmE8L25hbWU+DQogICAgICA8cGxheWVyPg0KICAgICAgICA8bmFtZT5MaW9uZWwgQW5kcmVzIE1lc3NpPC9uYW1lPg0KICAgICAgICA8c2Vhc29uPkNoYW1waW9ucyBMZWFndWUgMjAxNC0yMDE1PC9zZWFzb24+DQogICAgICAgIDxudW1iZXI+MTA8L251bWJlcj4NCiAgICAgICAgPHNjb3Jlcz40Mzwvc2NvcmVzPg0KICAgICAgPC9wbGF5ZXI+DQogICAgPC90ZWFtPg0KICAgIDx0ZWFtPg0KICAgICAgPG5hbWU+UmVhbCBNYWRyaWQ8L25hbWU+DQogICAgICA8cGxheWVyPg0KICAgICAgICA8bmFtZT5DcmlzdGlhbm8gUm9uYWxkbzwvbmFtZT4NCiAgICAgICAgPHNlYXNvbj5DaGFtcGlvbnMgTGVhZ3VlIDIwMTQtMjAxNTwvc2Vhc29uPg0KICAgICAgICA8bnVtYmVyPjc8L251bWJlcj4NCiAgICAgICAgPHNjb3Jlcz40ODwvc2NvcmVzPg0KICAgICAgPC9wbGF5ZXI+DQogICAgPC90ZWFtPg0KICA8L3Nwb3J0cz4NCg0KPC9kYXRhPg=="; + timeout = 15; + artifactLabel = normalizeArtifactLabel(artifactName); + break; + } + case VF_LICENSE: + case VENDOR_LICENSE: + case MODEL_INVENTORY_PROFILE: + case MODEL_QUERY_SPEC: + case VNF_CATALOG: + case YANG_XML: { + artifactName = generateUUIDforSufix() + artifactType + "yangXml.xml"; + payloadData = "PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8ZGF0YT4NCiAgPHNwb3J0cz4NCiAgICA8cGVyc29uPg0KICAgICAgPG5hbWU+TGlvbmVsIEFuZHJlcyBNZXNzaTwvbmFtZT4NCiAgICAgIDxiaXJ0aGRheT4xOTg3LTA2LTI0VDAwOjAwOjAwLTAwOjAwPC9iaXJ0aGRheT4NCiAgICA8L3BlcnNvbj4NCiAgICA8cGVyc29uPg0KICAgICAgPG5hbWU+Q3Jpc3RpYW5vIFJvbmFsZG88L25hbWU+DQogICAgICA8YmlydGhkYXk+MTk4NS0wMi0wNVQwMDowMDowMC0wMDowMDwvYmlydGhkYXk+DQogICAgPC9wZXJzb24+DQogICAgPHRlYW0+DQogICAgICA8bmFtZT5GQyBCYXJjZWxvbmE8L25hbWU+DQogICAgICA8cGxheWVyPg0KICAgICAgICA8bmFtZT5MaW9uZWwgQW5kcmVzIE1lc3NpPC9uYW1lPg0KICAgICAgICA8c2Vhc29uPkNoYW1waW9ucyBMZWFndWUgMjAxNC0yMDE1PC9zZWFzb24+DQogICAgICAgIDxudW1iZXI+MTA8L251bWJlcj4NCiAgICAgICAgPHNjb3Jlcz40Mzwvc2NvcmVzPg0KICAgICAgPC9wbGF5ZXI+DQogICAgPC90ZWFtPg0KICAgIDx0ZWFtPg0KICAgICAgPG5hbWU+UmVhbCBNYWRyaWQ8L25hbWU+DQogICAgICA8cGxheWVyPg0KICAgICAgICA8bmFtZT5DcmlzdGlhbm8gUm9uYWxkbzwvbmFtZT4NCiAgICAgICAgPHNlYXNvbj5DaGFtcGlvbnMgTGVhZ3VlIDIwMTQtMjAxNTwvc2Vhc29uPg0KICAgICAgICA8bnVtYmVyPjc8L251bWJlcj4NCiAgICAgICAgPHNjb3Jlcz40ODwvc2NvcmVzPg0KICAgICAgPC9wbGF5ZXI+DQogICAgPC90ZWFtPg0KICA8L3Nwb3J0cz4NCg0KPC9kYXRhPg=="; + updatedPayloadData = "PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8ZGF0YT4NCiAgPHNwb3J0cz4NCiAgICA8cGVyc29uPg0KICAgICAgPG5hbWU+TGlvbmVsIEFuZHJlcyBNZXNzaTwvbmFtZT4NCiAgICAgIDxiaXJ0aGRheT4xOTkwLTA2LTI0VDAwOjAwOjAwLTAwOjExPC9iaXJ0aGRheT4NCiAgICA8L3BlcnNvbj4NCiAgICA8cGVyc29uPg0KICAgICAgPG5hbWU+Q3Jpc3RpYW5vIFJvbmFsZG88L25hbWU+DQogICAgICA8YmlydGhkYXk+MTk4NS0wMi0wNVQwMDowMDowMC0wMDowMDwvYmlydGhkYXk+DQogICAgPC9wZXJzb24+DQogICAgPHRlYW0+DQogICAgICA8bmFtZT5GQyBCYXJjZWxvbmE8L25hbWU+DQogICAgICA8cGxheWVyPg0KICAgICAgICA8bmFtZT5MaW9uZWwgQW5kcmVzIE1lc3NpPC9uYW1lPg0KICAgICAgICA8c2Vhc29uPkNoYW1waW9ucyBMZWFndWUgMjAxNC0yMDE1PC9zZWFzb24+DQogICAgICAgIDxudW1iZXI+MTA8L251bWJlcj4NCiAgICAgICAgPHNjb3Jlcz40Mzwvc2NvcmVzPg0KICAgICAgPC9wbGF5ZXI+DQogICAgPC90ZWFtPg0KICAgIDx0ZWFtPg0KICAgICAgPG5hbWU+UmVhbCBNYWRyaWQ8L25hbWU+DQogICAgICA8cGxheWVyPg0KICAgICAgICA8bmFtZT5DcmlzdGlhbm8gUm9uYWxkbzwvbmFtZT4NCiAgICAgICAgPHNlYXNvbj5DaGFtcGlvbnMgTGVhZ3VlIDIwMTQtMjAxNTwvc2Vhc29uPg0KICAgICAgICA8bnVtYmVyPjc8L251bWJlcj4NCiAgICAgICAgPHNjb3Jlcz40ODwvc2NvcmVzPg0KICAgICAgPC9wbGF5ZXI+DQogICAgPC90ZWFtPg0KICA8L3Nwb3J0cz4NCg0KPC9kYXRhPg=="; + timeout = 0; + artifactLabel = normalizeArtifactLabel(artifactName); + break; + } + case SNMP_POLL: + case SNMP_TRAP: + case DCAE_INVENTORY_DOC: + case GUIDE: + case OTHER: { + artifactName = generateUUIDforSufix() + artifactType + "other.pdf"; + payloadData = "aGVhdF90ZW1wbGF0ZV92ZXJzaW9uOiAyMDEzLTA1LTIzDQoNCmRlc2NyaXB0aW9uOiBTaW1wbGUgdGVtcGxhdGUgdG8gZGVwbG95IGEgc3RhY2sgd2l0aCB0d28gdmlydHVhbCBtYWNoaW5lIGluc3RhbmNlcw0KDQpwYXJhbWV0ZXJzOg0KICBpbWFnZV9uYW1lXzE6DQogICAgdHlwZTogc3RyaW5nDQogICAgbGFiZWw6IEltYWdlIE5hbWUNCiAgICBkZXNjcmlwdGlvbjogU0NPSU1BR0UgU3BlY2lmeSBhbiBpbWFnZSBuYW1lIGZvciBpbnN0YW5jZTENCiAgICBkZWZhdWx0OiBjaXJyb3MtMC4zLjEteDg2XzY0DQogIGltYWdlX25hbWVfMjoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogSW1hZ2UgTmFtZQ0KICAgIGRlc2NyaXB0aW9uOiBTQ09JTUFHRSBTcGVjaWZ5IGFuIGltYWdlIG5hbWUgZm9yIGluc3RhbmNlMg0KICAgIGRlZmF1bHQ6IGNpcnJvcy0wLjMuMS14ODZfNjQNCiAgbmV0d29ya19pZDoNCiAgICB0eXBlOiBzdHJpbmcNCiAgICBsYWJlbDogTmV0d29yayBJRA0KICAgIGRlc2NyaXB0aW9uOiBTQ09ORVRXT1JLIE5ldHdvcmsgdG8gYmUgdXNlZCBmb3IgdGhlIGNvbXB1dGUgaW5zdGFuY2UNCiAgICBoaWRkZW46IHRydWUNCiAgICBjb25zdHJhaW50czoNCiAgICAgIC0gbGVuZ3RoOiB7IG1pbjogNiwgbWF4OiA4IH0NCiAgICAgICAgZGVzY3JpcHRpb246IFBhc3N3b3JkIGxlbmd0aCBtdXN0IGJlIGJldHdlZW4gNiBhbmQgOCBjaGFyYWN0ZXJzLg0KICAgICAgLSByYW5nZTogeyBtaW46IDYsIG1heDogOCB9DQogICAgICAgIGRlc2NyaXB0aW9uOiBSYW5nZSBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3ZhbHVlczoNCiAgICAgICAgLSBtMS5zbWFsbA0KICAgICAgICAtIG0xLm1lZGl1bQ0KICAgICAgICAtIG0xLmxhcmdlDQogICAgICAgIGRlc2NyaXB0aW9uOiBBbGxvd2VkIHZhbHVlcyBkZXNjcmlwdGlvbg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbYS16QS1aMC05XSsiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IGNvbnNpc3Qgb2YgY2hhcmFjdGVycyBhbmQgbnVtYmVycyBvbmx5Lg0KICAgICAgLSBhbGxvd2VkX3BhdHRlcm46ICJbQS1aXStbYS16QS1aMC05XSoiDQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBtdXN0IHN0YXJ0IHdpdGggYW4gdXBwZXJjYXNlIGNoYXJhY3Rlci4NCiAgICAgIC0gY3VzdG9tX2NvbnN0cmFpbnQ6IG5vdmEua2V5cGFpcg0KICAgICAgICBkZXNjcmlwdGlvbjogQ3VzdG9tIGRlc2NyaXB0aW9uDQoNCnJlc291cmNlczoNCiAgbXlfaW5zdGFuY2UxOg0KICAgIHR5cGU6IE9TOjpOb3ZhOjpTZXJ2ZXINCiAgICBwcm9wZXJ0aWVzOg0KICAgICAgaW1hZ2U6IHsgZ2V0X3BhcmFtOiBpbWFnZV9uYW1lXzEgfQ0KICAgICAgZmxhdm9yOiBtMS5zbWFsbA0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9DQogIG15X2luc3RhbmNlMjoNCiAgICB0eXBlOiBPUzo6Tm92YTo6U2VydmVyDQogICAgcHJvcGVydGllczoNCiAgICAgIGltYWdlOiB7IGdldF9wYXJhbTogaW1hZ2VfbmFtZV8yIH0NCiAgICAgIGZsYXZvcjogbTEudGlueQ0KICAgICAgbmV0d29ya3M6DQogICAgICAgIC0gbmV0d29yayA6IHsgZ2V0X3BhcmFtIDogbmV0d29ya19pZCB9"; + updatedPayloadData = "aGVhdF90ZW1wbGF0ZV92ZXJzaW9uOiAyMDE2LTA1LTIzDQoNCmRlc2NyaXB0aW9uOiBTaW1wbGUgdGVtcGxhdGRzYWRzYWRzYWUgdG8gZGVwbG95IGEgc3RhY2sgd2l0aCB0d28gdmlydHVhbCBtYWNoaW5lIGluc3RhbmNlcw0KDQpwYXJhbWV0ZXJzOg0KICBpbWFnZV9uYW1lXzE6DQogICAgdHlwZTogc3RyaW5nDQogICAgbGFiZWw6IEltYWdlIE5hbWUNCiAgICBkZXNjcmlwdGlvbjogU0NPSU1BR0UgU3BlY2lmeSBhbiBpbWFkc2FkYXN3Z2UgbmFtZSBmb3IgaW5zdGFuY2UxDQogICAgZGVmYXVsdDogY2lycm9zLTAuMy4xLXg4Nl82NA0KICBpbWFnZV9uYW1lXzI6DQogICAgdHlwZTogc3RyaW5nDQogICAgbGFiZWw6IEltYWdlIE5hbWUNCiAgICBkZXNjcmlwdGlvbjogU0NPSU1BR0UgU3BlY2lmeSBhbiBpbWFnZSBuYW1lIGZvciBpbnN0YW5jZTINCiAgICBkZWZhdWx0OiBjaXJyb3MtMC4zLjEteDg2XzY0DQogIG5ldHdvcmtfaWQ6DQogICAgdHlwZTogc3RyaW5nDQogICAgbGFiZWw6IE5ldHdvcmsgSUQNCiAgICBkZXNjcmlwdGlvbjogU0NPTkVUV09SSyBOZXR3b3JrIHRvIGJlIHVzZWQgZm9yIHRoZSBjb21wdXRlIGluc3RhbmNlDQogICAgaGlkZGVuOiB0cnVlDQogICAgY29uc3RyYWludHM6DQogICAgICAtIGxlbmd0aDogeyBtaW46IDYsIG1heDogOCB9DQogICAgICAgIGRlc2NyaXB0aW9uOiBQYXNzd29yZCBsZW5ndGggbXVzdCBiZSBiZXR3ZWVuIDYgYW5kIDggY2hhcmFjdGVycy4NCiAgICAgIC0gcmFuZ2U6IHsgbWluOiA2LCBtYXg6IDggfQ0KICAgICAgICBkZXNjcmlwdGlvbjogUmFuZ2UgZGVzY3JpcHRpb24NCiAgICAgIC0gYWxsb3dlZF92YWx1ZXM6DQogICAgICAgIC0gbTEuc21hbGwNCiAgICAgICAgLSBtMS5tZWRpdW0NCiAgICAgICAgLSBtMS5sYXJnZQ0KICAgICAgICBkZXNjcmlwdGlvbjogQWxsb3dlZCB2YWx1ZXMgZGVzY3JpcHRpb24NCiAgICAgIC0gYWxsb3dlZF9wYXR0ZXJuOiAiW2EtekEtWjAtOV0rIg0KICAgICAgICBkZXNjcmlwdGlvbjogUGFzc3dvcmQgbXVzdCBjb25zaXN0IG9mIGNoYXJhY3RlcnMgYW5kIG51bWJlcnMgb25seS4NCiAgICAgIC0gYWxsb3dlZF9wYXR0ZXJuOiAiW0EtWl0rW2EtekEtWjAtOV0qIg0KICAgICAgICBkZXNjcmlwdGlvbjogUGFzc3dvcmQgbXVzdCBzdGFydCB3aXRoIGFuIHVwcGVyY2FzZSBjaGFyYWN0ZXIuDQogICAgICAtIGN1c3RvbV9jb25zdHJhaW50OiBub3ZhLmtleXBhaXINCiAgICAgICAgZGVzY3JpcHRpb246IEN1c3RvbSBkZXNjcmlwdGlvbg0KDQpyZXNvdXJjZXM6DQogIG15X2luc3RhbmNlMToNCiAgICB0eXBlOiBPUzo6Tm92YTo6U2VydmVyDQogICAgcHJvcGVydGllczoNCiAgICAgIGltYWdlOiB7IGdldF9wYXJhbTogaW1hZ2VfbmFtZV8xIH0NCiAgICAgIGZsYXZvcjogbTEuc21hbGwNCiAgICAgIG5ldHdvcmtzOg0KICAgICAgICAtIG5ldHdvcmsgOiB7IGdldF9wYXJhbSA6IG5ldHdvcmtfaWQgfQ0KICBteV9pbnN0YW5jZTI6DQogICAgdHlwZTogT1M6Ok5vdmE6OlNlcnZlcg0KICAgIHByb3BlcnRpZXM6DQogICAgICBpbWFnZTogeyBnZXRfcGFyYW06IGltYWdlX25hbWVfMiB9DQogICAgICBmbGF2b3I6IG0xLnRpbnkNCiAgICAgIG5ldHdvcmtzOg0KICAgICAgICAtIG5ldHdvcmsgOiB7IGdldF9wYXJhbSA6IG5ldHdvcmtfaWQgfQ"; + timeout = 0; + artifactLabel = normalizeArtifactLabel(artifactName); + break; + } + case SHELL_SCRIPT: + default: {// dummy + artifactName = generateUUIDforSufix() + "testArtifact.sh"; + payloadData = "dGVzdA=="; + updatedPayloadData = "YmVzYg=="; + artifactLabel = normalizeArtifactLabel(artifactName); + break; + } + } + artifactLabel = normalizeArtifactLabel("ci" + artifactName); + + ArtifactReqDetails artifactDetails = null; + + if (!updatedPayload){ + artifactDetails = new ArtifactReqDetails(artifactName, artifactType, artifactDescription, payloadData, artifactLabel); + } + else artifactDetails = new ArtifactReqDetails(artifactName, artifactType, artifactDescription, + updatedPayloadData, artifactLabel); + + artifactDetails.setArtifactGroupType(ArtifactGroupTypeEnum.DEPLOYMENT.getType()); + artifactDetails.setUrl(url); + artifactDetails.setTimeout(timeout); + artifactDetails.setArtifactDisplayName(artifactLabel); + return artifactDetails; + } + + private static String getDcaeArtifactName(ArtifactTypeEnum artifactTypeEnum, String artifactType) { + String artifactName = null; + switch (artifactTypeEnum) { + case DCAE_INVENTORY_TOSCA: { + artifactName = generateUUIDforSufix() + artifactType + "_toscaSampleArtifact.yml"; + break; + } + case DCAE_INVENTORY_JSON: { + artifactName = generateUUIDforSufix() + artifactType + "_jsonSampleArtifact.json"; + break; + } + case DCAE_INVENTORY_POLICY: { + artifactName = generateUUIDforSufix() + artifactType + "_emfSampleArtifact.emf"; + break; + } + case DCAE_INVENTORY_DOC: { + artifactName = generateUUIDforSufix() + artifactType + "_docSampleArtifact.doc"; + break; + } + case DCAE_INVENTORY_BLUEPRINT: { + artifactName = generateUUIDforSufix() + artifactType + "_bluePrintSampleArtifact.xml"; + break; + } + case DCAE_INVENTORY_EVENT: { + artifactName = generateUUIDforSufix() + artifactType + "_eventSampleArtifact.xml"; + break; + } + } + return artifactName; + } + + // ---------------------Audit message------------------ + public static ExpectedResourceAuditJavaObject getDefaultImportResourceAuditMsgSuccess() { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(AuditingActionEnum.IMPORT_RESOURCE.getName()); + expectedResourceAuditJavaObject.setResourceName("defaultImportResourceName.yaml"); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion("0.1"); + expectedResourceAuditJavaObject.setModifierName(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getFullName()); + expectedResourceAuditJavaObject.setModifierUid(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setToscaNodeType(""); + return expectedResourceAuditJavaObject; + + } + + public static ExpectedResourceAuditJavaObject getDefaultImportResourceAuditMsgFailure(ErrorInfo errorInfo, List variables) { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(AuditingActionEnum.IMPORT_RESOURCE.getName()); + expectedResourceAuditJavaObject.setResourceName(""); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setModifierName(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getFullName()); + expectedResourceAuditJavaObject.setModifierUid(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + expectedResourceAuditJavaObject.setToscaNodeType(""); + return expectedResourceAuditJavaObject; + + } + + public static ExpectedResourceAuditJavaObject getDefaultCertificationRequestAuditMsgSuccess() { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(AuditingActionEnum.CERTIFICATION_REQUEST_RESOURCE.getName()); + expectedResourceAuditJavaObject.setResourceName("defaultResourceName"); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion("0.1"); + expectedResourceAuditJavaObject.setModifierName(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getFullName()); + expectedResourceAuditJavaObject.setModifierUid(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setComment(""); + return expectedResourceAuditJavaObject; + + } + + public static ExpectedResourceAuditJavaObject getDefaultCertificationRequestAuditMsgFailure(ErrorInfo errorInfo, List variables) { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(AuditingActionEnum.CERTIFICATION_REQUEST_RESOURCE.getName()); + expectedResourceAuditJavaObject.setResourceName(""); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setPrevVersion("0.1"); + expectedResourceAuditJavaObject.setCurrVersion("0.1"); + expectedResourceAuditJavaObject.setModifierName(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getFullName()); + expectedResourceAuditJavaObject.setModifierUid(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + expectedResourceAuditJavaObject.setComment(""); + return expectedResourceAuditJavaObject; + + } + + public static ExpectedExternalAudit getDefaultExternalAuditObject(AssetTypeEnum assetType, AuditingActionEnum action, String query) { + + ExpectedExternalAudit expectedExternalAudit = new ExpectedExternalAudit(); + expectedExternalAudit.setACTION(action.getName()); + expectedExternalAudit.setCONSUMER_ID("ci"); + expectedExternalAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetType.getValue() + (query == null ? "" : query)); + expectedExternalAudit.setSTATUS("200"); + expectedExternalAudit.setDESC("OK"); + return expectedExternalAudit; + + } + + public static ExpectedExternalAudit getDefaultAssetListAudit(AssetTypeEnum assetType, AuditingActionEnum auditAction) { + + // ExpectedExternalAudit expectedAssetListAuditJavaObject = new + // ExpectedExternalAudit(); + ExpectedExternalAudit expectedAssetListAuditJavaObject = getDefaultExternalAuditObject(assetType, auditAction, null); + return expectedAssetListAuditJavaObject; + + } + + public static ExpectedExternalAudit getDefaultFilteredAssetListAudit(AssetTypeEnum assetType, String query) { + + // ExpectedExternalAudit expectedAssetListAuditJavaObject = new + // ExpectedExternalAudit(); + ExpectedExternalAudit expectedAssetListAuditJavaObject = getDefaultExternalAuditObject(assetType, AuditingActionEnum.GET_FILTERED_ASSET_LIST, query); + return expectedAssetListAuditJavaObject; + + } + + public static ExpectedExternalAudit getDefaultExternalArtifactAuditSuccess(AssetTypeEnum assetType, AuditingActionEnum action, ArtifactDefinition artifactDefinition, String componentUUID) { + + // ExpectedExternalAudit expectedExternalArtifactAudit = new + // ExpectedExternalAudit(); + + ExpectedExternalAudit expectedExternalArtifactAudit = getDefaultExternalAuditObject(assetType, action, null); + expectedExternalArtifactAudit.setMODIFIER(AuditValidationUtils.getModifierString(artifactDefinition.getUpdaterFullName(), artifactDefinition.getUserIdLastUpdater())); + expectedExternalArtifactAudit.setPREV_ARTIFACT_UUID(""); + expectedExternalArtifactAudit.setCURR_ARTIFACT_UUID(artifactDefinition.getArtifactUUID()); + expectedExternalArtifactAudit.setARTIFACT_DATA(AuditValidationUtils.buildArtifactDataAudit(artifactDefinition)); + expectedExternalArtifactAudit.setRESOURCE_URL(expectedExternalArtifactAudit.getRESOURCE_URL() + "/" + componentUUID + "/artifacts"); + return expectedExternalArtifactAudit; + + } + + public static ExpectedExternalAudit getDefaultExternalArtifactAuditSuccess(AssetTypeEnum assetType, AuditingActionEnum action, ArtifactDefinition artifactDefinition, Component component) { + + //ExpectedExternalAudit expectedExternalArtifactAudit = new ExpectedExternalAudit(); + + ExpectedExternalAudit expectedExternalArtifactAudit = getDefaultExternalAuditObject(assetType, action, null); + expectedExternalArtifactAudit.setMODIFIER(AuditValidationUtils.getModifierString(artifactDefinition.getUpdaterFullName(), artifactDefinition.getUserIdLastUpdater())); + expectedExternalArtifactAudit.setPREV_ARTIFACT_UUID(""); + expectedExternalArtifactAudit.setCURR_ARTIFACT_UUID(artifactDefinition.getArtifactUUID()); + expectedExternalArtifactAudit.setARTIFACT_DATA(AuditValidationUtils.buildArtifactDataAudit(artifactDefinition)); + expectedExternalArtifactAudit.setRESOURCE_URL(expectedExternalArtifactAudit.getRESOURCE_URL() + "/" + component.getUUID() + "/artifacts"); + expectedExternalArtifactAudit.setRESOURCE_NAME(component.getName()); + expectedExternalArtifactAudit.setRESOURCE_TYPE(component.getComponentType().getValue()); + return expectedExternalArtifactAudit; + + } + + public static ExpectedResourceAuditJavaObject getDefaultCreateResourceExternalAPI(String resourceName) { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(AuditingActionEnum.CREATE_RESOURCE_BY_API.getName()); + expectedResourceAuditJavaObject.setResourceName(resourceName); + expectedResourceAuditJavaObject.setResourceType("Resource"); + expectedResourceAuditJavaObject.setCONSUMER_ID("ci"); + expectedResourceAuditJavaObject.setRESOURCE_URL("/sdc/v1/catalog/resources"); + expectedResourceAuditJavaObject.setMODIFIER(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion("0.1"); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + + return expectedResourceAuditJavaObject; + + + } + + public static ExpectedResourceAuditJavaObject getDefaultChangeAssetLifeCycleExternalAPI(Component resourceAssetStructure, User defaultUser, LifeCycleStatesEnum lifecycleStateEnum, AssetTypeEnum assetTypeEnum) { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(AuditingActionEnum.CHANGE_LIFECYCLE_BY_API.getName()); + expectedResourceAuditJavaObject.setResourceName(resourceAssetStructure.getName()); + expectedResourceAuditJavaObject.setResourceType(assetTypeEnum.getCorrespondingComponent()); + expectedResourceAuditJavaObject.setCONSUMER_ID("ci"); + expectedResourceAuditJavaObject.setRESOURCE_URL(String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", assetTypeEnum.getValue().toLowerCase(), resourceAssetStructure.getUUID(), lifecycleStateEnum.getState())); + expectedResourceAuditJavaObject.setMODIFIER(defaultUser.getFullName() + "(" + defaultUser.getUserId() + ")"); + expectedResourceAuditJavaObject.setPrevVersion("0.1"); + expectedResourceAuditJavaObject.setCurrVersion("0.1"); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + // TODO: Remove comment +// expectedResourceAuditJavaObject.setINVARIANT_UUID(resourceAssetStructure.getInvariantUUID()); + // TODO: SERVICE_INSTANCE_ID + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + + return expectedResourceAuditJavaObject; + + } + + public static ExpectedResourceAuditJavaObject getDefaultInvalidChangeAssetLifeCycleExternalAPI(String assetUUID, User defaultUser, LifeCycleStatesEnum lifecycleStateEnum, AssetTypeEnum assetTypeEnum) { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + expectedResourceAuditJavaObject.setAction(AuditingActionEnum.CHANGE_LIFECYCLE_BY_API.getName()); + expectedResourceAuditJavaObject.setResourceName(""); + expectedResourceAuditJavaObject.setResourceType(assetTypeEnum.getCorrespondingComponent()); + expectedResourceAuditJavaObject.setCONSUMER_ID("ci"); + expectedResourceAuditJavaObject.setRESOURCE_URL(String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", assetTypeEnum.getValue().toLowerCase(), assetUUID, lifecycleStateEnum.getState())); + expectedResourceAuditJavaObject.setMODIFIER(""); + expectedResourceAuditJavaObject.setMODIFIER(defaultUser.getFullName() + "(" + defaultUser.getUserId() + ")"); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrVersion(""); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setCurrState(""); + expectedResourceAuditJavaObject.setStatus("404"); + expectedResourceAuditJavaObject.setDesc("OK"); + + return expectedResourceAuditJavaObject; + + } + + public static ExpectedExternalAudit getDefaultExternalArtifactAuditSuccess(AssetTypeEnum assetType, AuditingActionEnum action, ArtifactDefinition artifactDefinition, String componentUUID, String resourceInstanceName) { + + ExpectedExternalAudit expectedExternalArtifactAudit = getDefaultExternalArtifactAuditSuccess(assetType, action, artifactDefinition, componentUUID); + expectedExternalArtifactAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetType.getValue() + "/" + componentUUID + "/resourceInstances/" + resourceInstanceName + "/artifacts"); + return expectedExternalArtifactAudit; + } + + public static ExpectedExternalAudit getDefaultExternalArtifactAuditFailure(AssetTypeEnum assetType, AuditingActionEnum action, ArtifactDefinition artifactDefinition, String componentUUID, ErrorInfo errorInfo, List variables) { + + // ExpectedExternalAudit expectedExternalArtifactAudit = new + // ExpectedExternalAudit(); + + ExpectedExternalAudit expectedExternalArtifactAudit = getDefaultExternalAuditObject(assetType, action, null); + expectedExternalArtifactAudit.setMODIFIER(AuditValidationUtils.getModifierString(artifactDefinition.getUpdaterFullName(), artifactDefinition.getUserIdLastUpdater())); + expectedExternalArtifactAudit.setPREV_ARTIFACT_UUID(""); + expectedExternalArtifactAudit.setCURR_ARTIFACT_UUID(artifactDefinition.getArtifactUUID()); + expectedExternalArtifactAudit.setARTIFACT_DATA(AuditValidationUtils.buildArtifactDataAudit(artifactDefinition)); + expectedExternalArtifactAudit.setRESOURCE_URL(expectedExternalArtifactAudit.getRESOURCE_URL() + "/" + componentUUID + "/artifacts"); + expectedExternalArtifactAudit.setSTATUS(errorInfo.getCode().toString()); + expectedExternalArtifactAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + return expectedExternalArtifactAudit; + + } + + public static ExpectedExternalAudit getDefaultExternalArtifactAuditFailure(AssetTypeEnum assetType, AuditingActionEnum action, ArtifactDefinition artifactDefinition, String componentUUID, ErrorInfo errorInfo, List variables, + String resourceInstanceName) { + + ExpectedExternalAudit expectedExternalArtifactAudit = getDefaultExternalArtifactAuditFailure(assetType, action, artifactDefinition, componentUUID, errorInfo, variables); + expectedExternalArtifactAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetType.getValue() + "/" + componentUUID + "/resourceInstances/" + resourceInstanceName + "/artifacts"); + return expectedExternalArtifactAudit; + } + + public static ExpectedExternalAudit getFilteredAssetListAuditCategoryNotFound(AssetTypeEnum assetType, String query, String category) { + + // ExpectedExternalAudit expectedAssetListAuditJavaObject = new + // ExpectedExternalAudit(); + ExpectedExternalAudit expectedAssetListAuditJavaObject = getDefaultExternalAuditObject(assetType, AuditingActionEnum.GET_FILTERED_ASSET_LIST, query); + expectedAssetListAuditJavaObject.setSTATUS("404"); + ErrorInfo errorInfo = null; + try { + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name()); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + String desc = (errorInfo.getMessageId() + ": " + errorInfo.getMessage()).replace("%2", "category").replace("%3", category).replace("%1", "resource"); + expectedAssetListAuditJavaObject.setDESC(desc); + + return expectedAssetListAuditJavaObject; + + } + + public static ExpectedExternalAudit getDefaultAssetMetadataAudit(AssetTypeEnum assetType, Component component) { + + ExpectedExternalAudit expectedAssetListAuditJavaObject = new ExpectedExternalAudit(); + expectedAssetListAuditJavaObject = getDefaultExternalAuditObject(assetType, AuditingActionEnum.GET_ASSET_METADATA, null); + expectedAssetListAuditJavaObject.setRESOURCE_URL(expectedAssetListAuditJavaObject.getRESOURCE_URL() + "/" + component.getUUID() + "/metadata"); + expectedAssetListAuditJavaObject.setRESOURCE_NAME(component.getName()); + expectedAssetListAuditJavaObject.setRESOURCE_TYPE(component.getComponentType().getValue()); + expectedAssetListAuditJavaObject.setSERVICE_INSTANCE_ID(component.getUUID()); + return expectedAssetListAuditJavaObject; + + } + + public static ExpectedExternalAudit getDefaultAssetMetadataAuditFailure(AssetTypeEnum assetType, String serviceUuid, String resourceType) { + + ExpectedExternalAudit expectedAssetListAuditJavaObject = new ExpectedExternalAudit(); + expectedAssetListAuditJavaObject = getDefaultExternalAuditObject(assetType, AuditingActionEnum.GET_ASSET_METADATA, null); + expectedAssetListAuditJavaObject.setSTATUS("404"); + expectedAssetListAuditJavaObject.setDESC("OK"); + expectedAssetListAuditJavaObject.setRESOURCE_URL(expectedAssetListAuditJavaObject.getRESOURCE_URL() + "/" + serviceUuid + "/metadata"); + expectedAssetListAuditJavaObject.setRESOURCE_TYPE(resourceType); + expectedAssetListAuditJavaObject.setSERVICE_INSTANCE_ID(serviceUuid); + return expectedAssetListAuditJavaObject; + + } + + // Category/Subcategory/Group + public static CategoryDefinition getDefaultCategory() { + CategoryDefinition productCategoryDefinition = new CategoryDefinition(); + productCategoryDefinition.setName("CiCateg" + generateUUIDforSufix()); + return productCategoryDefinition; + } + + public static SubCategoryDefinition getDefaultSubCategory() { + SubCategoryDefinition productSubCategoryDefinition = new SubCategoryDefinition(); + productSubCategoryDefinition.setName("CiSubCateg" + generateUUIDforSufix()); + return productSubCategoryDefinition; + } + + public static GroupingDefinition getDefaultGroup() { + GroupingDefinition productGroupDefinition = new GroupingDefinition(); + productGroupDefinition.setName("CiGrouping1" + generateUUIDforSufix()); + return productGroupDefinition; + } + + // Product + + public static ProductReqDetails getDefaultProduct() { + return createDefaultProductReqDetails(CI_PRODUCT, null); + } + + public static ProductReqDetails getDefaultProduct(String name) { + return createDefaultProductReqDetails(name, null); + } + + public static ProductReqDetails getDefaultProduct(CategoryDefinition category) { + List categories = new ArrayList<>(); + categories.add(category); + return createDefaultProductReqDetails(CI_PRODUCT, categories); + } + + public static ProductReqDetails getDefaultProduct(String name, CategoryDefinition category) { + List categories = new ArrayList<>(); + categories.add(category); + return createDefaultProductReqDetails(name, categories); + } + + public static ProductReqDetails getDefaultProduct(List categories) { + return createDefaultProductReqDetails(CI_PRODUCT, categories); + } + + public static ProductReqDetails getDefaultProduct(String name, List categories) { + return createDefaultProductReqDetails(name, categories); + } + + private static ProductReqDetails createDefaultProductReqDetails(String productName, List categories) { + ProductReqDetails product = new ProductReqDetails(productName); + productName = (productName + generateUUIDforSufix()); + product.setName(productName); + ArrayList tags = new ArrayList(); + tags.add(productName); + product.setTags(tags); + product.setProjectCode("12345"); + product.setIcon("myIcon"); + ArrayList contacts = new ArrayList(); + // contacts.add(ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1).getUserId()); + // contacts.add(ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST2).getUserId()); + contacts.add(ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1).getUserId()); + // contacts.add(ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER2).getUserId()); + product.setContacts(contacts); + product.setContactId(UserRoleEnum.PRODUCT_MANAGER1.getUserId()); + product.setCategories(categories); + String fullName = "This is my full name: " + productName; + product.setFullName(fullName); + String description = "This is product description"; + product.setDescription(description); + return product; + } + + public static RequirementCapabilityRelDef getReqCapRelation(String fromCompInstId, String toCompInstId, String reqOwnerId, String capOwnerId, String capType, String reqCapName, List capList, + List reqList) { + RequirementCapabilityRelDef requirementDef = new RequirementCapabilityRelDef(); + requirementDef.setFromNode(fromCompInstId); + requirementDef.setToNode(toCompInstId); + RequirementAndRelationshipPair pair = new RequirementAndRelationshipPair(); + pair.setRequirementOwnerId(reqOwnerId); + pair.setCapabilityOwnerId(capOwnerId); + pair.setRequirement(reqCapName); + RelationshipImpl relationship = new RelationshipImpl(); + relationship.setType(capType); + pair.setRelationships(relationship); + pair.setCapabilityUid(capList.get(0).getUniqueId()); + pair.setRequirementUid(reqList.get(0).getUniqueId()); + List relationships = new ArrayList<>(); + relationships.add(pair); + requirementDef.setRelationships(relationships); + return requirementDef; + } + + private static String generateUUIDforSufix() { + + String uniqueSufix = UUID.randomUUID().toString(); + String[] split = uniqueSufix.split("-"); + return uniqueSufix = split[4]; + } + + private static String normalizeArtifactLabel(String label) { + + label = label.substring(0, label.indexOf(".")); + String normalizedLabel = ValidationUtils.normalizeArtifactLabel(label); + return normalizedLabel.substring(0, Math.min(25, normalizedLabel.length())); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/FileUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/FileUtils.java new file mode 100644 index 0000000000..28964e2f7e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/FileUtils.java @@ -0,0 +1,137 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.general; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.openecomp.sdc.ci.tests.utils.Decoder; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class FileUtils { + static Logger logger = LoggerFactory.getLogger(Utils.class.getName()); + + public static void writeToFile(String filePath, String content) { + try { + Files.write(Paths.get(filePath), content.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static String getFileName(String fullyQualified) { + String fileName = fullyQualified; + + int i = fullyQualified.lastIndexOf('.'); + if (i > 0) { + fileName = fullyQualified.substring(i + 1); + } + return fileName; + + } + + public static Either getFileContentUTF8(String filePath) { + Either eitherResult; + try { + String content = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8); + eitherResult = Either.left(content); + } catch (Exception e) { + eitherResult = Either.right(e); + } + return eitherResult; + } + + public static List getFileListFromBaseDirectoryByTestName(String testResourcesPath) { + + File file = new File(testResourcesPath); + File[] listFiles = file.listFiles(); + if (listFiles != null) { + List listFileName = new ArrayList(); + for (File newFile : listFiles) { + if (newFile.isFile()) { + listFileName.add(newFile.getPath()); + } + } + return listFileName; + } + assertTrue("directory " + testResourcesPath + " is empty", false); + return null; + } + + public static String getFilePathFromListByPattern(List fileList, String pattern) { + + for (String filePath : fileList) { + if (filePath.contains(pattern)) { + return filePath; + } + } + return null; + } + + public static String loadPayloadFileFromListUsingPosition(List listFileName, String pattern, + Boolean isBase64, int positionInList) throws IOException { + List newList = new ArrayList(Arrays.asList(listFileName.get(positionInList))); + return loadPayloadFile(newList, pattern, isBase64); + } + + public static String loadPayloadFile(List listFileName, String pattern, Boolean isBase64) + throws IOException { + String fileName; + String payload = null; + fileName = FileUtils.getFilePathFromListByPattern(listFileName, pattern); + logger.debug("fileName: {}", fileName); + + if (fileName != null) { + payload = Decoder.readFileToString(fileName); + if (isBase64) { + payload = Decoder.encode(payload.getBytes()); + } + } else { + assertTrue("file to upload not found", false); + } + return payload; + } + + public static String getFileNameFromPath(String testResourcesPath) { + + File file = new File(testResourcesPath); + String fileName = null; + if (file.exists()) { + return file.getName(); + } else { + assertTrue("file to upload not found", false); + } + return fileName; + + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/ImportUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/ImportUtils.java new file mode 100644 index 0000000000..c1f311a91e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/general/ImportUtils.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.general; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.utils.Utils; + +public class ImportUtils { + + public static ImportReqDetails getImportResourceDetailsByPathAndName(ImportReqDetails importReqDetails, + String filePath, String fileName) throws IOException { + + // ImportReqDetails importReqDetails; + // User sdncUserDetails; + // String testResourcesPath; + // ResourceReqDetails resourceDetails; + // Config config; + // config = Utils.getConfig(); + // + // importReqDetails = ElementFactory.getDefaultImportResource(); + // User sdncUserDetails = + // ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + // ResourceReqDetails resourceDetails = + // ElementFactory.getDefaultResource(); + // String sourceDir = config.getResourceConfigDir(); + // String testResourcesPath = sourceDir + File.separator + workDir; + // final String workDir = "importToscaResourceByCreateUrl"; + + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(filePath); + importReqDetails.setPayloadName(fileName); + String payloadData = FileUtils.loadPayloadFile(listFileName, fileName, true); + importReqDetails.setPayloadData(payloadData); + + return importReqDetails; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ArtifactRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ArtifactRestUtils.java new file mode 100644 index 0000000000..a7ab544725 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ArtifactRestUtils.java @@ -0,0 +1,934 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.util.ValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.AssertJUnit; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +public class ArtifactRestUtils extends BaseRestUtils { + private static Logger logger = LoggerFactory.getLogger(ArtifactRestUtils.class.getName()); + + + // External API + // Delete Artifact on rI of the asset + public static RestResponse externalAPIDeleteArtifactOfComponentInstanceOnAsset(Component component, User user, ComponentInstance resourceInstance, String artifactUUID) throws IOException { + Config config = Utils.getConfig(); + String resourceType = null; + String resourceUUID = component.getUUID(); + String resourceInstanceName = resourceInstance.getNormalizedName(); + + System.out.println(component.getComponentType()); + + if(component.getComponentType().toString().toLowerCase().equals("resource")) { + resourceType = "resources"; + } else { + resourceType = "services"; + } + + String url = String.format(Urls.DELETE_EXTRNAL_API_DELETE_ARTIFACT_OF_COMPONENTINSTANCE_ON_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceType, resourceUUID, resourceInstanceName, artifactUUID); + + return deleteInformationalArtifact(user, url); + } + + // Delete Artifact of the asset + public static RestResponse externalAPIDeleteArtifactOfTheAsset(Component component, User user, String artifactUUID) throws IOException { + Config config = Utils.getConfig(); + String resourceType = null; + String resourceUUID = component.getUUID(); + + System.out.println(component.getComponentType()); + + if(component.getComponentType().toString().toLowerCase().equals("resource")) { + resourceType = "resources"; + } else { + resourceType = "services"; + } + + String url = String.format(Urls.DELETE_EXTRNAL_API_DELETE_ARTIFACT_OF_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceType, resourceUUID, artifactUUID); + + RestResponse restResponse = deleteInformationalArtifact(user, url); + + return restResponse; + } + + + // Update Artifact on rI of the asset + public static RestResponse externalAPIUpdateArtifactOfComponentInstanceOnAsset(Component component, User user, ArtifactReqDetails artifactReqDetails, ComponentInstance resourceInstance, String artifactUUID) throws IOException { + Config config = Utils.getConfig(); + String resourceType = null; + String resourceUUID = component.getUUID(); + String resourceInstanceName = resourceInstance.getNormalizedName(); + + System.out.println(component.getComponentType()); + + if(component.getComponentType().toString().toLowerCase().equals("resource")) { + resourceType = "resources"; + } else { + resourceType = "services"; + } + + String url = String.format(Urls.POST_EXTERNAL_API_UPDATE_ARTIFACT_OF_COMPONENTINSTANCE_ON_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceType, resourceUUID, resourceInstanceName, artifactUUID); + + return updateInformationalArtifact(artifactReqDetails, user, calculateChecksum(artifactReqDetails), url); + } + + // Update Artifact of the asset + public static RestResponse externalAPIUpdateArtifactOfTheAsset(Component component, User user, ArtifactReqDetails artifactReqDetails, String artifactUUID) throws IOException { + Config config = Utils.getConfig(); + String resourceType = null; + String resourceUUID = component.getUUID(); + + System.out.println(component.getComponentType()); + + if(component.getComponentType().toString().toLowerCase().equals("resource")) { + resourceType = "resources"; + } else { + resourceType = "services"; + } + + String url = String.format(Urls.POST_EXTERNAL_API_UPDATE_ARTIFACT_OF_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceType, resourceUUID, artifactUUID); + + return updateInformationalArtifact(artifactReqDetails, user, calculateChecksum(artifactReqDetails), url); + } + + + // Upload Artifact on rI of the asset + public static RestResponse externalAPIUploadArtifactOfComponentInstanceOnAsset(Component component, User user, ArtifactReqDetails artifactReqDetails, ComponentInstance resourceInstance) throws IOException { + Config config = Utils.getConfig(); + String resourceType = null; + String resourceUUID = component.getUUID(); + String resourceInstanceName = resourceInstance.getNormalizedName(); + + System.out.println(component.getComponentType()); + + if(component.getComponentType().toString().toLowerCase().equals("resource")) { + resourceType = "resources"; + } else { + resourceType = "services"; + } + + String url = String.format(Urls.POST_EXTERNAL_API_UPLOAD_ARTIFACT_OF_COMPONENTINSTANCE_ON_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceType, resourceUUID, resourceInstanceName); + + return uploadInformationalArtifact(artifactReqDetails, user, calculateChecksum(artifactReqDetails), url); + } + + // Upload Artifact of the asset + public static RestResponse externalAPIUploadArtifactOfTheAsset(Component component, User user, ArtifactReqDetails artifactReqDetails) throws IOException { + Config config = Utils.getConfig(); + String resourceType = null; + String resourceUUID = component.getUUID(); + + System.out.println(component.getComponentType()); + + if(component.getComponentType().toString().toLowerCase().equals("resource")) { + resourceType = "resources"; + } else { + resourceType = "services"; + } + + String url = String.format(Urls.POST_EXTERNAL_API_UPLOAD_ARTIFACT_OF_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceType, resourceUUID); + + return uploadInformationalArtifact(artifactReqDetails, user, calculateChecksum(artifactReqDetails), url); + } + + + // Upload Artifact of the asset with invalid checksum + public static RestResponse externalAPIUploadArtifactWithInvalidCheckSumOfComponentInstanceOnAsset(Component component, User user, ArtifactReqDetails artifactReqDetails, ComponentInstance resourceInstance) throws IOException { + Config config = Utils.getConfig(); + String resourceType = null; + String resourceUUID = component.getUUID(); + String resourceInstanceName = resourceInstance.getNormalizedName(); + + System.out.println(component.getComponentType()); + + if(component.getComponentType().toString().toLowerCase().equals("resource")) { + resourceType = "resources"; + } else { + resourceType = "services"; + } + + String url = String.format(Urls.POST_EXTERNAL_API_UPLOAD_ARTIFACT_OF_COMPONENTINSTANCE_ON_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceType, resourceUUID, resourceInstanceName); + + return uploadInformationalArtifact(artifactReqDetails, user, calculateChecksum(artifactReqDetails) + "123", url); + } + + // Upload Artifact of the asset with invalid checksum + public static RestResponse externalAPIUploadArtifactWithInvalidCheckSumOfTheAsset(Component component, User user, ArtifactReqDetails artifactReqDetails) throws IOException { + Config config = Utils.getConfig(); + String resourceType = null; + String resourceUUID = component.getUUID(); + + System.out.println(component.getComponentType()); + + if(component.getComponentType().toString().toLowerCase().equals("resource")) { + resourceType = "resources"; + } else { + resourceType = "services"; + } + + String url = String.format(Urls.POST_EXTERNAL_API_UPLOAD_ARTIFACT_OF_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceType, resourceUUID); + + return uploadInformationalArtifact(artifactReqDetails, user, calculateChecksum(artifactReqDetails) + "123", url); + } + + + // + // Testing + // + public static RestResponse getResourceDeploymentArtifactExternalAPI(String resourceUUID, String artifactUUID,User sdncModifierDetails, String resourceType) throws IOException { + Config config = Utils.getConfig(); + String url = null; + + if (resourceType.toUpperCase().equals("SERVICE")) { + url = String.format(Urls.GET_DOWNLOAD_SERVICE_ARTIFACT_OF_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceUUID, artifactUUID); + + } else { + url = String.format(Urls.GET_DOWNLOAD_RESOURCE_ARTIFACT_OF_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), resourceUUID, artifactUUID); + } + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + HttpRequest http = new HttpRequest(); + + logger.debug("Send GET request to get Resource Assets: {}", url); + System.out.println("Send GET request to get Resource Assets: " + url); + + logger.debug("Request headers: {}", headersMap); + System.out.println("Request headers: " + headersMap); + + RestResponse sendGetResourceAssets = http.httpSendGet(url, headersMap); + + return sendGetResourceAssets; + + } + + + + public static RestResponse getComponentInstanceDeploymentArtifactExternalAPI(String resourceUUID, String componentNormalizedName, String artifactUUID,User sdncModifierDetails, String resourceType) throws IOException { + Config config = Utils.getConfig(); + String url = null; + + if (resourceType.toLowerCase().equals("service")) { + url = String.format(Urls.GET_DOWNLOAD_SERVICE_ARTIFACT_OF_COMPONENT_INSTANCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceUUID, componentNormalizedName, artifactUUID); + + } else { + url = String.format(Urls.GET_DOWNLOAD_RESOURCE_ARTIFACT_OF_COMPONENT_INSTANCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceUUID, componentNormalizedName, artifactUUID); + } + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + HttpRequest http = new HttpRequest(); + + logger.debug("Send GET request to get Resource Assets: {}", url); + System.out.println("Send GET request to get Resource Assets: " + url); + + logger.debug("Request headers: {}", headersMap); + System.out.println("Request headers: " + headersMap); + + RestResponse sendGetResourceAssets = http.httpSendGet(url, headersMap); + + return sendGetResourceAssets; + + } + + + //*********** SERVICE **************** + public static RestResponse getArtifactTypesList() throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_ALL_ARTIFACTS, config.getCatalogBeHost(), config.getCatalogBePort()); + + return sendGet(url, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + } + + public static RestResponse addInformationalArtifactToService(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String serviceUid) throws IOException { + return addInformationalArtifactToService(artifactDetails, sdncModifierDetails, serviceUid, calculateChecksum(artifactDetails)); + } + + public static RestResponse addInformationalArtifactToService(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String serviceUid, String checksum) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.ADD_ARTIFACT_TO_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), serviceUid); + + return uploadInformationalArtifact(artifactDetails, sdncModifierDetails, checksum, url); + } + + public static RestResponse downloadServiceArtifact(ServiceReqDetails service, ArtifactReqDetails artifact, User user, Map addionalHeaders) throws Exception + { + + return downloadServiceArtifact( service, artifact, user,addionalHeaders,true); + } + + public static RestResponse downloadServiceArtifact(ServiceReqDetails service, ArtifactReqDetails artifact, User user, Map addionalHeaders,boolean addEcompHeader) throws Exception + { + Config config = Utils.getConfig(); + String relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_SERVICE_ARTIFACT_RELATIVE_URL, ValidationUtils.convertToSystemName(service.getName()), service.getVersion(), ValidationUtils.normalizeFileName(artifact.getArtifactName()))); + String fullUrl = String.format(Urls.DOWNLOAD_SERVICE_ARTIFACT_FULL_URL, config.getCatalogBeHost(),config.getCatalogBePort(), relativeUrl); + + return downloadArtifact(fullUrl, user, addionalHeaders,addEcompHeader); + } + + public static RestResponse downloadResourceArtifact(ServiceReqDetails service, ResourceReqDetails resource, ArtifactReqDetails artifact, User user, Map addionalHeaders) throws Exception + { + return downloadResourceArtifact(service, resource, artifact, user,addionalHeaders, true); + } + + public static RestResponse downloadResourceArtifact(ServiceReqDetails service,ResourceReqDetails resource, ArtifactReqDetails artifact, User user, Map addionalHeaders,boolean addEcompHeader) throws Exception + { + Config config = Utils.getConfig(); + String relativeUrl = encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_RESOURCE_ARTIFACT_RELATIVE_URL, ValidationUtils.convertToSystemName(service.getName()),service.getVersion(),ValidationUtils.convertToSystemName(resource.getName()), resource.getVersion(), ValidationUtils.normalizeFileName(artifact.getArtifactName()))); + String fullUrl = String.format(Urls.DOWNLOAD_RESOURCE_ARTIFACT_FULL_URL, config.getCatalogBeHost(),config.getCatalogBePort(), relativeUrl); + + return downloadArtifact(fullUrl, user, addionalHeaders,addEcompHeader); + } + + + + public static RestResponse downloadResourceInstanceArtifact(String serviceUniqueId,String resourceInstanceId, User user, String artifactUniqeId) throws Exception + { + Config config = Utils.getConfig(); + String url = String.format(Urls.DOWNLOAD_COMPONENT_INSTANCE_ARTIFACT, config.getCatalogBeHost(),config.getCatalogBePort(), serviceUniqueId, resourceInstanceId, artifactUniqeId); + RestResponse res = sendGet(url, user.getUserId(), null); + return res; + } + + //// + + //update + + public static RestResponse updateInformationalArtifactOfServiceByMethod(ArtifactReqDetails artifactReqDetails, String serviceUid, String artifactUid, User sdncModifierDetails, String httpMethod) throws IOException { + return updateInformationalArtifactOfServiceByMethod(artifactReqDetails, serviceUid, artifactUid, sdncModifierDetails, httpMethod, calculateChecksum(artifactReqDetails)); + } + + public static RestResponse updateInformationalArtifactOfServiceByMethod(ArtifactReqDetails artifactReqDetails, String serviceUid, User sdncModifierDetails, String httpMethod) throws IOException { + return updateInformationalArtifactOfServiceByMethod(artifactReqDetails, serviceUid, artifactReqDetails.getUniqueId(), sdncModifierDetails, httpMethod, calculateChecksum(artifactReqDetails)); + } + + public static RestResponse downloadResourceArtifactInternalApi(String resourceId, User user, String artifactUniqeId) throws Exception + { + return downloadComponentArtifactInternalApi(resourceId, user, artifactUniqeId, Urls.UI_DOWNLOAD_RESOURCE_ARTIFACT); + } + + public static RestResponse downloadServiceArtifactInternalApi(String componentId, User user, String artifactUniqeId) throws Exception + { + return downloadComponentArtifactInternalApi(componentId, user, artifactUniqeId, Urls.UI_DOWNLOAD_SERVICE_ARTIFACT); + } + public static RestResponse downloadComponentArtifactInternalApi(String componentId, User user, String artifactUniqeId, String urlTemplate) throws Exception + { + Config config = Utils.getConfig(); + String url = String.format(urlTemplate, config.getCatalogBeHost(),config.getCatalogBePort(), componentId, artifactUniqeId); + RestResponse res = sendGet(url, user.getUserId(), null); + return res; + } + +// public static RestResponse downloadServiceArtifactInternalApi(String resourceId, User user, String artifactUniqeId) throws Exception +// { +// Config config = Utils.getConfig(); +// String url = String.format(Urls.UI_DOWNLOAD_SERVICE_ARTIFACT, config.getCatalogBeHost(),config.getCatalogBePort(), resourceId, artifactUniqeId); +// RestResponse res = sendGet(url, user.getUserId(), null); +// return res; +// } + + /* + public static RestResponse updateInformationalArtifactPayloadOfService(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String serviceUid, String artifactUid, String checksum) throws IOException + { + return updateInformationalArtifactOfService(artifactDetails, sdncModifierDetails, serviceUid, artifactUid, checksum, true); + } + + public static RestResponse updateInformationalArtifactMetadataOfService(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String serviceUid, String artifactUid) throws IOException + { + return updateInformationalArtifactOfService(artifactDetails, sdncModifierDetails, serviceUid, artifactUid, calculateChecksum(artifactDetails), false); + } + + public static RestResponse updateInformationalArtifactOfService(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String serviceUid, String artifactUid, String checksum, boolean isPayloadUpdate) throws IOException + { + Config config = Utils.getConfig(); + Map headersMap = getHeadersMap(sdncModifierDetails); + + if (isPayloadUpdate){ + headersMap.put(HttpHeaderEnum.Content_MD5.getValue(), checksum); + } + + Gson gson = new Gson(); + String jsonBody = gson.toJson(artifactDetails); + + HttpRequest http = new HttpRequest(); + + String url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_SERVICE, config.getCatalogBeHost(),config.getCatalogBePort(), serviceUid, artifactUid); + RestResponse res = http.httpSendPost(url, jsonBody, headersMap); + System.out.println("update artifact was finished with response: "+ res.getErrorCode()); + return res; + }*/ + + + + public static RestResponse updateInformationalArtifactOfServiceByMethod(ArtifactReqDetails artifactReqDetails, String serviceUid, String artifactUid, User sdncModifierDetails, String httpMethod, String checksum) throws IOException + { + Config config = Utils.getConfig(); + + Map headersMap = getHeadersMap(sdncModifierDetails); + headersMap.put(HttpHeaderEnum.Content_MD5.getValue(), checksum); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(artifactReqDetails); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_SERVICE, config.getCatalogBeHost(),config.getCatalogBePort(), serviceUid, artifactUid); + RestResponse updateResourceResponse = http.httpSendByMethod(url, httpMethod, userBodyJson, headersMap); +// System.out.println("update artifact was finished with response: "+ updateResourceResponse.getErrorCode()); + + return updateResourceResponse; + } + + + public static Map getHeadersMap(User sdncModifierDetails) { + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptJsonHeader); + + try{ + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + } + catch(Exception e) + { + + } + + return headersMap; + } + + //*********** RESOURCE **************** + //add + public static RestResponse addInformationalArtifactToResource(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String resourceUid) throws IOException{ + return addInformationalArtifactToResource(artifactDetails, sdncModifierDetails, resourceUid, calculateChecksum(artifactDetails)); + } + + public static RestResponse explicitAddInformationalArtifactToResource(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String resourceUid) throws IOException{ + Config config = Utils.getConfig(); + + + String url = String.format(Urls.ADD_ARTIFACT_TO_RESOURCE, config.getCatalogBeHost(),config.getCatalogBePort(), resourceUid); + + return uploadInformationalArtifact(artifactDetails, sdncModifierDetails, calculateChecksum(artifactDetails), url); + } + + + public static RestResponse addInformationalArtifactToResource(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String resourceUid, String checksum) throws IOException{ + Config config = Utils.getConfig(); + + if (artifactDetails.getArtifactGroupType()!=null && artifactDetails.getArtifactGroupType().equals(ArtifactGroupTypeEnum.DEPLOYMENT.getType())){ + //YANG_XML and OTHER deployment artifact should be added through this API, not updated + String artifactType = artifactDetails.getArtifactType(); + if (!(ArtifactTypeEnum.YANG_XML.getType().equals(artifactType) || + ArtifactTypeEnum.OTHER.getType().equals(artifactType) || + ArtifactTypeEnum.VNF_CATALOG.getType().equals(artifactType) || + ArtifactTypeEnum.VF_LICENSE.getType().equals(artifactType) || + ArtifactTypeEnum.VENDOR_LICENSE.getType().equals(artifactType) || + ArtifactTypeEnum.MODEL_INVENTORY_PROFILE.getType().equals(artifactType) || + ArtifactTypeEnum.MODEL_QUERY_SPEC.getType().equals(artifactType) || + ArtifactTypeEnum.APPC_CONFIG.getType().equals(artifactType))){ + //return updateInformationalArtifactToResource(artifactDetails, sdncModifierDetails, resourceUid); + } + } + String url = String.format(Urls.ADD_ARTIFACT_TO_RESOURCE, config.getCatalogBeHost(),config.getCatalogBePort(), resourceUid); + + return uploadInformationalArtifact(artifactDetails, sdncModifierDetails, checksum, url); + } + //update + public static RestResponse updateInformationalArtifactToResource(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String resourceUid) throws IOException{ + return updateInformationalArtifactToResource(artifactDetails, sdncModifierDetails, resourceUid, calculateChecksum(artifactDetails)); + } + + public static RestResponse updateInformationalArtifactToResource(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String resourceUid, String checksum) throws IOException { + Config config = Utils.getConfig(); + if (artifactDetails.getArtifactGroupType()!=null && artifactDetails.getArtifactGroupType().equals("DEPLOYMENT")){ + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceUid ); + Resource resourceRespJavaObject = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + ArtifactDefinition artifactDefinition = deploymentArtifacts.get(artifactDetails.getArtifactLabel()); + artifactDetails.setUniqueId(artifactDefinition.getUniqueId()); + artifactDetails.setArtifactLabel(artifactDefinition.getArtifactLabel()); + + } + + String url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceUid, artifactDetails.getUniqueId()); + + return uploadInformationalArtifact(artifactDetails, sdncModifierDetails, calculateChecksum(artifactDetails), url); + } + + public static RestResponse uploadArtifactToPlaceholderOnResource(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String resourceUid, String placeHolderLabel) throws IOException { + Config config = Utils.getConfig(); + if (artifactDetails.getArtifactLabel() != null && !artifactDetails.getArtifactLabel().isEmpty()){ + RestResponse resourceGetResponse = ResourceRestUtils.getResource(sdncModifierDetails, resourceUid ); + Resource resourceRespJavaObject = ResponseParser.convertResourceResponseToJavaObject(resourceGetResponse.getResponse()); + Map deploymentArtifacts = resourceRespJavaObject.getDeploymentArtifacts(); + ArtifactDefinition artifactDefinition = deploymentArtifacts.get(artifactDetails.getArtifactLabel()); + AssertJUnit.assertNotNull(artifactDefinition); + artifactDetails.setUniqueId(artifactDefinition.getUniqueId()); + artifactDetails.setArtifactLabel(artifactDefinition.getArtifactLabel()); + + } + + String url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceUid, artifactDetails.getUniqueId()); + + return uploadInformationalArtifact(artifactDetails, sdncModifierDetails, calculateChecksum(artifactDetails), url); + } + + public static RestResponse updateArtifactToResourceInstance(ArtifactDefinition artifactDefinition, User sdncModifierDetails, String resourceInstanceId, String serviceId) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_RESOURCE_INSTANCE_ARTIFACT, config.getCatalogBeHost(), config.getCatalogBePort(), serviceId, resourceInstanceId, artifactDefinition.getUniqueId()); + return updateDeploymentArtifact(artifactDefinition, sdncModifierDetails, url); + } + + public static RestResponse updateDeploymentArtifactToResource(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String resourceUid) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceUid, artifactDetails.getUniqueId()); + + return updateDeploymentArtifact(artifactDetails, sdncModifierDetails, url); + } + + + public static RestResponse updateDeploymentArtifactToRI(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String resourceInstanceId, String serviceId) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_RESOURCE_INSTANCE_HEAT_ENV_PARAMS, config.getCatalogBeHost(), config.getCatalogBePort(), serviceId, resourceInstanceId, artifactDetails.getUniqueId()); + return updateDeploymentArtifact(artifactDetails, sdncModifierDetails, url); + } + + //delete + public static RestResponse deleteArtifactFromResourceInstance (ArtifactDefinition artifactDefinition, User sdncModifierDetails, String resourceUid, String serviceId) throws IOException{ + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_RESOURCE_INSTANCE_ARTIFACT, config.getCatalogBeHost(), config.getCatalogBePort(), serviceId, resourceUid, artifactDefinition.getUniqueId()); + return sendDelete(url, sdncModifierDetails.getUserId()); + } + + public static RestResponse deleteInformationalArtifactFromResource(String resourceUid, ArtifactReqDetails artifactDetails, User sdncModifierDetails) throws IOException{ + return deleteInformationalArtifactFromResource( resourceUid, artifactDetails.getUniqueId(), sdncModifierDetails); + } + + public static RestResponse deleteInformationalArtifactFromResource( String resourceUid, String artifactId, User sdncModifierDetails) throws IOException{ + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), resourceUid, artifactId); + return sendDelete(url, sdncModifierDetails.getUserId()); + } + + public static RestResponse deleteServiceApiArtifact(ArtifactReqDetails artifactDetails, String serviceUniqueId, User user) throws Exception + { + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_DELETE_SERVICE_API_ARTIFACT, config.getCatalogBeHost(),config.getCatalogBePort(), serviceUniqueId, artifactDetails.getUniqueId()); + RestResponse res = sendDelete(url, user.getUserId()); + logger.debug("Deleting api artifact was finished with response: {}", res.getErrorCode()); + logger.debug("Response body: {}", res.getResponseMessage()); + return res; + } + + //*************** RESOURCE INSTANCE ************** + /** + * Add DCAE artifacts to resource instance. + * @param artifactDetails + * @param sdncModifierDetails + * @param resourceInstanceId + * @param serviceId + * @return + * @throws IOException + */ + public static RestResponse addArtifactToResourceInstance(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String resourceInstanceId, String serviceId) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.ADD_RESOURCE_INSTANCE_ARTIFACT, config.getCatalogBeHost(), config.getCatalogBePort(), serviceId,resourceInstanceId, artifactDetails.getUniqueId()); + return addArtifactToInstance(artifactDetails, sdncModifierDetails, calculateChecksum(artifactDetails), url); + } + + //*************** COMPONENT ************** + + public static RestResponse uploadDeploymentArtifact(ArtifactReqDetails artifactDetails, Component component, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + Map additionalHeaders = null; + String checksum = ResponseParser.calculateMD5Header(artifactDetails); + additionalHeaders = new HashMap(); + additionalHeaders.put(HttpHeaderEnum.Content_MD5.getValue(), checksum); + + ComponentTypeEnum componentType = component.getComponentType(); + + String url = null; + + switch (componentType){ + + case RESOURCE: + { + url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_SERVICE, config.getCatalogBeHost(),config.getCatalogBePort(), component.getUniqueId(), artifactDetails.getUniqueId()); + + break; + } + case SERVICE: { + + break; + } + + case PRODUCT: { + + break; + } + + default: {//dummy + assertTrue("failed on enum selection", false); + + break; + } + } + + + + + Gson gson = new Gson(); + String jsonBody = gson.toJson(artifactDetails); +// System.out.println("ArtifactDetails: "+ jsonBody); + + RestResponse res = sendPost(url, jsonBody, sdncModifierDetails.getUserId(), acceptHeaderData, additionalHeaders); + if (res.getErrorCode() == STATUS_CODE_SUCCESS) { + artifactDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); + } +// System.out.println("Add artifact was finished with response: "+ res.getErrorCode()); + return res; + } + + public static RestResponse uploadArtifact(ArtifactReqDetails artifactDetails, Component component, User sdncModifierDetails) throws IOException { + Config config = Utils.getConfig(); + List placeHolderlst = Utils.getListOfResPlaceHoldersDepArtTypes(); + Map additionalHeaders = null; + String checksum = null; + String url= null; +// +// +// if (artifactDetails.getArtifactGroupType() != null +// && artifactDetails.getArtifactGroupType().equals("DEPLOYMENT") +// && placeHolderlst.contains(artifactDetails.getArtifactType())) { +// Map deploymentArtifacts = component.getDeploymentArtifacts(); +// ArtifactDefinition artifactDefinition = deploymentArtifacts.get(artifactDetails.getArtifactLabel()); +// artifactDetails.setUniqueId(artifactDefinition.getUniqueId()); +// artifactDetails.setArtifactLabel(artifactDefinition.getArtifactLabel()); +// checksum = ResponseParser.calculateMD5Header(artifactDetails); +// additionalHeaders = new HashMap(); +// additionalHeaders.put(HttpHeaderEnum.Content_MD5.getValue(), checksum); +// url = String.format(Urls.UPDATE_ARTIFACT_OF_COMPONENT, config.getCatalogBeHost(), +// config.getCatalogBePort(), ComponentTypeEnum.findParamByType(component.getComponentType()), +// component.getUniqueId(), artifactDetails.getUniqueId()); +// } +// +// else { + checksum = ResponseParser.calculateMD5Header(artifactDetails); + additionalHeaders = new HashMap(); + additionalHeaders.put(HttpHeaderEnum.Content_MD5.getValue(), checksum); + url = String.format(Urls.UPLOAD_DELETE_ARTIFACT_OF_COMPONENT, config.getCatalogBeHost(), + config.getCatalogBePort(), ComponentTypeEnum.findParamByType(component.getComponentType()), + component.getUniqueId(), artifactDetails.getUniqueId()); +// } + + Gson gson = new Gson(); + String jsonBody = gson.toJson(artifactDetails); +// System.out.println("ArtifactDetails: "+ jsonBody); + + RestResponse res = sendPost(url, jsonBody, sdncModifierDetails.getUserId(), acceptHeaderData, additionalHeaders); + if (res.getErrorCode() == STATUS_CODE_SUCCESS) { + artifactDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); + } +// System.out.println("Add artifact was finished with response: "+ res.getErrorCode()); + return res; + } + + + + + //*************** PRIVATE ************** + private static RestResponse deleteInformationalArtifact(User sdncModifierDetails, String url) throws IOException { + Map additionalHeaders = null; + + additionalHeaders = new HashMap(); + + + additionalHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + additionalHeaders.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + return sendDelete(url, sdncModifierDetails.getUserId(), additionalHeaders); + +// Gson gson = new Gson(); +//// System.out.println("ArtifactDetails: "+ jsonBody); +// String jsonBody = gson.toJson(artifactDetails); +// +// RestResponse res = sendPost(url, jsonBody, sdncModifierDetails.getUserId(), acceptHeaderData, additionalHeaders); +// if ((res.getErrorCode() == STATUS_CODE_SUCCESS) || (res.getErrorCode() == STATUS_CODE_CREATED)) { +// artifactDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); +// } +//// System.out.println("Add artifact was finished with response: "+ res.getErrorCode()); +// return res; + } + + private static RestResponse updateInformationalArtifact(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String checksum, String url) throws IOException { + return uploadInformationalArtifact(artifactDetails, sdncModifierDetails, checksum, url); + } + + private static RestResponse uploadInformationalArtifact(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String checksum, String url) throws IOException { + Map additionalHeaders = null; + if (checksum != null && !checksum.isEmpty()) { + additionalHeaders = new HashMap(); + additionalHeaders.put(HttpHeaderEnum.Content_MD5.getValue(), checksum); + } + + additionalHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + additionalHeaders.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + Gson gson = new Gson(); +// System.out.println("ArtifactDetails: "+ jsonBody); + String jsonBody = gson.toJson(artifactDetails); + + RestResponse res = sendPost(url, jsonBody, sdncModifierDetails.getUserId(), acceptHeaderData, additionalHeaders); + if ((res.getErrorCode() == STATUS_CODE_SUCCESS) || (res.getErrorCode() == STATUS_CODE_CREATED)) { + artifactDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); + } +// System.out.println("Add artifact was finished with response: "+ res.getErrorCode()); + return res; + } + + private static RestResponse addArtifactToInstance(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String checksum, String url) throws IOException { + Map additionalHeaders = null; + additionalHeaders = new HashMap(); + if (checksum != null && !checksum.isEmpty()) { + additionalHeaders = new HashMap(); + additionalHeaders.put(HttpHeaderEnum.Content_MD5.getValue(), checksum); + } + additionalHeaders.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json, text/plain, */*"); + additionalHeaders.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json;charset=UTF-8"); + + Gson gson = new Gson(); + String jsonBody = gson.toJson(artifactDetails); + + RestResponse res = sendPost(url, jsonBody, sdncModifierDetails.getUserId(), "application/json, text/plain, */*", additionalHeaders); + if (res.getErrorCode() == STATUS_CODE_SUCCESS) { + artifactDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); + } + return res; + } + + private static RestResponse updateDeploymentArtifact(ArtifactDefinition artifactDefinition, User sdncModifierDetails, String url) throws IOException { + Map additionalHeaders = null; + additionalHeaders = new HashMap(); + additionalHeaders.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json, text/plain, */*"); + additionalHeaders.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json;charset=UTF-8"); + + Gson gson = new Gson(); + String jsonBody = gson.toJson(artifactDefinition); + + RestResponse res = sendPost(url, jsonBody, sdncModifierDetails.getUserId(), "application/json, text/plain, */*", additionalHeaders); + return res; + } + + private static RestResponse updateDeploymentArtifact(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String url) throws IOException { + Map additionalHeaders = null; + + additionalHeaders = new HashMap(); + additionalHeaders.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json, text/plain, */*"); + additionalHeaders.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json;charset=UTF-8"); +// additionalHeaders.put(HttpHeaderEnum..getValue(), "application/json;charset=UTF-8"); + + + Gson gson = new Gson(); + String jsonBody = gson.toJson(artifactDetails); +// System.out.println("ArtifactDetails: "+ jsonBody); + + RestResponse res = sendPost(url, jsonBody, sdncModifierDetails.getUserId(), "application/json, text/plain, */*", additionalHeaders); + if (res.getErrorCode() == STATUS_CODE_SUCCESS) { + artifactDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); + } +// System.out.println("Add artifact was finished with response: "+ res.getErrorCode()); + return res; + } + + private static RestResponse downloadArtifact(String url, User user, Map addionalHeaders,boolean addEcompHeader) throws IOException + { + if(addEcompHeader){ + addionalHeaders.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), ecomp); + } + return downloadArtifact(url, user, addionalHeaders, acceptOctetStream); + } + + private static RestResponse downloadArtifact(String url, User user, Map addionalHeaders, String accept) throws IOException + { + addionalHeaders.put(HttpHeaderEnum.ACCEPT.getValue(), accept); + + RestResponse res = sendGet(url, user.getUserId(), addionalHeaders); +// System.out.println("download artifact was finished with response: "+ res.getErrorCode()); +// System.out.println("response is: " + res.getResponse()); + return res; + } + + private static Map> getArtifactsListFromResponse(String jsonResponse, String fieldOfArtifactList){ + JSONObject object = (JSONObject)JSONValue.parse(jsonResponse); + Map> map = (Map>)object.get(fieldOfArtifactList); + return map; + } + + public static String calculateChecksum(ArtifactReqDetails artifactDetails) { + String checksum = null; + if (artifactDetails.getPayload() != null) { + checksum = ResponseParser.calculateMD5Header(artifactDetails); + } + return checksum; + } + + public static String encodeUrlForDownload(String url){ + + return url.replaceAll(" ", "%20"); + } + + public static String getPartialUrlByArtifactName(ServiceReqDetails serviceDetails,String serviceVersion ,String artifactName){ + return encodeUrlForDownload(String.format(Urls.DISTRIB_DOWNLOAD_SERVICE_ARTIFACT_RELATIVE_URL, ValidationUtils.convertToSystemName(serviceDetails.getName()), serviceVersion, artifactName)); + } + + public static String getUniqueIdOfArtifact(RestResponse createResponse, String artifactField, String requieredArtifactLabel) throws Exception + { + Map artifact = getArtifactFromRestResponse(createResponse, artifactField, requieredArtifactLabel); + assertNotNull(artifact); + return artifact.get("uniqueId").toString(); + } + + public static Map getArtifactFromRestResponse(RestResponse response, String artifactField, String requieredArtifactLabel) + { + Map> map = getArtifactsListFromResponse(response.getResponse(), artifactField); + return map.get(requieredArtifactLabel); + } + + + + public static RestResponse updateInformationalArtifactPayloadOfService(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String serviceUid, String artifactUid) throws IOException + { + return updateInformationalArtifactPayloadOfService(artifactDetails, sdncModifierDetails, serviceUid, artifactUid, calculateMD5Header(artifactDetails)); + } + + private static RestResponse updateInformationalArtifactPayloadOfService(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String serviceUid, String artifactUid, String checksum) throws IOException + { + return updateInformationalArtifactOfService(artifactDetails, sdncModifierDetails, serviceUid, artifactUid, checksum, true); + } + + private static RestResponse updateInformationalArtifactOfService(ArtifactReqDetails artifactDetails, User sdncModifierDetails, String serviceUid, String artifactUid, String checksum, boolean isPayloadUpdate) throws IOException + { + Config config = Utils.getConfig(); + Map headersMap = prepareHeadersMap(sdncModifierDetails.getUserId()); + + if (isPayloadUpdate){ + headersMap.put(HttpHeaderEnum.Content_MD5.getValue(), checksum); + } + + Gson gson = new Gson(); + String jsonBody = gson.toJson(artifactDetails); + + HttpRequest http = new HttpRequest(); + + String url = String.format(Urls.UPDATE_OR_DELETE_ARTIFACT_OF_SERVICE, config.getCatalogBeHost(),config.getCatalogBePort(), serviceUid, artifactUid); + RestResponse res = http.httpSendPost(url, jsonBody, headersMap); +// System.out.println("update artifact was finished with response: "+ res.getErrorCode()); + return res; + } + + public static String calculateMD5Header(ArtifactReqDetails artifactDetails) + { + Gson gson = new Gson(); + String jsonBody = gson.toJson(artifactDetails); + // calculate MD5 for json body + return calculateMD5(jsonBody); + + } + + public static String calculateMD5 (String data){ + String calculatedMd5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(data); + // encode base-64 result + byte[] encodeBase64 = Base64.encodeBase64(calculatedMd5.getBytes()); + String encodeBase64Str = new String(encodeBase64); + return encodeBase64Str; + + } + + + public static ArtifactDefinition getArtifactDataFromJson(String json) { + Gson gson = new Gson(); + JsonObject jsonElement = new JsonObject(); + jsonElement = gson.fromJson(json, jsonElement.getClass()); + ArtifactDefinition artifact = new ArtifactDefinition(); + String payload = null; + JsonElement artifactPayload = jsonElement.get(Constants.ARTIFACT_PAYLOAD_DATA); + if (artifactPayload != null && !artifactPayload.isJsonNull()) { + payload = artifactPayload.getAsString(); + } + jsonElement.remove(Constants.ARTIFACT_PAYLOAD_DATA); + artifact = gson.fromJson(jsonElement, ArtifactDefinition.class); + artifact.setPayloadData(payload); + + /*atifact.setArtifactName(UPLOAD_ARTIFACT_NAME); +artifact.setArtifactDisplayName("configure"); +artifact.setArtifactType("SHELL"); +artifact.setMandatory(false); +artifact.setDescription("ff"); +artifact.setPayloadData(UPLOAD_ARTIFACT_PAYLOAD); +artifact.setArtifactLabel("configure");*/ + return artifact; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/AssetRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/AssetRestUtils.java new file mode 100644 index 0000000000..13a56417e8 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/AssetRestUtils.java @@ -0,0 +1,626 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.codehaus.jackson.map.ObjectMapper; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.AssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceDetailedAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceInstanceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ServiceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ServiceDetailedAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class AssetRestUtils extends BaseRestUtils { + static Gson gson = new Gson(); + static ObjectMapper objectMapper = new ObjectMapper(); + + static Logger logger = LoggerFactory.getLogger(AssetRestUtils.class.getName()); + static final String contentTypeHeaderData = "application/json"; + static final String acceptHeaderDate = "application/json"; + static final String basicAuthentication = "Basic Y2k6MTIzNDU2"; + // /sdc/v1/catalog/{services/resources}/{componentUUID}/artifacts/{artifactUUID} + static final String COMPONENT_ARTIFACT_URL = "/sdc/v1/catalog/%s/%s/artifacts/%s"; + // /sdc/v1/catalog/{services/resources}/{componentUUID}/resourceInstances/{resourceInstanceName}/artifacts/{artifactUUID} + static final String RESOURCE_INSTANCE_ARTIFACT_URL = "/sdc/v1/catalog/%s/%s/resourceInstances/%s/artifacts/%s"; + + public static HttpResponse getComponentToscaModel(AssetTypeEnum assetType, String uuid) throws IOException { + Config config = Utils.getConfig(); + CloseableHttpClient httpclient = HttpClients.createDefault(); + String url = String.format(Urls.GET_TOSCA_MODEL, config.getCatalogBeHost(), config.getCatalogBePort(), + assetType.getValue(), uuid); + HttpGet httpGet = new HttpGet(url); + + httpGet.addHeader(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + httpGet.addHeader(HttpHeaderEnum.AUTHORIZATION.getValue(), basicAuthentication); + + logger.debug("Send GET request to get Tosca model: {}", url); + + return httpclient.execute(httpGet); + } + + public static File getToscaModelCsarFile(AssetTypeEnum assetType, String uuid) throws IOException { + Config config = Utils.getConfig(); + CloseableHttpClient httpclient = HttpClients.createDefault(); + String url = String.format(Urls.GET_TOSCA_MODEL, config.getCatalogBeHost(), config.getCatalogBePort(), + assetType.getValue(), uuid); + HttpGet httpGet = new HttpGet(url); + File myFile = new File("tmpCSAR"); + + + httpGet.addHeader(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + httpGet.addHeader(HttpHeaderEnum.AUTHORIZATION.getValue(), basicAuthentication); + + logger.debug("Send GET request to get Tosca model: {}", url); + CloseableHttpResponse execute = httpclient.execute(httpGet); + + HttpEntity entity = execute.getEntity(); + if (entity != null) { + try (FileOutputStream outstream = new FileOutputStream(myFile)) { + entity.writeTo(outstream); + outstream.close(); + } + } + return myFile; + } + + public static RestResponse getRestResponseComponentToscaModel(AssetTypeEnum assetType, String uuid) throws IOException { + Config config = Utils.getConfig(); + + String url = String.format(Urls.GET_TOSCA_MODEL, config.getCatalogBeHost(), config.getCatalogBePort(), + assetType.getValue(), uuid); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + HttpRequest http = new HttpRequest(); + + logger.debug("Send GET request to get Resource Assets: {}", url); + System.out.println("Send GET request to get Resource Assets: " + url); + + logger.debug("Request headers: {}", headersMap); + System.out.println("Request headers: " + headersMap); + + RestResponse sendGetResourceAssets = http.httpSendGet(url, headersMap); + + return sendGetResourceAssets; + + } + + public static RestResponse getComponentListByAssetType(boolean isBasicAuthentication, AssetTypeEnum assetType, + String... filterArrayString) throws IOException { + Config config = Utils.getConfig(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + if (isBasicAuthentication) { + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), basicAuthentication); + } + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_ASSET_LIST, config.getCatalogBeHost(), config.getCatalogBePort(), + assetType.getValue()); + if (filterArrayString != null && filterArrayString.length > 0) { + url = buildUrlWithFilter(url, filterArrayString); + } + + RestResponse sendGetResourceAssets = http.httpSendGet(url, headersMap); + + return sendGetResourceAssets; + } + + public static RestResponse getFilteredComponentList(AssetTypeEnum assetType, String query) throws IOException { + Config config = Utils.getConfig(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), basicAuthentication); + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + HttpRequest http = new HttpRequest(); + + String url = String.format(Urls.GET_FILTERED_ASSET_LIST, config.getCatalogBeHost(), config.getCatalogBePort(), + assetType.getValue(), query); + + logger.debug("Send GET request to get Resource Assets: {}", url); + logger.debug("Request headers: {}", headersMap); + + RestResponse sendGetResourceAssets = http.httpSendGet(url, headersMap); + + return sendGetResourceAssets; + } + + public static String buildUrlWithFilter(String url, String[] filterArrayString) { + StringBuilder sb = new StringBuilder(); + int length = filterArrayString.length; + int count = 0; + for (String filterString : filterArrayString) { + sb.append(filterString); + count++; + if (length != count) { + sb.append("&"); + } + } + return url + "?" + sb; + } + + public static RestResponse getAssetMetadataByAssetTypeAndUuid(boolean isBasicAuthentication, + AssetTypeEnum assetType, String uuid) throws IOException { + + Config config = Utils.getConfig(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + if (isBasicAuthentication) { + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), basicAuthentication); + } + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_ASSET_METADATA, config.getCatalogBeHost(), config.getCatalogBePort(), + assetType.getValue(), uuid); + + logger.debug("Send GET request to get Resource Assets: {}", url); + logger.debug("Request headers: {}", headersMap); + + RestResponse sendGetResourceAssets = http.httpSendGet(url, headersMap); + + return sendGetResourceAssets; + } + + public static List getResourceAssetList(RestResponse assetResponse) { + List resourceAssetList = new ArrayList<>(); + + JsonElement jelement = new JsonParser().parse(assetResponse.getResponse()); + JsonArray componenetArray = (JsonArray) jelement; + for (JsonElement jElement : componenetArray) { + ResourceAssetStructure resource = gson.fromJson(jElement, ResourceAssetStructure.class); + resourceAssetList.add(resource); + } + return resourceAssetList; + } + + public static ResourceDetailedAssetStructure getResourceAssetMetadata(RestResponse assetResponse) { + + List resourcesList = new ArrayList<>(); + List artifactsList = new ArrayList<>(); + ResourceDetailedAssetStructure resourceAssetMetadata = new ResourceDetailedAssetStructure(); + String response = assetResponse.getResponse(); + + JsonObject jObject = (JsonObject) new JsonParser().parse(response); + resourceAssetMetadata = gson.fromJson(jObject, ResourceDetailedAssetStructure.class); + + setResourceInstanceAssetList(resourcesList, jObject); + resourceAssetMetadata.setResources(resourcesList); + + setArtifactAssetList(artifactsList, jObject); + resourceAssetMetadata.setArtifacts(artifactsList); + + return resourceAssetMetadata; + } + + public static void generalMetadataFieldsValidatior(AssetStructure assetMetadata, Component component) { + + assertTrue("Expected resourceUuid is " + component.getUUID() + " actual: " + assetMetadata.getUuid(), + assetMetadata.getUuid().equals(component.getUUID())); + assertTrue( + "Expected resourceInvariantUuid is " + component.getInvariantUUID() + " actual: " + + assetMetadata.getInvariantUUID(), + assetMetadata.getInvariantUUID().equals(component.getInvariantUUID())); + assertTrue("Expected asset name is " + component.getName() + " actual: " + assetMetadata.getName(), + assetMetadata.getName().equals(component.getName())); + assertTrue("Expected asset version is " + component.getVersion() + " actual: " + assetMetadata.getVersion(), + assetMetadata.getVersion().equals(component.getVersion())); + assertTrue( + "Expected asset lastUpdaterUserId is " + component.getLastUpdaterUserId() + " actual: " + + assetMetadata.getLastUpdaterUserId(), + assetMetadata.getLastUpdaterUserId().equals(component.getLastUpdaterUserId())); + assertNotNull("Expected asset toscaModel is null", assetMetadata.getToscaModelURL()); + assertTrue( + "Expected asset category is " + component.getCategories().get(0).getName() + " actual: " + + assetMetadata.getCategory(), + assetMetadata.getCategory().equals(component.getCategories().get(0).getName())); + assertTrue( + "Expected asset lifeCycleState is " + component.getLifecycleState() + " actual: " + + assetMetadata.getLifecycleState(), + assetMetadata.getLifecycleState().equals(component.getLifecycleState().toString())); + + } + + public static void resourceMetadataValidatior(ResourceDetailedAssetStructure resourceAssetMetadata, + Resource resource, AssetTypeEnum assetType) throws Exception { + + generalMetadataFieldsValidatior(resourceAssetMetadata, resource); + assertTrue( + "Expected asset lastUpdaterFullName is " + resource.getLastUpdaterFullName() + " actual: " + + resourceAssetMetadata.getLastUpdaterFullName(), + resourceAssetMetadata.getLastUpdaterFullName().equals(resource.getLastUpdaterFullName())); + assertTrue( + "Expected asset subCategory is " + resource.getCategories().get(0).getSubcategories().get(0).getName() + + " actual: " + resourceAssetMetadata.getSubCategory(), + resourceAssetMetadata.getSubCategory() + .equals(resource.getCategories().get(0).getSubcategories().get(0).getName())); + assertTrue( + "Expected asset toscaResourceName is " + resource.getToscaResourceName() + " actual: " + + resourceAssetMetadata.getToscaResourceName(), + resourceAssetMetadata.getToscaResourceName().equals(resource.getToscaResourceName())); + assertTrue( + "Expected asset resourceType is " + resource.getResourceType() + " actual: " + + resourceAssetMetadata.getResourceType(), + resourceAssetMetadata.getResourceType().equals(resource.getResourceType().toString())); + resourceInstanceAssetValidator(resourceAssetMetadata.getResources(), resource, assetType); + // resourceInstanceAssetValidator(resourceAssetMetadata.getResources(), + // resource); + artifactAssetValidator(resourceAssetMetadata.getArtifacts(), resource, assetType); + + } + + public static void serviceMetadataValidatior(ServiceDetailedAssetStructure serviceAssetMetadata, Service service, + AssetTypeEnum assetType) throws Exception { + + generalMetadataFieldsValidatior(serviceAssetMetadata, service); + assertTrue( + "Expected asset lastUpdaterFullName is " + service.getLastUpdaterFullName() + " actual: " + + serviceAssetMetadata.getLastUpdaterFullName(), + serviceAssetMetadata.getLastUpdaterFullName().equals(service.getLastUpdaterFullName())); + assertTrue("Expected asset distributionStatus is " + service.getDistributionStatus() + " actual: " + + serviceAssetMetadata.getDistributionStatus(), + serviceAssetMetadata.getDistributionStatus().equals(service.getDistributionStatus().toString())); + resourceInstanceAssetValidator(serviceAssetMetadata.getResources(), service, assetType); + // resourceInstanceAssetValidator(serviceAssetMetadata.getResources(), + // service); + artifactAssetValidator(serviceAssetMetadata.getArtifacts(), service, assetType); + + } + + private static void artifactAssetValidator(List artifactAssetStructureList, + Component component, AssetTypeEnum assetType) { + Map componentDeploymentArtifacts = component.getDeploymentArtifacts(); + validateArtifactMetadata(componentDeploymentArtifacts, artifactAssetStructureList, component.getUUID(), + assetType, null); + } + + private static void validateArtifactMetadata(Map componentDeploymentArtifacts, + List artifactAssetStructureList, String componentUuid, AssetTypeEnum assetType, + String resourceInstanceName) { + if(componentDeploymentArtifacts != null){ + for (Entry componentDeploymentArtifact : componentDeploymentArtifacts.entrySet()) { + ArtifactAssetStructure artifactAssetStructure = getArtifactMetadata(artifactAssetStructureList, + componentDeploymentArtifact.getValue().getArtifactUUID()); + ArtifactDefinition componentDeploymentArtifactValue = componentDeploymentArtifact.getValue(); + if (artifactAssetStructure != null) { + assertTrue( + "Expected artifact asset artifactName is " + componentDeploymentArtifactValue.getArtifactName() + + " actual: " + artifactAssetStructure.getArtifactName(), + componentDeploymentArtifactValue.getArtifactName() + .equals(artifactAssetStructure.getArtifactName())); + assertTrue( + "Expected artifact asset Type is " + componentDeploymentArtifactValue.getArtifactType() + + " actual: " + artifactAssetStructure.getArtifactType(), + componentDeploymentArtifactValue.getArtifactType() + .equals(artifactAssetStructure.getArtifactType())); + // assertNotNull("Expected artifact asset resourceInvariantUUID + // is null", + // resourceInstanceAssetStructure.getResourceInvariantUUID()); + // String expectedArtifactUrl = "/sdc/v1/catalog/" + + // assetType.getValue() + "/" + componentUuid + "/artifacts/" + + // componentDeploymentArtifactValue.getArtifactUUID(); + String expectedArtifactUrl = ""; + if (resourceInstanceName == null) { + expectedArtifactUrl = String.format(COMPONENT_ARTIFACT_URL, assetType.getValue(), componentUuid, + componentDeploymentArtifactValue.getArtifactUUID()); + } else { + expectedArtifactUrl = String.format(RESOURCE_INSTANCE_ARTIFACT_URL, assetType.getValue(), + componentUuid, resourceInstanceName, componentDeploymentArtifactValue.getArtifactUUID()); + } + + assertTrue( + "Expected artifact asset URL is " + expectedArtifactUrl + " actual: " + + artifactAssetStructure.getArtifactURL(), + artifactAssetStructure.getArtifactURL().equals(expectedArtifactUrl)); + assertTrue( + "Expected artifact asset description is " + componentDeploymentArtifactValue.getDescription() + + " actual: " + artifactAssetStructure.getArtifactDescription(), + componentDeploymentArtifactValue.getDescription().toString() + .equals(artifactAssetStructure.getArtifactDescription())); + assertTrue( + "Expected artifact asset checkSum is " + componentDeploymentArtifactValue.getArtifactChecksum() + + " actual: " + artifactAssetStructure.getArtifactChecksum(), + componentDeploymentArtifactValue.getArtifactChecksum() + .equals(artifactAssetStructure.getArtifactChecksum())); + assertTrue( + "Expected artifact asset version is " + componentDeploymentArtifactValue.getArtifactVersion() + + " actual: " + artifactAssetStructure.getArtifactVersion(), + componentDeploymentArtifactValue.getArtifactVersion() + .equals(artifactAssetStructure.getArtifactVersion())); + if (componentDeploymentArtifactValue.getTimeout() > 0) { + assertTrue( + "Expected artifact asset timeout is " + componentDeploymentArtifactValue.getTimeout() + + " actual: " + artifactAssetStructure.getArtifactTimeout(), + componentDeploymentArtifactValue.getTimeout() + .equals(artifactAssetStructure.getArtifactTimeout())); + } + + } else { + assertTrue("artifact asset with UUID" + componentDeploymentArtifact.getValue().getArtifactUUID() + + " not found in get Metadata response", false); + } + } + }else{ + System.out.println("componentDeploymentArtifacts is null"); + logger.debug("componentDeploymentArtifacts is null"); + } + + } + + private static ArtifactAssetStructure getArtifactMetadata(List artifactAssetStructureList, + String artifactUUID) { + for (ArtifactAssetStructure artifactAssetStructure : artifactAssetStructureList) { + if (artifactAssetStructure.getArtifactUUID().equals(artifactUUID)) { + return artifactAssetStructure; + } + } + return null; + } + + private static void resourceInstanceAssetValidator( + List resourceInstanceAssetStructures, Component component, + AssetTypeEnum assetType) throws Exception { + + List componentInstances = component.getComponentInstances(); + if (componentInstances != null) { + for (ComponentInstance componentInstance : componentInstances) { + ResourceInstanceAssetStructure resourceInstanceAssetStructure = getResourceInstanceMetadata( + resourceInstanceAssetStructures, componentInstance.getName()); + if (resourceInstanceAssetStructure != null) { + assertTrue( + "Expected RI asset resourceName is " + componentInstance.getComponentName() + " actual: " + + resourceInstanceAssetStructure.getResourceName(), + componentInstance.getComponentName() + .equals(resourceInstanceAssetStructure.getResourceName())); + assertTrue( + "Expected RI asset Name is " + componentInstance.getName() + " actual: " + + resourceInstanceAssetStructure.getResourceInstanceName(), + componentInstance.getName() + .equals(resourceInstanceAssetStructure.getResourceInstanceName())); + assertNotNull("Expected RI asset resourceInvariantUUID is null", + resourceInstanceAssetStructure.getResourceInvariantUUID()); + assertTrue( + "Expected RI asset resourceVersion is " + componentInstance.getComponentVersion() + + " actual: " + resourceInstanceAssetStructure.getResourceVersion(), + componentInstance.getComponentVersion() + .equals(resourceInstanceAssetStructure.getResourceVersion())); + assertTrue( + "Expected RI asset resourceType is " + componentInstance.getOriginType() + " actual: " + + resourceInstanceAssetStructure.getResoucreType(), + componentInstance.getOriginType().toString() + .equals(resourceInstanceAssetStructure.getResoucreType())); + Resource resource = AtomicOperationUtils.getResourceObject(componentInstance.getComponentUid()); + assertTrue("Expected RI asset resourceUUID is " + resource.getUUID() + " actual: " + resourceInstanceAssetStructure.getResourceUUID(), + resource.getUUID().equals(resourceInstanceAssetStructure.getResourceUUID())); + validateArtifactMetadata(componentInstance.getDeploymentArtifacts(), + resourceInstanceAssetStructure.getArtifacts(), component.getUUID(), assetType, + componentInstance.getNormalizedName()); + // validateArtifactMetadata(componentInstance.getDeploymentArtifacts(), + // resourceInstanceAssetStructure.getArtifacts(), + // component.getUUID(), AssetTypeEnum.RESOURCES); + } else { + assertTrue("resourceInstance asset with UUID" + componentInstance.getComponentUid() + + " not found in get Metadata response", false); + } + } + } + + } + + // private static ResourceInstanceAssetStructure + // getResourceInstanceMetadata(List + // resourceInstanceAssetStructures, String componentUid) { + private static ResourceInstanceAssetStructure getResourceInstanceMetadata( + List resourceInstanceAssetStructures, String name) { + for (ResourceInstanceAssetStructure resourceInstanceAssetStructure : resourceInstanceAssetStructures) { + if (resourceInstanceAssetStructure.getResourceInstanceName().equals(name)) { + return resourceInstanceAssetStructure; + } + } + return null; + } + + public static ServiceDetailedAssetStructure getServiceAssetMetadata(RestResponse assetResponse) { + + List resourcesList = new ArrayList<>(); + List artifactsList = new ArrayList<>(); + ServiceDetailedAssetStructure serviceAssetMetadata; + + JsonObject jObject = (JsonObject) new JsonParser().parse(assetResponse.getResponse()); + serviceAssetMetadata = gson.fromJson(jObject, ServiceDetailedAssetStructure.class); + + setResourceInstanceAssetList(resourcesList, jObject); + serviceAssetMetadata.setResources(resourcesList); + + setArtifactAssetList(artifactsList, jObject); + serviceAssetMetadata.setArtifacts(artifactsList); + + return serviceAssetMetadata; + } + + public static void setArtifactAssetList(List artifactsList, JsonObject jObject) { + JsonArray artifactsArray = jObject.getAsJsonArray("artifacts"); + if (artifactsArray != null) { + for (JsonElement jElement : artifactsArray) { + ArtifactAssetStructure artifact = gson.fromJson(jElement, ArtifactAssetStructure.class); + artifactsList.add(artifact); + } + } + } + + public static void setResourceInstanceAssetList(List resourcesList, + JsonObject jObject) { + JsonArray resourcesArray = jObject.getAsJsonArray("resources"); + if (resourcesArray != null) { + for (JsonElement jElement : resourcesArray) { + ResourceInstanceAssetStructure resource = gson.fromJson(jElement, ResourceInstanceAssetStructure.class); + resourcesList.add(resource); + } + } + } + + public static List getServiceAssetList(RestResponse assetResponse) { + List serviceAssetList = new ArrayList<>(); + + JsonElement jelement = new JsonParser().parse(assetResponse.getResponse()); + JsonArray componenetArray = (JsonArray) jelement; + for (JsonElement jElement : componenetArray) { + ServiceAssetStructure service = gson.fromJson(jElement, ServiceAssetStructure.class); + serviceAssetList.add(service); + } + return serviceAssetList; + } + + public static List getResourceNamesList(List resourceAssetList) { + List assetNamesList = new ArrayList<>(); + for (ResourceAssetStructure resourceAsset : resourceAssetList) { + assetNamesList.add(resourceAsset.getName()); + } + return assetNamesList; + } + + public static Map getResourceAssetMap(RestResponse assetResponse) { + Map resourceAssetMap = new HashMap<>(); + + JsonElement jelement = new JsonParser().parse(assetResponse.getResponse()); + JsonArray componenetArray = (JsonArray) jelement; + for (JsonElement jElement : componenetArray) { + ResourceAssetStructure resource = gson.fromJson(jElement, ResourceAssetStructure.class); + resourceAssetMap.put(resource.getName(), resource.getVersion()); + } + return resourceAssetMap; + } + + public static Map getResourceListFiltteredByWholeVersion(Map resourceAssetList) { + Map assetNamesMap = new HashMap<>(); + for (Entry entry : resourceAssetList.entrySet()) { + String key = entry.getKey(); + String[] parts = entry.getValue().split("\\."); + String lastOne = parts[parts.length-1]; + + if (key.contains("CinderVolume") ){ + assetNamesMap.put(key,entry.getValue()); + } + + if (lastOne.equals("0") && !key.contains("Ci") ){ + assetNamesMap.put(key,entry.getValue()); + } + } + + return assetNamesMap; + } + + public static List getResourceObjectByNameAndVersionToscaNamesList(Map resourceAssetList) throws Exception { + List assetNamesList = new ArrayList<>(); + for (Entry entry : resourceAssetList.entrySet()) { + System.out.println("fetch data---->"+entry.getKey()+entry.getValue()); + Resource resourceObjectByNameAndVersion = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, entry.getKey(), entry.getValue()); + assetNamesList.add(resourceObjectByNameAndVersion.getToscaResourceName()); + + } + + return assetNamesList; + } + + + public static List getServiceNamesList(List serviceAssetList) { + List assetNamesList = new ArrayList<>(); + for (ServiceAssetStructure serviceAsset : serviceAssetList) { + assetNamesList.add(serviceAsset.getName()); + } + return assetNamesList; + } + + public static void checkResourceTypeInObjectList(List resourceAssetList, ResourceTypeEnum resourceType) { + for (ResourceAssetStructure resourceAsset : resourceAssetList) { + assertTrue("Expected resourceType is " + resourceType.toString() + " actual: " + resourceAsset.getResourceType(), + resourceAsset.getResourceType().equals(resourceType.toString())); + } + } + + public static void checkComponentTypeInObjectList(List resourceAssetList, ComponentTypeEnum componentType) { + ComponentTypeEnum actualComponentType; + for (ResourceAssetStructure resourceAsset : resourceAssetList) { + actualComponentType = detectComponentType(resourceAsset); + assertTrue("Expected componentType is " + componentType.getValue() + " actual: " + actualComponentType.getValue(), actualComponentType.equals(componentType)); + } + } + + private static ComponentTypeEnum detectComponentType(ResourceAssetStructure resourceAsset) { + String resourceType = resourceAsset.getResourceType(); + if(ResourceTypeEnum.getType(resourceType) !=null){ + return ComponentTypeEnum.RESOURCE; + } + return null; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/AutomationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/AutomationUtils.java new file mode 100644 index 0000000000..2e27907fb5 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/AutomationUtils.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; + +public class AutomationUtils extends BaseRestUtils { + + + public static String getOnboardVersion() { + String onboardVersionStr = null; + try { + + RestResponse onboardVersion = CatalogRestUtils.getOnboardVersion(); + onboardVersionStr = ResponseParser.getValueFromJsonResponse(onboardVersion.getResponse() , "Version"); + + } catch (Exception e) { + System.out.println("UnknownOnboardVersion"); + } + return onboardVersionStr != null ? onboardVersionStr : "UnknownOnboardVersion"; + + } + + public static String getOSVersion() { + String osVersionStr = null; + try { + RestResponse osVersion = CatalogRestUtils.getOsVersion(); + osVersionStr = ResponseParser.getVersionFromResponse(osVersion); + + } catch (Exception e) { + System.out.println("UnknownOSversion"); + } + + return osVersionStr != null ? osVersionStr : "UnknownOSversion" ; + } + + + + public static void createVersionsInfoFile(String filepath, String onboardVersion, String osVersion, String envData, String suiteName) + throws FileNotFoundException, IOException { + File myFoo = new File(filepath); + FileOutputStream fooStream = new FileOutputStream(myFoo, false); // true to append + String versions = ("onboardVesrion=\""+ onboardVersion+ "\"\n" + "osVersion=\"" + osVersion + "\"\n" + "env=\""+ envData + "\"\n" + "suiteName=\""+ suiteName+ "\"\n"); + byte[] myBytes = versions.getBytes(); + fooStream.write(myBytes); + fooStream.close(); + } + + public static void createVersionsInfoFile(String filepath, String onboardVersion, String osVersion, String envData) + throws FileNotFoundException, IOException { + createVersionsInfoFile(filepath, onboardVersion, osVersion, envData, null); + } + + public static void addEnvDetailsToReport() throws FileNotFoundException{ + + Config config = Utils.getConfig(); + config.getUrl(); + } + + public static File getConfigFile(String configFileName) throws Exception { + File configFile = new File(getBasePath() + File.separator + "conf" + File.separator + configFileName); + if (!configFile.exists()) { + configFile = new File(getConfFilesPath() + configFileName); + } + return configFile; + } + + public static String getCiFilesPath() { + return getBasePath() + File.separator + "src" + File.separator + "main" + File.separator + "resources" + + File.separator + "ci"; + } + + public static String getConfFilesPath() { + return getCiFilesPath() + File.separator + "conf" + File.separator; + } + + public static String getTestSuitesFilesPath() { + return getCiFilesPath() + File.separator + "testSuites" + File.separator; + } + public static String getBasePath() { + return System.getProperty("user.dir"); + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/BaseRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/BaseRestUtils.java new file mode 100644 index 0000000000..4ea404784a --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/BaseRestUtils.java @@ -0,0 +1,265 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.validation.BaseValidationUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BaseRestUtils extends BaseValidationUtils { + public static final String contentTypeHeaderData = "application/json"; + public static final String acceptHeaderData = "application/json"; + public static final String acceptJsonHeader = "application/json"; + public static final String acceptOctetHeader = "application/octet-stream"; + public static final String authorizationHeader = "Basic " + Base64.encodeBase64String("ci:123456".getBytes()); + public static final String acceptOctetStream = "application/octet-stream"; + public static final String ecomp = "ecomp"; + public static final String authorizationPrefixString = "Basic "; + + public static final String RESOURCE_COMPONENT_TYPE = "resources"; + public static final String PRODUCT_COMPONENT_TYPE = "products"; + public static final String SERVICE_COMPONENT_TYPE = "services"; + + public static final int STATUS_CODE_SUCCESS = 200; + public static final int STATUS_CODE_CREATED = 201; + public static final int STATUS_CODE_DELETE = 204; + public static final int STATUS_CODE_NOT_FOUND = 404; + public static final int STATUS_CODE_SUCCESS_NO_CONTENT = 204; + public static final int STATUS_CODE_SUCCESS_DELETE = 204; + public static final int STATUS_CODE_INVALID_CONTENT = 400; + public static final int STATUS_CODE_MISSING_DATA = 400; + public static final int STATUS_CODE_MISSING_INFORMATION = 403; + public static final int STATUS_CODE_RESTRICTED_ACCESS = 403; + public static final int STATUS_CODE_ALREADY_EXISTS = 409; + public static final int STATUS_CODE_RESTRICTED_OPERATION = 409; + public static final int STATUS_CODE_COMPONENT_NAME_EXCEEDS_LIMIT = 400; + public static final int STATUS_CODE_MISSING_COMPONENT_NAME = 400; + public static final int STATUS_CODE_UNSUPPORTED_ERROR = 400; + public static final int STATUS_CODE_IMPORT_SUCCESS = 201; + public static final int STATUS_CODE_UPDATE_SUCCESS = 200; + public static final int RESTRICTED_OPERATION = 409; + public static final int STATUS_CODE_GET_SUCCESS = 200; + + public static final String SUCCESS_MESSAGE = "OK"; + private static Logger logger = LoggerFactory.getLogger(BaseRestUtils.class.getName()); + + private static byte[] encodeBase64; + + // ************* PRIVATE METHODS ************************ + + protected static Map prepareHeadersMap(String userId) { + return prepareHeadersMap(userId, acceptHeaderData); + } + + protected static Map prepareHeadersMap(String userId, String accept) { + Map headersMap = new HashMap(); + if (contentTypeHeaderData != null) { + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + } + if (accept != null) { + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), accept); + } + if (userId != null) { + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), userId); + } + + return headersMap; + } + + // send request + // GET + protected static RestResponse sendGet(String url, String userId) throws IOException { + return sendGet(url, userId, null); + } + + protected static RestResponse sendGet(String url, String userId, Map additionalHeaders) + throws IOException { + Map headersMap = prepareHeadersMap(userId); + if (additionalHeaders != null) { + headersMap.putAll(additionalHeaders); + } + + HttpRequest http = new HttpRequest(); + RestResponse getResourceResponse = http.httpSendGet(url, headersMap); + return getResourceResponse; + } + + public static RestResponse sendGetAndRemoveHeaders(String url, String userId, List headersToRemove) + throws IOException { + Map headersMap = prepareHeadersMap(userId); + if (headersToRemove != null) { + for (String header : headersToRemove) { + headersMap.remove(header); + } + } + + HttpRequest http = new HttpRequest(); + RestResponse getResourceResponse = http.httpSendGet(url, headersMap); + return getResourceResponse; + } + + // PUT + protected static RestResponse sendPut(String url, String userBodyJson, String userId, String cont) + throws IOException { + Map headersMap = prepareHeadersMap(userId, cont); + + HttpRequest http = new HttpRequest(); + RestResponse updateResourceResponse = http.httpSendByMethod(url, "PUT", userBodyJson, headersMap); + return updateResourceResponse; + } + + // POST + public static RestResponse sendPost(String url, String userBodyJson, String userId, String accept) + throws IOException { + return sendPost(url, userBodyJson, userId, accept, null); + } + + protected static RestResponse sendPost(String url, String userBodyJson, String userId, String accept, + Map additionalHeaders) throws IOException { + Map headersMap = prepareHeadersMap(userId, accept); + if (additionalHeaders != null) { + headersMap.putAll(additionalHeaders); + } + HttpRequest http = new HttpRequest(); + RestResponse postResourceResponse = http.httpSendPost(url, userBodyJson, headersMap); + return postResourceResponse; + } + + // used form complex requests like import categories.. + protected static RestResponse sendPost(String url, HttpEntity entity, String userId, String accept) + throws IOException { + RestResponse postResponse = new RestResponse(); + CloseableHttpResponse response = null; + CloseableHttpClient client = null; + try { + client = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost(url); + + httpPost.addHeader("USER_ID", userId); + httpPost.setEntity(entity); + response = client.execute(httpPost); + HttpEntity responseEntity = response.getEntity(); + int statusCode = response.getStatusLine().getStatusCode(); + + postResponse.setErrorCode(statusCode); + StringBuffer sb = new StringBuffer(); + try { + BufferedReader in = new BufferedReader(new InputStreamReader(responseEntity.getContent())); + String inputLine; + while ((inputLine = in.readLine()) != null) { + sb.append(inputLine); + } + in.close(); + } catch (Exception e) { + logger.debug("response body is null"); + } + postResponse.setResponse(sb.toString()); + } finally { + try { + if (response != null) { + response.close(); + } + + } catch (IOException e) { + logger.debug("failed to close client or response: ", e); + } + try { + if (client != null) { + client.close(); + } + } catch (IOException e) { + logger.debug("failed to close client or response: ", e); + } + } + return postResponse; + } + + // DELETE + protected static RestResponse sendDelete(String url, String userId) throws IOException { +// Map headersMap = prepareHeadersMap(userId); + + return sendDelete(url, userId, null); + } + + protected static RestResponse sendDelete(String url, String userId, Map additionalHeaders) throws IOException { + Map headersMap = prepareHeadersMap(userId); + if (additionalHeaders != null) { + headersMap.putAll(additionalHeaders); + } + + HttpRequest http = new HttpRequest(); + RestResponse deleteResourceResponse = http.httpSendDelete(url, headersMap); + return deleteResourceResponse; + } + + /* + * // ------ protected static Boolean checkErrorCode(RestResponse + * deleteResponse) { if (deleteResponse.getErrorCode() == + * STATUS_CODE_SUCCESS || deleteResponse.getErrorCode() == + * STATUS_CODE_DELETE) { return true; } return false; } + * + * // *** STATUS CODE VALIDATION UTIITIES **** public static void + * checkStatusCode(RestResponse response, String assertMessage, boolean AND, + * int... statuses) { int statusCode = response.getErrorCode(); for (int + * status : statuses) { if (AND && statusCode != status) { + * Assert.fail(assertMessage + " status: " + statusCode); } else if + * (statusCode == status) { return; } } if (!AND) { + * Assert.fail(assertMessage + " status: " + statusCode); } } + * + * public static void checkDeleteResponse(RestResponse response) { + * checkStatusCode(response,"delete request failed",false,STATUS_CODE_DELETE + * ,STATUS_CODE_NOT_FOUND, STATUS_CODE_SUCCESS); // STATUS_CODE_SUCCESS for + * deActivate user } + * + * public static void checkCreateResponse(RestResponse response) { + * checkStatusCode(response, "create request failed", false, + * STATUS_CODE_CREATED); } + */ + public static String encodeUrlForDownload(String url) { + return url.replaceAll(" ", "%20"); + } + + public static Map addAuthorizeHeader(String userName, String password) { + String userCredentials = userName + ":" + password; + encodeBase64 = Base64.encodeBase64(userCredentials.getBytes()); + String encodedUserCredentials = authorizationPrefixString + new String(encodeBase64); + Map authorizationHeader = new HashMap(); + authorizationHeader.put(HttpHeaderEnum.AUTHORIZATION.getValue(), encodedUserCredentials); + return authorizationHeader; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/CatalogRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/CatalogRestUtils.java new file mode 100644 index 0000000000..25fce34a75 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/CatalogRestUtils.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; + +public class CatalogRestUtils extends BaseRestUtils { + + public static RestResponse getAbstractResources() throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_ALL_ABSTRACT_RESOURCES, config.getCatalogBeHost(), + config.getCatalogBePort()); + + return sendGet(url, UserRoleEnum.DESIGNER.getUserId()); + } + + public static RestResponse getCatalog() throws IOException { + return getCatalog(UserRoleEnum.DESIGNER.getUserId()); + } + + public static RestResponse getCatalog(String userId) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_CATALOG_DATA, config.getCatalogBeHost(), config.getCatalogBePort()); + return sendGet(url, userId); + } + + public static RestResponse getAllCategoriesTowardsCatalogBe() throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_ALL_CATEGORIES, config.getCatalogBeHost(), config.getCatalogBePort(), + BaseRestUtils.RESOURCE_COMPONENT_TYPE); + + return sendGet(url, UserRoleEnum.DESIGNER.getUserId()); + } + + public static RestResponse getAllCategoriesTowardsCatalogFeWithUuid(String uuid) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_ALL_CATEGORIES_FE, config.getCatalogFeHost(), config.getCatalogFePort(), + BaseRestUtils.RESOURCE_COMPONENT_TYPE); + + Map additionalHeaders = new HashMap(); + additionalHeaders.put(HttpHeaderEnum.X_ECOMP_REQUEST_ID_HEADER.getValue(), uuid); + + return sendGet(url, UserRoleEnum.DESIGNER.getUserId(), additionalHeaders); + } + + public static RestResponse getOnboardVersion() throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.ONBOARD_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort()); + + return sendGet(url, UserRoleEnum.DESIGNER.getUserId()); + } + + public static RestResponse getOsVersion() throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.OS_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort()); + + return sendGet(url, UserRoleEnum.DESIGNER.getUserId()); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/CategoryRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/CategoryRestUtils.java new file mode 100644 index 0000000000..460518b35f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/CategoryRestUtils.java @@ -0,0 +1,309 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +public class CategoryRestUtils extends BaseRestUtils { + + private static final int STATUS_CODE_CREATED = 201; + + private static Gson gson = new Gson(); + + public static RestResponse createCategory(CategoryDefinition categoryDefinition, User sdncModifierDetails, + String categoryType) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_CATEGORY, config.getCatalogBeHost(), config.getCatalogBePort(), + categoryType); + String bodyJson = gson.toJson(categoryDefinition); + RestResponse addCategoryResponse = BaseRestUtils.sendPost(url, bodyJson, sdncModifierDetails.getUserId(), + acceptHeaderData); + if (addCategoryResponse.getErrorCode().intValue() == STATUS_CODE_CREATED) + categoryDefinition.setUniqueId( + ResponseParser.getValueFromJsonResponse(addCategoryResponse.getResponse(), "uniqueId")); + return addCategoryResponse; + } + + // GET categories + public static RestResponse getAllCategories(User sdncModifierDetails, String categoryType) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_ALL_CATEGORIES, config.getCatalogBeHost(), config.getCatalogBePort(), + categoryType); + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + RestResponse getCategotyResponse = http.httpSendGet(url, headersMap); + return getCategotyResponse; + } + + public static RestResponse getAllCategoriesTowardsFe(User sdncModifierDetails, String categoryType) + throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_ALL_CATEGORIES_FE, config.getCatalogFeHost(), config.getCatalogFePort(), + categoryType); + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + RestResponse getCategotyResponse = http.httpSendGet(url, headersMap); + return getCategotyResponse; + } + + // Delete Category + public static RestResponse deleteCategory(String categoryId, String psUserId, String categoryType) + throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_CATEGORY, config.getCatalogBeHost(), config.getCatalogBePort(), + categoryType, categoryId); + url = url.replace("#", "%23"); // HEX + url = url.replace(" ", "%20"); // HEX + RestResponse deleteCategoryResponse = sendDelete(url, psUserId); + return deleteCategoryResponse; + } + + public static RestResponse createSubCategory(SubCategoryDefinition subCategory, CategoryDefinition parentCategory, + User sdncModifierDetails, String categoryType) throws Exception { + // categoryType = service/resource/product + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_SUB_CATEGORY, config.getCatalogBeHost(), config.getCatalogBePort(), + categoryType, parentCategory.getUniqueId()); + String bodyJson = gson.toJson(subCategory); + RestResponse createSubCategoryPost = BaseRestUtils.sendPost(url, bodyJson, sdncModifierDetails.getUserId(), + acceptHeaderData); + if (createSubCategoryPost.getErrorCode().intValue() == STATUS_CODE_CREATED) + subCategory.setUniqueId( + ResponseParser.getValueFromJsonResponse(createSubCategoryPost.getResponse(), "uniqueId")); + + return createSubCategoryPost; + } + + public static RestResponse deleteSubCategory(String subCategoryId, String categoryId, String psUserId, + String categoryType) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_SUB_CATEGORY, config.getCatalogBeHost(), config.getCatalogBePort(), + categoryType, categoryId, subCategoryId); + url = url.replace("#", "%23"); // HEX + url = url.replace(" ", "%20"); // HEX + RestResponse deleteSubCategoryResponse = sendDelete(url, psUserId); + return deleteSubCategoryResponse; + } + + public static RestResponse deleteGrouping(String groupId, String subCategoryId, String categoryId, String psUserId, + String categoryType) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_GROUPING, config.getCatalogBeHost(), config.getCatalogBePort(), + categoryType, categoryId, subCategoryId, groupId); + url = url.replace("#", "%23"); // HEX + url = url.replace(" ", "%20"); // HEX + RestResponse deleteGroupResponse = sendDelete(url, psUserId); + return deleteGroupResponse; + } + + public static RestResponse createServiceCategoryHttpCspAtuUidIsMissing(CategoryDefinition categoryDataDefinition, + User sdncModifierDetails) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_CATEGORY, config.getCatalogBeHost(), config.getCatalogBePort(), + SERVICE_COMPONENT_TYPE); + + Map headersMap = prepareHeadersMap(sdncModifierDetails.getUserId()); + headersMap.remove("USER_ID"); + Gson gson = new Gson(); + String userBodyJson = gson.toJson(categoryDataDefinition); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + // System.out.println(userBodyJson); + RestResponse createCatergoryResponse = http.httpSendPost(url, userBodyJson, headersMap); + return createCatergoryResponse; + } + + public static RestResponse createSubCategoryHttpCspAtuUidIsMissing(SubCategoryDefinition subCategory, + CategoryDefinition parentCategory, User sdncModifierDetails, String categoryType) throws Exception { + // categoryType = service/resource/product + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_SUB_CATEGORY, config.getCatalogBeHost(), config.getCatalogBePort(), + categoryType, parentCategory.getUniqueId()); + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + headersMap.remove("USER_ID"); + Gson gson = new Gson(); + String subCatJson = gson.toJson(subCategory); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + // System.out.println(subCatJson); + RestResponse addCategoryResponse = http.httpSendPost(url, subCatJson, headersMap); + return addCategoryResponse; + } + + public static RestResponse deleteCatergoryHttpCspAtuUidIsMissing(CategoryDefinition categoryDataDefinition, + User sdncModifierDetails) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_CONSUMER, config.getCatalogBeHost(), config.getCatalogBePort(), + categoryDataDefinition.getName()); + + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + headersMap.remove("USER_ID"); + Gson gson = new Gson(); + String userBodyJson = gson.toJson(categoryDataDefinition); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + // System.out.println(userBodyJson); + RestResponse deleteCategotyResponse = http.httpSendDelete(url, headersMap); + return deleteCategotyResponse; + } + + public static RestResponse createGrouping(GroupingDefinition grouping, SubCategoryDefinition subCategory, + CategoryDefinition parentCategory, User sdncModifierDetails, String categoryType) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_GROUPING, config.getCatalogBeHost(), config.getCatalogBePort(), + categoryType, parentCategory.getUniqueId(), subCategory.getUniqueId()); + String bodyJson = gson.toJson(grouping); + RestResponse addGroupingResponse = BaseRestUtils.sendPost(url, bodyJson, sdncModifierDetails.getUserId(), + acceptHeaderData); + return addGroupingResponse; + } + + public static RestResponse importCategories(MultipartEntityBuilder mpBuilder, String userId) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.IMPORT_CATEGORIES, config.getCatalogBeHost(), config.getCatalogBePort()); + + RestResponse importResponse = BaseRestUtils.sendPost(url, mpBuilder.build(), userId, acceptHeaderData); + return importResponse; + } + + public static int getMatchingCategoriesNum(RestResponse getAllCategoryRest, CategoryDefinition categoryDefinition) { + String response = getAllCategoryRest.getResponse(); + Gson gson = new Gson(); + List categoryDefinitions = gson.fromJson(response, + new TypeToken>() { + }.getType()); + int categoriesNum = 0; + String catName = categoryDefinition.getName(); + for (CategoryDefinition elem : categoryDefinitions) { + if (elem.getName().equals(catName)) { + categoryDefinition.setUniqueId(elem.getUniqueId()); + categoriesNum++; + } + } + + return categoriesNum; + } + + public static int getMatchingSubCategoriesNum(RestResponse getAllCategoryRest, String parentCategoryId, + SubCategoryDefinition expectedSubCategoryDefinition) { + + String response = getAllCategoryRest.getResponse(); + Gson gson = new Gson(); + List categoryDefinitions = gson.fromJson(response, + new TypeToken>() { + }.getType()); + int subCatNum = 0; + String subCatName = expectedSubCategoryDefinition.getName(); + for (CategoryDefinition elem : categoryDefinitions) { + if (elem.getUniqueId().equals(parentCategoryId)) { + List subCategories = elem.getSubcategories(); + if (subCategories != null) { + for (SubCategoryDefinition subCategoryDataDefinition : subCategories) { + if (subCatName.equals(subCategoryDataDefinition.getName())) { + expectedSubCategoryDefinition.setUniqueId(subCategoryDataDefinition.getUniqueId()); + subCatNum++; + } + } + } + + } + } + return subCatNum; + } + + public static int getMatchingGroupingNum(RestResponse getAllCategoryRest, String parentCategoryId, + String subCategoryId, GroupingDefinition expectedGroupingDefinition) { + + String response = getAllCategoryRest.getResponse(); + Gson gson = new Gson(); + List categoryDefinitions = gson.fromJson(response, + new TypeToken>() { + }.getType()); + int groupingNum = 0; + String groupingName = expectedGroupingDefinition.getName(); + for (CategoryDefinition elem : categoryDefinitions) { + if (elem.getUniqueId().equals(parentCategoryId)) { + List subCategories = elem.getSubcategories(); + if (subCategories != null) { + for (SubCategoryDefinition subCategoryDataDefinition : subCategories) { + // if + // (subCategoryId.equals(subCategoryDataDefinition.getUniqueId())) + // { + if (subCategoryId.equals(subCategoryDataDefinition.getUniqueId()) + && subCategoryDataDefinition.getGroupings() != null) { + List grouping = subCategoryDataDefinition.getGroupings(); + for (GroupingDefinition groupingDataDefinition : grouping) { + if (groupingName.equals(groupingDataDefinition.getName())) { + expectedGroupingDefinition.setUniqueId(groupingDataDefinition.getUniqueId()); + groupingNum++; + } + } + + } + } + } + + } + } + return groupingNum; + } + + public enum CategoryAuditJsonKeysEnum { + ACTION("ACTION"), MODIFIER("MODIFIER"), CATEGORY_NAME("CATEGORY_NAME"), SUB_CATEGORY_NAME("SUB_CATEGORY_NAME"), GROUPING_NAME("GROUPING_NAME"), RESOURCE_TYPE("RESOURCE_TYPE"), ECOMP_USER("ECOMP_USER"), STATUS("STATUS"), DESCRIPTION("DESCRIPTION"), DETAILS("DETAILS"); + + private String auditJsonKeyName; + + private CategoryAuditJsonKeysEnum(String auditJsonKeyName) { + this.auditJsonKeyName = auditJsonKeyName; + } + + public String getAuditJsonKeyName() { + return auditJsonKeyName.toLowerCase(); + } + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ComponentInstanceRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ComponentInstanceRestUtils.java new file mode 100644 index 0000000000..1b550e4fff --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ComponentInstanceRestUtils.java @@ -0,0 +1,276 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import static org.testng.Assert.assertTrue; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; + +import com.google.gson.Gson; + +public class ComponentInstanceRestUtils extends BaseRestUtils { + public static String acceptHeaderDate = "application/json"; + static Config config = Config.instance(); + public static Gson gson = new Gson(); + + // 'componentType' can be 'services' or 'resources' + + public static RestResponse createComponentInstance(ComponentInstanceReqDetails componentInstanceReqDetails, + User sdncModifierDetails, Component component) throws Exception { + return createComponentInstance(componentInstanceReqDetails, sdncModifierDetails, component.getUniqueId(), + component.getComponentType()); + } + + public static RestResponse createComponentInstance(ComponentInstanceReqDetails componentInstanceReqDetails, + User sdncModifierDetails, String componentId, ComponentTypeEnum componentType) throws Exception { + + return createComponentInstance(componentInstanceReqDetails, sdncModifierDetails, componentId, + ComponentTypeEnum.findParamByType(componentType)); + } + + public static RestResponse createComponentInstance(ComponentInstanceReqDetails componentInstanceReqDetails, + User sdncModifierDetails, String componentId, String componentType) throws Exception { + Config config = Utils.getConfig(); + String userId = sdncModifierDetails.getUserId(); + String serviceBodyJson = gson.toJson(componentInstanceReqDetails); + String url = String.format(Urls.CREATE_COMPONENT_INSTANCE, config.getCatalogBeHost(), config.getCatalogBePort(), + componentType, componentId); + RestResponse createResourceInstance = sendPost(url, serviceBodyJson, userId, acceptHeaderData); + if (createResourceInstance.getErrorCode().equals(BaseRestUtils.STATUS_CODE_CREATED)) { + String uniqueId = ResponseParser.getValueFromJsonResponse(createResourceInstance.getResponse(), "uniqueId"); + componentInstanceReqDetails.setUniqueId(uniqueId); + // Gson gson = new Gson(); + // ResourceInstanceReqDetails fromJson = + // gson.fromJson(createResourceInstance.getResponse(), + // ResourceInstanceReqDetails.class); + // componentInstanceReqDetails.setUniqueId(fromJson.getUniqueId()); + } + return createResourceInstance; + } + + public static RestResponse getComponentInstances(ComponentTypeEnum type, String componentId, User user) + throws IOException { + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderData); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), user.getUserId()); + + String url = String.format(Urls.GET_COMPONENT_INSTANCES, config.getCatalogBeHost(), config.getCatalogBePort(), + ComponentTypeEnum.findParamByType(type), componentId); + + RestResponse sendGetServerRequest = sendGet(url, user.getUserId(), headersMap); + + return sendGetServerRequest; + + } + + public static RestResponse deleteComponentInstance(User sdncModifierDetails, String componentId, + String resourceInstanceId, ComponentTypeEnum componentType) throws Exception { + + return deleteComponentInstance(sdncModifierDetails, componentId, resourceInstanceId, + ComponentTypeEnum.findParamByType(componentType)); + } + + public static RestResponse deleteComponentInstance(User sdncModifierDetails, String componentId, + String resourceInstanceId, String componentTypeString) throws Exception { + Config config = Utils.getConfig(); + String userId = sdncModifierDetails.getUserId(); + String url = String.format(Urls.DELETE_COMPONENT_INSTANCE, config.getCatalogBeHost(), config.getCatalogBePort(), + componentTypeString, componentId, resourceInstanceId); + RestResponse sendCreateUserRequest = sendDelete(url, userId); + return sendCreateUserRequest; + } + + public static RestResponse updateComponentInstance(ComponentInstanceReqDetails componentInstanceReqDetails, + User sdncModifierDetails, String componentId, ComponentTypeEnum componentType) throws IOException { + + Config config = Utils.getConfig(); + String userId = sdncModifierDetails.getUserId(); + String serviceBodyJson = gson.toJson(componentInstanceReqDetails); + String url = String.format(Urls.UPDATE_COMPONENT_INSTANCE, config.getCatalogBeHost(), config.getCatalogBePort(), + ComponentTypeEnum.findParamByType(componentType), componentId, + componentInstanceReqDetails.getUniqueId()); + RestResponse updateResourceInstance = sendPost(url, serviceBodyJson, userId, acceptHeaderData); + return updateResourceInstance; + } + + //Tal G - CI for New API Multiple Instance Update + public static RestResponse updateMultipleComponentInstance( + List componentInstanceReqDetailsList, User sdncModifierDetails, + String componentId, ComponentTypeEnum componentType) throws IOException { + Config config = Utils.getConfig(); + String userId = sdncModifierDetails.getUserId(); + String serviceBodyJson = gson.toJson(componentInstanceReqDetailsList.toArray()); + String url = String.format(Urls.UPDATE_MULTIPLE_COMPONENT_INSTANCE, config.getCatalogBeHost(), + config.getCatalogBePort(), ComponentTypeEnum.findParamByType(componentType), componentId); + RestResponse updateResourceInstance = sendPost(url, serviceBodyJson, userId, acceptHeaderData); + return updateResourceInstance; + } + + public static RestResponse associateInstances(RequirementCapabilityRelDef relation, User sdncModifierDetails, + String componentId, ComponentTypeEnum componentTypeEnum) throws IOException { + + Config config = Utils.getConfig(); + + String componentType = ""; + switch (componentTypeEnum) { + case RESOURCE: + componentType = ComponentTypeEnum.RESOURCE_PARAM_NAME; + break; + case SERVICE: + componentType = ComponentTypeEnum.SERVICE_PARAM_NAME; + break; + default: + break; + } + String serviceBodyJson = gson.toJson(relation); + String url = String.format(Urls.ASSOCIATE__RESOURCE_INSTANCE, config.getCatalogBeHost(), + config.getCatalogBePort(), componentType, componentId); + + RestResponse associateInstance = sendPost(url, serviceBodyJson, sdncModifierDetails.getUserId(), + acceptHeaderData); + return associateInstance; + + } + + public static RestResponse dissociateInstances(RequirementCapabilityRelDef relation, User sdncModifierDetails, + String componentId, ComponentTypeEnum componentTypeEnum) throws IOException { + + Config config = Utils.getConfig(); + + String componentType = ""; + switch (componentTypeEnum) { + case RESOURCE: + componentType = ComponentTypeEnum.RESOURCE_PARAM_NAME; + break; + case SERVICE: + componentType = ComponentTypeEnum.SERVICE_PARAM_NAME; + break; + default: + break; + } + String serviceBodyJson = gson.toJson(relation); + String url = String.format(Urls.DISSOCIATE__RESOURCE_INSTANCE, config.getCatalogBeHost(), + config.getCatalogBePort(), componentType, componentId); + + RestResponse associateInstance = sendPut(url, serviceBodyJson, sdncModifierDetails.getUserId(), + acceptHeaderData); + return associateInstance; + + } + + public static void checkComponentInstanceType(RestResponse response, String expectedComponentType) { + String actualComponentType = ResponseParser.getComponentTypeFromResponse(response); + assertTrue(expectedComponentType.equals(actualComponentType), + "Failed. expected: " + expectedComponentType + ", actual: " + actualComponentType + "/"); + } + + public static RestResponse updatePropertyValueOnResourceInstance(Component component, ComponentInstance instDetails, + User user, ComponentInstanceProperty updatedInstanceProperty) throws IOException { + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderData); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), user.getUserId()); + + String url = String.format(Urls.UPDATE_PROPERTY_TO_RESOURCE_INSTANCE, config.getCatalogBeHost(), + config.getCatalogBePort(), ComponentTypeEnum.findParamByType(component.getComponentType()), + component.getUniqueId(), instDetails.getUniqueId()); + String body = gson.toJson(updatedInstanceProperty); + + RestResponse sendGetServerRequest = sendPost(url, body, user.getUserId(), acceptHeaderData); + return sendGetServerRequest; + + } + + public static RestResponse changeComponentInstanceVersion(Component container, + ComponentInstance componentInstanceToReplace, Component newInstance, User sdncModifierDetails) + throws Exception { + + return changeComponentInstanceVersion(container.getUniqueId(), componentInstanceToReplace, newInstance, + sdncModifierDetails, container.getComponentType()); + } + + public static RestResponse changeComponentInstanceVersion(String containerUID, + ComponentInstance componentInstanceToReplace, Component component, User sdncModifierDetails, + ComponentTypeEnum componentType) throws IOException { + + Config config = Utils.getConfig(); + String resourceUid = ("{\"componentUid\":\"" + component.getUniqueId() + "\"}"); + String url = String.format(Urls.CHANGE__RESOURCE_INSTANCE_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), ComponentTypeEnum.findParamByType(componentType), containerUID, + componentInstanceToReplace.getUniqueId()); + RestResponse changeResourceInstanceVersion = sendPost(url, resourceUid, sdncModifierDetails.getUserId(), + acceptHeaderData); + + if (changeResourceInstanceVersion.getErrorCode() == 200 + || changeResourceInstanceVersion.getErrorCode() == 201) { + Gson gson = new Gson(); + // ResourceInstanceReqDetails + // convertResourceInstanceResponseToJavaObject = + // ResponseParser.convertResourceInstanceResponseToJavaObject(createResourceInstance.getResponse()); + ComponentInstanceReqDetails fromJson = gson.fromJson(changeResourceInstanceVersion.getResponse(), + ComponentInstanceReqDetails.class); + + componentInstanceToReplace.setUniqueId(fromJson.getUniqueId()); + + } + + return changeResourceInstanceVersion; + + } + + public static RestResponse changeComponentInstanceVersion(String componentUniqueId, + String serviceInstanceToReplaceUniqueId, String serviceUniqueId, User sdncModifierDetails, + ComponentTypeEnum componentType) throws IOException { + Config config = Utils.getConfig(); + String resourceUid = ("{\"componentUid\":\"" + serviceUniqueId + "\"}"); + String url = String.format(Urls.CHANGE__RESOURCE_INSTANCE_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), ComponentTypeEnum.findParamByType(componentType), componentUniqueId, + serviceInstanceToReplaceUniqueId); + RestResponse changeResourceInstanceVersion = sendPost(url, resourceUid, sdncModifierDetails.getUserId(), + acceptHeaderData); + return changeResourceInstanceVersion; + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ComponentRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ComponentRestUtils.java new file mode 100644 index 0000000000..dcebe4afa8 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ComponentRestUtils.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.IOException; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; + +public class ComponentRestUtils extends BaseRestUtils { + public static RestResponse getComponentRequirmentsCapabilities(User sdncModifierDetails, + ComponentReqDetails componentReqDetails) throws IOException { + Config config = Utils.getConfig(); + ComponentTypeEnum componentType = null; + if (componentReqDetails instanceof ResourceReqDetails) { + componentType = ComponentTypeEnum.RESOURCE; + } else if (componentReqDetails instanceof ServiceReqDetails) { + componentType = ComponentTypeEnum.SERVICE; + } else if (componentReqDetails instanceof ProductReqDetails) { + componentType = ComponentTypeEnum.PRODUCT; + } + String url = String.format(Urls.GET_COMPONENT_REQUIRMENTS_CAPABILITIES, config.getCatalogBeHost(), + config.getCatalogBePort(), ComponentTypeEnum.findParamByType(componentType), + componentReqDetails.getUniqueId()); + return sendGet(url, sdncModifierDetails.getUserId()); + } + + public static CapReqDef getAndParseComponentRequirmentsCapabilities(User user, ComponentReqDetails componentDetails) + throws IOException { + RestResponse getComponentReqCap = getComponentRequirmentsCapabilities(user, componentDetails); + ResourceRestUtils.checkSuccess(getComponentReqCap); + CapReqDef capReqDef = ResponseParser.parseToObject(getComponentReqCap.getResponse(), CapReqDef.class); + return capReqDef; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ConsumerRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ConsumerRestUtils.java new file mode 100644 index 0000000000..71735d5a4a --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ConsumerRestUtils.java @@ -0,0 +1,245 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import static org.testng.AssertJUnit.assertEquals; + +import java.util.Map; + +import org.codehaus.jackson.map.ObjectMapper; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; + +import com.google.gson.Gson; + +public class ConsumerRestUtils extends BaseRestUtils { + + public static final int STATUS_CODE_SUCCESS = 200; + public static final int STATUS_CODE_CREATED = 201; + public static final int STATUS_CODE_DELETE = 204; + public static final int STATUS_CODE_NOT_FOUND = 404; + Utils utils = new Utils(); + private static Long expectedsLastupdatedtime; + private static Long expectedLastAuthenticationTime; + + public static RestResponse createConsumer(ConsumerDataDefinition consumerDataDefinition, User sdncModifierDetails) + throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_CONSUMER, config.getCatalogBeHost(), config.getCatalogBePort()); + + String userId = sdncModifierDetails.getUserId(); + + Map headersMap = prepareHeadersMap(userId); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(consumerDataDefinition); + + HttpRequest http = new HttpRequest(); + // System.out.println(url); + // System.out.println(userBodyJson); + RestResponse createConsumerResponse = http.httpSendPost(url, userBodyJson, headersMap); + if (createConsumerResponse.getErrorCode() == STATUS_CODE_CREATED) { + ConsumerDataDefinition getConsumerDataObject = parseComsumerResp(createConsumerResponse); + consumerDataDefinition + .setConsumerDetailsLastupdatedtime(getConsumerDataObject.getConsumerDetailsLastupdatedtime()); + consumerDataDefinition + .setConsumerLastAuthenticationTime(getConsumerDataObject.getConsumerLastAuthenticationTime()); + consumerDataDefinition.setLastModfierAtuid(getConsumerDataObject.getLastModfierAtuid()); + } + return createConsumerResponse; + } + + public static RestResponse createConsumerHttpCspAtuUidIsMissing(ConsumerDataDefinition consumerDataDefinition, + User sdncModifierDetails) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_CONSUMER, config.getCatalogBeHost(), config.getCatalogBePort()); + + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + headersMap.remove("USER_ID"); + Gson gson = new Gson(); + String userBodyJson = gson.toJson(consumerDataDefinition); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + // System.out.println(userBodyJson); + RestResponse createConsumerResponse = http.httpSendPost(url, userBodyJson, headersMap); + if (createConsumerResponse.getErrorCode() == STATUS_CODE_CREATED) { + ConsumerDataDefinition getConsumerDataObject = parseComsumerResp(createConsumerResponse); + consumerDataDefinition + .setConsumerDetailsLastupdatedtime(getConsumerDataObject.getConsumerDetailsLastupdatedtime()); + consumerDataDefinition + .setConsumerLastAuthenticationTime(getConsumerDataObject.getConsumerLastAuthenticationTime()); + consumerDataDefinition.setLastModfierAtuid(getConsumerDataObject.getLastModfierAtuid()); + } + return createConsumerResponse; + } + + public static RestResponse deleteConsumerHttpCspAtuUidIsMissing(ConsumerDataDefinition consumerDataDefinition, + User sdncModifierDetails) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_CONSUMER, config.getCatalogBeHost(), config.getCatalogBePort(), + consumerDataDefinition.getConsumerName()); + + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + headersMap.remove("USER_ID"); + Gson gson = new Gson(); + String userBodyJson = gson.toJson(consumerDataDefinition); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + // System.out.println(userBodyJson); + RestResponse deleteConsumerResponse = http.httpSendDelete(url, headersMap); + return deleteConsumerResponse; + } + + public static ConsumerDataDefinition parseComsumerResp(RestResponse restResponse) throws Exception { + + String bodyToParse = restResponse.getResponse(); + ObjectMapper mapper = new ObjectMapper(); + try { + ConsumerDataDefinition component = mapper.readValue(bodyToParse, ConsumerDataDefinition.class); + return component; + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + public static RestResponse deleteConsumer(ConsumerDataDefinition consumerDataDefinition, User sdncModifierDetails) + throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_CONSUMER, config.getCatalogBeHost(), config.getCatalogBePort(), + consumerDataDefinition.getConsumerName()); + + String userId = sdncModifierDetails.getUserId(); + + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + RestResponse deleteConsumerResponse = http.httpSendDelete(url, headersMap); + return deleteConsumerResponse; + } + + public static RestResponse getConsumer(ConsumerDataDefinition consumerDataDefinition, User sdncModifierDetails) + throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_CONSUMER, config.getCatalogBeHost(), config.getCatalogBePort(), + consumerDataDefinition.getConsumerName()); + + String userId = sdncModifierDetails.getUserId(); + + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + RestResponse getConsumerResponse = http.httpSendGet(url, headersMap); + return getConsumerResponse; + } + + public static void validateConsumerReqVsResp(ConsumerDataDefinition consumerDefinition, + ConsumerDataDefinition getConsumerDataObject) { + + String expected; + + expected = consumerDefinition.getConsumerName(); + assertEquals("consumer name - ", expected, getConsumerDataObject.getConsumerName()); + + expected = consumerDefinition.getConsumerPassword().toLowerCase(); + assertEquals("consumer password - ", expected, getConsumerDataObject.getConsumerPassword()); + + expected = consumerDefinition.getLastModfierAtuid(); + assertEquals("consumer Last Modfier Atuid - ", expected, getConsumerDataObject.getLastModfierAtuid()); + + expected = consumerDefinition.getConsumerSalt(); + assertEquals("consumer Salt - ", expected, getConsumerDataObject.getConsumerSalt()); + + expectedsLastupdatedtime = consumerDefinition.getConsumerDetailsLastupdatedtime(); + assertEquals("consumer Last updated time - ", expectedsLastupdatedtime, + getConsumerDataObject.getConsumerDetailsLastupdatedtime()); + + expectedLastAuthenticationTime = consumerDefinition.getConsumerLastAuthenticationTime(); + assertEquals("consumer Last authentication time - ", expectedLastAuthenticationTime, + getConsumerDataObject.getConsumerLastAuthenticationTime()); + } + + ///// New + public enum EcompConsumerAuditJsonKeysEnum { + ACTION("ACTION"), MODIFIER("MODIFIER"), ECOMP_USER("ECOMP_USER"), STATUS("STATUS"), DESC("DESCRIPTION"); + private String auditJsonKeyName; + + private EcompConsumerAuditJsonKeysEnum(String auditJsonKeyName) { + this.auditJsonKeyName = auditJsonKeyName; + } + + public String getAuditJsonKeyName() { + return auditJsonKeyName.toLowerCase(); + } + } + + /* + * protected void resourceArtifatAuditSuccess(String action, + * ArtifactReqDetails artifact, ResourceReqDetails resourceDetails , User + * user) throws Exception { ExpectedResourceAuditJavaObject + * expectedResourceAuditJavaObject = + * Convertor.constructFieldsForAuditValidation(resourceDetails, + * resourceDetails.getVersion(), user); String auditAction = action; + * expectedResourceAuditJavaObject.setAction(auditAction); + * expectedResourceAuditJavaObject.setPrevState(""); + * expectedResourceAuditJavaObject.setPrevVersion(""); + * expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum. + * NOT_CERTIFIED_CHECKOUT).toString()); + * expectedResourceAuditJavaObject.setStatus("200"); + * expectedResourceAuditJavaObject.setDesc("OK"); + * expectedResourceAuditJavaObject.setArtifactName(artifact.getArtifactName( + * )); AuditUtils.validateAudit(expectedResourceAuditJavaObject, + * auditAction, null); } + */ + + /* + * protected void resourceArtifatValidateAuditWithErrorMessage(String + * actionStatus, ResourceReqDetails resourceDetails, String auditAction, + * String setCurrState, Object ... variables)throws Exception { ErrorInfo + * errorInfo = utils.parseYaml(actionStatus); + * ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = + * Convertor.constructFieldsForAuditValidation(resourceDetails, + * resourceDetails.getVersion(), sdncUserDetails); + * expectedResourceAuditJavaObject.setAction(auditAction); + * expectedResourceAuditJavaObject.setPrevState(""); + * expectedResourceAuditJavaObject.setPrevVersion(""); + * expectedResourceAuditJavaObject.setCurrState(setCurrState); + * expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()) + * ; + * expectedResourceAuditJavaObject.setDesc(errorInfo.getAuditDesc(variables) + * ); expectedResourceAuditJavaObject.setArtifactName(""); + * AuditUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, + * null); } + */ +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/EcompUserRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/EcompUserRestUtils.java new file mode 100644 index 0000000000..458aa4a91c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/EcompUserRestUtils.java @@ -0,0 +1,253 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.portalsdk.core.restful.domain.EcompRole; +import org.openecomp.portalsdk.core.restful.domain.EcompUser; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.run.StartTest; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +public class EcompUserRestUtils extends BaseRestUtils { + + static Gson gson = new Gson(); + + static Logger logger = LoggerFactory.getLogger(EcompUserRestUtils.class.getName()); + static String contentTypeHeaderData = "application/json"; + static String acceptHeaderDate = "application/json"; + static String ecompUsername = "12345"; + static String ecompPassword = "12345"; + + public EcompUserRestUtils() { + super(); + + StartTest.enableLogger(); + } + + public static RestResponse pushUser(EcompUser ecompUser) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.ECOMP_USERNAME.getValue(), ecompUsername); + headersMap.put(HttpHeaderEnum.ECOMP_PASSWORD.getValue(), ecompPassword); + + String userBodyJson = gson.toJson(ecompUser); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.ECOMP_PUSH_USER, config.getCatalogBeHost(), config.getCatalogBePort()); + + logger.debug("Send POST request to create user: {}", url); + logger.debug("User body: {}", userBodyJson); + logger.debug("User headers: {}", headersMap); + + RestResponse sendPushUserResponse = http.httpSendPost(url, userBodyJson, headersMap); + + return sendPushUserResponse; + } + + /* + * loginId - equals to userId + */ + public static RestResponse editUser(String loginId, EcompUser ecompUser) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.ECOMP_USERNAME.getValue(), ecompUsername); + headersMap.put(HttpHeaderEnum.ECOMP_PASSWORD.getValue(), ecompPassword); + + String userBodyJson = gson.toJson(ecompUser); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.ECOMP_EDIT_USER, config.getCatalogBeHost(), config.getCatalogBePort(), loginId); + + logger.debug("Send POST request to edit user: {}", url); + logger.debug("User body: {}", userBodyJson); + logger.debug("User headers: {}", headersMap); + + RestResponse sendEditUserResponse = http.httpSendPost(url, userBodyJson, headersMap); + + return sendEditUserResponse; + } + + /* + * loginId - equals to userId + */ + public static RestResponse getUser(String loginId) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.ECOMP_USERNAME.getValue(), ecompUsername); + headersMap.put(HttpHeaderEnum.ECOMP_PASSWORD.getValue(), ecompPassword); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.ECOMP_GET_USER, config.getCatalogBeHost(), config.getCatalogBePort(), loginId); + + logger.debug("Send GET request to get user: {}", url); + logger.debug("User headers: {}", headersMap); + + RestResponse sendGetUserRequest = http.httpSendGet(url, headersMap); + + return sendGetUserRequest; + } + + public static RestResponse getAllUsers() throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.ECOMP_USERNAME.getValue(), ecompUsername); + headersMap.put(HttpHeaderEnum.ECOMP_PASSWORD.getValue(), ecompPassword); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.ECOMP_GET_ALL_USERS, config.getCatalogBeHost(), config.getCatalogBePort()); + + logger.debug("Send POST request to get all users: {}", url); + logger.debug("User headers: {}", headersMap); + + RestResponse sendGetAllUsersRequest = http.httpSendGet(url, headersMap); + + return sendGetAllUsersRequest; + } + + public static RestResponse getAllAvailableRoles() throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.ECOMP_USERNAME.getValue(), ecompUsername); + headersMap.put(HttpHeaderEnum.ECOMP_PASSWORD.getValue(), ecompPassword); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.ECOMP_GET_ALL_AVAILABLE_ROLES, config.getCatalogBeHost(), + config.getCatalogBePort()); + + logger.debug("Send GET request to get all available roles: {}", url); + logger.debug("User headers: {}", headersMap); + + RestResponse sendUpdateUserRequest = http.httpSendGet(url, headersMap); + + return sendUpdateUserRequest; + } + + /* + * loginId - equals to userId + */ + public static RestResponse pushUserRoles(String loginId, List roles) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.ECOMP_USERNAME.getValue(), ecompUsername); + headersMap.put(HttpHeaderEnum.ECOMP_PASSWORD.getValue(), ecompPassword); + + String roleBodyJson = gson.toJson(roles); + if(roleBodyJson.equals("[{}]")) { + roleBodyJson = "[]"; + } + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.ECOMP_PUSH_USER_ROLES, config.getCatalogBeHost(), config.getCatalogBePort(), + loginId); + + logger.debug("Send POST request to push user role: {}", url); + logger.debug("Roles body: {}", roleBodyJson); + logger.debug("Request headers: {}", headersMap); + + RestResponse sendpushUserRolesResponse = http.httpSendPost(url, roleBodyJson, headersMap); + + return sendpushUserRolesResponse; + } + + /* + * loginId - equals to userId + */ + public static RestResponse getUserRoles(String loginId) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.ECOMP_USERNAME.getValue(), ecompUsername); + headersMap.put(HttpHeaderEnum.ECOMP_PASSWORD.getValue(), ecompPassword); + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.ECOMP_GET_USER_ROLES, config.getCatalogBeHost(), config.getCatalogBePort(), + loginId); + + logger.debug("Send GET request to get user roles: {}", url); + logger.debug("User headers: {}", headersMap); + + RestResponse sendGetUserRolesRequest = http.httpSendGet(url, headersMap); + + return sendGetUserRolesRequest; + } + + // TODO !!!!!!!!!!!!!! + /* + * Ask Eli if implementation of users is needed DELETE ECOMP USER + */ + + /* + * public static void main(String[] args) { EcompUser ecompUser = new + * EcompUser(); ecompUser.setFirstName("Test"); + * ecompUser.setLastName("Testovich"); + * ecompUser.setActive(true); + * + * EcompRole roleToUpdate = new EcompRole(); roleToUpdate.setId(new + * Long(6)); roleToUpdate.setName("PRODUCT_STRATEGIST"); List + * listOfRoles = new LinkedList<>(); listOfRoles.add(roleToUpdate); + * + * try { + * System.out.println("\n-----------------------------\n Testing pushUser"); + * System.out.println(pushUser(ecompUser)); + * System.out.println("\n-----------------------------\n Testing editUser"); + * System.out.println("\n-----------------------------\n Testing getUser"); + * // System.out.println(getUser(ecompUser.getLoginId())); System.out. + * println("\n-----------------------------\n Testing getAllUsers"); // + * System.out.println(getAllUsers()); System.out. + * println("\n-----------------------------\n Testing getAllAvailableRoles" + * ); // System.out.println(getAllAvailableRoles().toString()); System.out. + * println("\n-----------------------------\n Testing pushUserRoles"); + * TODO Auto-generated catch block e.printStackTrace(); } } + */ +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/GroupRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/GroupRestUtils.java new file mode 100644 index 0000000000..d79c8e002c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/GroupRestUtils.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; + +import com.google.gson.Gson; + +public class GroupRestUtils extends BaseRestUtils { + public static String acceptHeaderDate = "application/json"; + static Config config = Config.instance(); + public static Gson gson = new Gson(); + + public static RestResponse getGroupById(Component component, String groupId, User user) throws IOException { + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderData); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), user.getUserId()); + + String url = String.format(Urls.GET_GROUP_BY_ID, config.getCatalogBeHost(), config.getCatalogBePort(), + ComponentTypeEnum.findParamByType(component.getComponentType()), component.getUniqueId(), groupId); + + RestResponse sendGetServerRequest = sendGet(url, user.getUserId(), headersMap); + + return sendGetServerRequest; + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ImportRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ImportRestUtils.java new file mode 100644 index 0000000000..951831c39d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ImportRestUtils.java @@ -0,0 +1,408 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.entity.mime.content.StringBody; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.codehaus.jettison.json.JSONException; +import org.openecomp.sdc.be.dao.rest.HttpRestClient; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.ImportTestTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.rest.api.RestResponseAsByteArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ImportRestUtils extends BaseRestUtils { + + private static Logger log = LoggerFactory.getLogger(ImportRestUtils.class.getName()); + private static Properties downloadCsarHeaders = new Properties(); + + static { + downloadCsarHeaders.put("Accept", "application/octet-stream"); + } + + @SuppressWarnings("unused") + private static Integer importNormativeResource(NormativeTypesEnum resource, UserRoleEnum userRole) + throws IOException { + Config config = Utils.getConfig(); + CloseableHttpResponse response = null; + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + + mpBuilder.addPart("resourceZip", new FileBody(getTestZipFile(resource.getFolderName()))); + mpBuilder.addPart("resourceMetadata", + new StringBody(getTestJsonStringOfFile(resource.getFolderName(), resource.getFolderName() + ".json"), + ContentType.APPLICATION_JSON)); + + String url = String.format(Urls.IMPORT_RESOURCE_NORMATIVE, config.getCatalogBeHost(), + config.getCatalogBePort()); + + CloseableHttpClient client = HttpClients.createDefault(); + try { + HttpPost httpPost = new HttpPost(url); + httpPost.addHeader("USER_ID", userRole.getUserId()); + httpPost.setEntity(mpBuilder.build()); + response = client.execute(httpPost); + return response.getStatusLine().getStatusCode(); + } finally { + closeResponse(response); + closeHttpClient(client); + + } + } + + /* + * public static RestResponse importResourceByName(String resourceName, User + * user) throws IOException { Config config = Utils.getConfig(); + * CloseableHttpResponse response = null; MultipartEntityBuilder mpBuilder = + * MultipartEntityBuilder.create(); + * + * mpBuilder.addPart("resourceZip", new + * FileBody(getTestZipFile(resourceName))); + * mpBuilder.addPart("resourceMetadata", new + * StringBody(getTestJsonStringOfFile(resourceName, resourceName + ".json"), + * ContentType.APPLICATION_JSON)); + * + * String url = String.format(Urls.IMPORT_RESOURCE_NORMATIVE, + * config.getCatalogBeHost(), config.getCatalogBePort()); + * + * CloseableHttpClient client = HttpClients.createDefault(); try { HttpPost + * httpPost = new HttpPost(url); RestResponse restResponse = new + * RestResponse(); httpPost.addHeader("USER_ID", user.getUserId()); + * httpPost.setEntity(mpBuilder.build()); response = + * client.execute(httpPost); HttpEntity entity = response.getEntity(); + * String responseBody = null; if (entity != null) { InputStream instream = + * entity.getContent(); StringWriter writer = new StringWriter(); + * IOUtils.copy(instream, writer); responseBody = writer.toString(); try { + * + * } finally { instream.close(); } } + * + * restResponse.setErrorCode(response.getStatusLine().getStatusCode()); + * restResponse.setResponse(responseBody); if (restResponse.getErrorCode() + * == STATUS_CODE_CREATED ){ + * + * } + * + * return restResponse; + * + * } finally { closeResponse(response); closeHttpClient(client); + * + * } + * + * } + */ + + public static RestResponse importResourceByName(ResourceReqDetails resourceDetails, User importer) + throws Exception { + Config config = Utils.getConfig(); + CloseableHttpResponse response = null; + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + + mpBuilder.addPart("resourceZip", new FileBody(getTestZipFile(resourceDetails.getName()))); + mpBuilder.addPart("resourceMetadata", + new StringBody(getTestJsonStringOfFile(resourceDetails.getName(), resourceDetails.getName() + ".json"), + ContentType.APPLICATION_JSON)); + + String url = String.format(Urls.IMPORT_RESOURCE_NORMATIVE, config.getCatalogBeHost(), + config.getCatalogBePort()); + + CloseableHttpClient client = HttpClients.createDefault(); + try { + HttpPost httpPost = new HttpPost(url); + RestResponse restResponse = new RestResponse(); + httpPost.addHeader("USER_ID", importer.getUserId()); + httpPost.setEntity(mpBuilder.build()); + response = client.execute(httpPost); + HttpEntity entity = response.getEntity(); + String responseBody = null; + if (entity != null) { + InputStream instream = entity.getContent(); + StringWriter writer = new StringWriter(); + IOUtils.copy(instream, writer); + responseBody = writer.toString(); + try { + + } finally { + instream.close(); + } + } + + restResponse.setErrorCode(response.getStatusLine().getStatusCode()); + restResponse.setResponse(responseBody); + + if (restResponse.getErrorCode() == STATUS_CODE_CREATED) { + resourceDetails.setUUID(ResponseParser.getUuidFromResponse(restResponse)); + resourceDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(restResponse)); + resourceDetails.setVersion(ResponseParser.getVersionFromResponse(restResponse)); + resourceDetails.setCreatorUserId(importer.getUserId()); + resourceDetails.setCreatorFullName(importer.getFullName()); + } + + return restResponse; + + } finally { + closeResponse(response); + closeHttpClient(client); + + } + + } + + public static RestResponse importNewResourceByName(String resourceName, UserRoleEnum userRole) throws IOException { + Config config = Utils.getConfig(); + + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + + mpBuilder.addPart("resourceZip", new FileBody(getTestZipFile(resourceName))); + mpBuilder.addPart("resourceMetadata", new StringBody( + getTestJsonStringOfFile(resourceName, resourceName + ".json"), ContentType.APPLICATION_JSON)); + HttpEntity requestEntity = mpBuilder.build(); + String url = String.format(Urls.IMPORT_USER_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort()); + Map headers = new HashMap(); + headers.put("USER_ID", userRole.getUserId()); + + return HttpRequest.sendHttpPostWithEntity(requestEntity, url, headers); + } + + public static RestResponse importNormativeResourceByName(String resourceName, UserRoleEnum userRole) + throws IOException { + Config config = Utils.getConfig(); + + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + + mpBuilder.addPart("resourceZip", new FileBody(getTestZipFile(resourceName))); + mpBuilder.addPart("resourceMetadata", new StringBody( + getTestJsonStringOfFile(resourceName, resourceName + ".json"), ContentType.APPLICATION_JSON)); + HttpEntity requestEntity = mpBuilder.build(); + String url = String.format(Urls.IMPORT_RESOURCE_NORMATIVE, config.getCatalogBeHost(), + config.getCatalogBePort()); + Map headers = new HashMap(); + headers.put("USER_ID", userRole.getUserId()); + + return HttpRequest.sendHttpPostWithEntity(requestEntity, url, headers); + } + + public static RestResponse importTestResource(ImportTestTypesEnum resource, UserRoleEnum userRole) + throws IOException { + Config config = Utils.getConfig(); + CloseableHttpResponse response = null; + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + + mpBuilder.addPart("resourceZip", new FileBody(getTestZipFile(resource.getFolderName()))); + mpBuilder.addPart("resourceMetadata", + new StringBody(getTestJsonStringOfFile(resource.getFolderName(), resource.getFolderName() + ".json"), + ContentType.APPLICATION_JSON)); + + String url = String.format(Urls.IMPORT_RESOURCE_NORMATIVE, config.getCatalogBeHost(), + config.getCatalogBePort()); + + CloseableHttpClient client = HttpClients.createDefault(); + try { + HttpPost httpPost = new HttpPost(url); + RestResponse restResponse = new RestResponse(); + httpPost.addHeader("USER_ID", UserRoleEnum.ADMIN.getUserId()); + httpPost.setEntity(mpBuilder.build()); + response = client.execute(httpPost); + HttpEntity entity = response.getEntity(); + String responseBody = null; + if (entity != null) { + InputStream instream = entity.getContent(); + StringWriter writer = new StringWriter(); + IOUtils.copy(instream, writer); + responseBody = writer.toString(); + try { + + } finally { + instream.close(); + } + } + + restResponse.setErrorCode(response.getStatusLine().getStatusCode()); + // restResponse.setResponse(response.getEntity().toString()); + restResponse.setResponse(responseBody); + return restResponse; + } finally { + closeResponse(response); + closeHttpClient(client); + + } + } + + public static Boolean removeNormativeTypeResource(NormativeTypesEnum current) + throws FileNotFoundException, IOException, ClientProtocolException { + User user = new User(UserRoleEnum.ADMIN.getFirstName(), UserRoleEnum.ADMIN.getLastName(), + UserRoleEnum.ADMIN.getUserId(), null, null, null); + RestResponse deleteResponse = ResourceRestUtils.deleteResourceByNameAndVersion(user, current.getNormativeName(), + "1.0"); + if (deleteResponse.getErrorCode() == 200) { + return true; + } + return false; + } + + public static void validateImportTestTypesResp(ImportTestTypesEnum currResource, RestResponse restResponse) + throws IOException, JSONException { + + // assertTrue( status != ResourceUtils.STATUS_CODE_IMPORT_SUCCESS ); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(currResource.getActionStatus().name()); + + assertNotNull("check response object is not null after create service", restResponse); + assertNotNull("check error code exists in response after create service", restResponse.getErrorCode()); + assertEquals("Check response code after create service", errorInfo.getCode(), restResponse.getErrorCode()); + + // validate create service response vs actual + List variables = (currResource.getErrorParams() != null ? currResource.getErrorParams() + : new ArrayList()); + if (restResponse.getErrorCode() != 200) { + ErrorValidationUtils.checkBodyResponseOnError(currResource.getActionStatus().name(), variables, + restResponse.getResponse()); + } + } + + private static String getTestJsonStringOfFile(String folderName, String fileName) throws IOException { + // String sourceDir = "src/test/resources/CI/importResourceTests"; + Config config = Utils.getConfig(); + String sourceDir = config.getImportResourceTestsConfigDir(); + java.nio.file.Path filePath = FileSystems.getDefault().getPath(sourceDir + File.separator + folderName, + fileName); + byte[] fileContent = Files.readAllBytes(filePath); + String content = new String(fileContent); + return content; + } + + private static File getTestZipFile(String elementName) throws IOException { + Config config = Utils.getConfig(); + String sourceDir = config.getImportResourceTestsConfigDir(); + java.nio.file.Path filePath = FileSystems.getDefault().getPath(sourceDir + File.separator + elementName, + "normative-types-new-" + elementName + ".zip"); + return filePath.toFile(); + } + + private static void closeHttpClient(CloseableHttpClient client) { + try { + if (client != null) { + client.close(); + } + } catch (IOException e) { + log.debug("failed to close client or response: ", e); + } + } + + private static void closeResponse(CloseableHttpResponse response) { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + log.debug("failed to close client or response: {}", e); + } + } + + public static RestResponseAsByteArray getCsar(String csarUid, User sdncModifierDetails) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_CSAR_USING_SIMULATOR, config.getCatalogBeHost(), config.getCatalogBePort(), + csarUid); + + String userId = sdncModifierDetails.getUserId(); + + Map headersMap = prepareHeadersMap(userId); + + // Gson gson = new Gson(); + // String userBodyJson = gson.toJson(resourceDetails); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + // System.out.println(userBodyJson); + + HttpRestClient httpRestClient = new HttpRestClient(); + + for (Map.Entry mapEntry : headersMap.entrySet()) { + + downloadCsarHeaders.put(mapEntry.getKey(), mapEntry.getValue()); + } + RestResponseAsByteArray doGetAsByteArray = httpRestClient.doGetAsByteArray(url, downloadCsarHeaders); + // RestResponse getCsar = http.httpSendGet(url, headersMap); + + return doGetAsByteArray; + + } + + private static File getGroupTypeZipFile(String elementName) throws IOException { + Config config = Utils.getConfig(); + String sourceDir = config.getImportResourceTestsConfigDir(); + sourceDir += File.separator + ".." + File.separator + "importTypesTest" + File.separator; + java.nio.file.Path filePath = FileSystems.getDefault().getPath(sourceDir + File.separator + elementName, + elementName + ".zip"); + return filePath.toFile(); + } + + public static RestResponse importNewGroupTypeByName(String groupTypeName, UserRoleEnum userRole) + throws IOException { + Config config = Utils.getConfig(); + + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + + mpBuilder.addPart("groupTypesZip", new FileBody(getGroupTypeZipFile(groupTypeName))); + HttpEntity requestEntity = mpBuilder.build(); + String url = String.format(Urls.IMPORT_GROUP_TYPE, config.getCatalogBeHost(), config.getCatalogBePort()); + Map headers = new HashMap(); + headers.put("USER_ID", userRole.getUserId()); + + return HttpRequest.sendHttpPostWithEntity(requestEntity, url, headers); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/InputsRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/InputsRestUtils.java new file mode 100644 index 0000000000..de7be077d1 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/InputsRestUtils.java @@ -0,0 +1,122 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstInputsMap; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +/** + * RestUtils for inputs + * + * @author il0695 + * + */ +public class InputsRestUtils extends BaseRestUtils { + + @SuppressWarnings("unused") + private static Logger logger = LoggerFactory.getLogger(InputsRestUtils.class.getName()); + + /** + * Add inputs to service + * + * @param component + * @param inputs + * @param userRole + * @return {@link org.openecomp.sdc.ci.tests.datatypes.http.RestResponse} + * @throws Exception + */ + public static RestResponse addInput(Component component, ComponentInstInputsMap inputs, UserRoleEnum userRole) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.ADD_INPUTS, config.getCatalogBeHost(), config.getCatalogBePort(), ComponentTypeEnum.findParamByType(component.getComponentType()), component.getUniqueId()); + String json = new Gson().toJson(inputs); + return sendPost(url, json, userRole.getUserId(), acceptHeaderData); + } + + /** + * Get all Component inputs + * + * @param component + * @return {@link org.openecomp.sdc.ci.tests.datatypes.http.RestResponse} + * @throws Exception + */ + public static RestResponse getComponentInputs(Component component) throws Exception { + Config config = Utils.getConfig(); + //services/{componentId}/inputs + String url = String.format(Urls.GET_COMPONENT_INPUTS, config.getCatalogBeHost(), config.getCatalogBePort(), component.getUniqueId()); + return sendGet(url, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + } + + /** + * Get all inputs of component instance + * + * @param parentComponent + * @param componentInstance + * @return {@link org.openecomp.sdc.ci.tests.datatypes.http.RestResponse} + * @throws Exception + */ + public static RestResponse getComponentInstanceInputs(Component parentComponent, ComponentInstance componentInstance) throws Exception { + Config config = Utils.getConfig(); + //{componentType}/{componentId}/componentInstances/{instanceId}/{originComonentUid}/inputs + String url = String.format(Urls.GET_COMPONENT_INSTANCE_INPUTS, config.getCatalogBeHost(), config.getCatalogBePort(), ComponentTypeEnum.findParamByType(parentComponent.getComponentType()), parentComponent.getUniqueId(), componentInstance.getUniqueId(), componentInstance.getComponentUid()); + return sendGet(url, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + } + + /** + * Delete input from component + * + * @param parentComponent + * @param inputId + * @return {@link org.openecomp.sdc.ci.tests.datatypes.http.RestResponse} + * @throws Exception + */ + public static RestResponse deleteInputFromComponent(Component parentComponent, String inputId) throws Exception { + return deleteInputFromComponent(ComponentTypeEnum.findParamByType(parentComponent.getComponentType()), parentComponent.getUniqueId(), inputId); + } + + /** + * Delete input from component + * + * @param componentType + * @param componentId + * @param inputUniqueId + * @return {@link org.openecomp.sdc.ci.tests.datatypes.http.RestResponse} + * @throws Exception + */ + public static RestResponse deleteInputFromComponent(String componentType, String componentId, String inputUniqueId) throws Exception { + Config config = Utils.getConfig(); + //{componentType}/{componentId}/delete/{inputId}/input + String url = String.format(Urls.DELETE_INPUT_BY_ID, config.getCatalogBeHost(), config.getCatalogBePort(), componentType, componentId, inputUniqueId); + return sendDelete(url, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/LifecycleRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/LifecycleRestUtils.java new file mode 100644 index 0000000000..d53d2da91b --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/LifecycleRestUtils.java @@ -0,0 +1,451 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.json.simple.JSONObject; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LifecycleRestUtils extends BaseRestUtils { + private static Logger logger = LoggerFactory.getLogger(LifecycleRestUtils.class.getName()); + public static final String COMMENT = "comment"; + + // External APIs + public static RestResponse checkInResource(String resourceUUID, User sdncModifierDetails) throws IOException { + String comment = "Chekin resource: " + resourceUUID; + return changeLifeCycleOfAsset(resourceUUID, AssetTypeEnum.RESOURCES, LifeCycleStatesEnum.CHECKIN, sdncModifierDetails, comment); + } + + public static RestResponse checkInService(String serviceUUID, User sdncModifierDetails) throws IOException { + String comment = "Chekin service: " + serviceUUID; + return changeLifeCycleOfAsset(serviceUUID, AssetTypeEnum.SERVICES, LifeCycleStatesEnum.CHECKIN, sdncModifierDetails, comment); + } + + public static RestResponse checkOutResource(String resourceUUID, User sdncModifierDetails) throws IOException { + String comment = "CheckOut resource: " + resourceUUID; + return changeLifeCycleOfAsset(resourceUUID, AssetTypeEnum.RESOURCES, LifeCycleStatesEnum.CHECKOUT, sdncModifierDetails, comment); + } + + public static RestResponse checkOutService(String serviceUUID, User sdncModifierDetails) throws IOException { + String comment = "CheckOut service: " + serviceUUID; + return changeLifeCycleOfAsset(serviceUUID, AssetTypeEnum.SERVICES, LifeCycleStatesEnum.CHECKOUT, sdncModifierDetails, comment); + } + + public static RestResponse certificationRequestService(String serviceUUID, User sdncModifierDetails) throws IOException { + String comment = "Certification request service: " + serviceUUID; + return changeLifeCycleOfAsset(serviceUUID, AssetTypeEnum.SERVICES, LifeCycleStatesEnum.CERTIFICATIONREQUEST, sdncModifierDetails, comment); + } + + public static RestResponse certificationRequestResource(String resourceUUID, User sdncModifierDetails) throws IOException { + String comment = "Certification request resource: " + resourceUUID; + return changeLifeCycleOfAsset(resourceUUID, AssetTypeEnum.RESOURCES, LifeCycleStatesEnum.CERTIFICATIONREQUEST, sdncModifierDetails, comment); + } + + public static RestResponse startTestingService(String serviceUUID, User sdncModifierDetails) throws IOException { + String comment = "Start testing request service: " + serviceUUID; + return changeLifeCycleOfAsset(serviceUUID, AssetTypeEnum.SERVICES, LifeCycleStatesEnum.STARTCERTIFICATION, sdncModifierDetails, comment); + } + + public static RestResponse startTestingResource(String resourceUUID, User sdncModifierDetails) throws IOException { + String comment = "Start testing request resource: " + resourceUUID; + return changeLifeCycleOfAsset(resourceUUID, AssetTypeEnum.RESOURCES, LifeCycleStatesEnum.STARTCERTIFICATION, sdncModifierDetails, comment); + } + + public static RestResponse certifyService(String serviceUUID, User sdncModifierDetails) throws IOException { + String comment = "Certify request service: " + serviceUUID; + return changeLifeCycleOfAsset(serviceUUID, AssetTypeEnum.SERVICES, LifeCycleStatesEnum.CERTIFY, sdncModifierDetails, comment); + } + + public static RestResponse certifyResource(String resourceUUID, User sdncModifierDetails) throws IOException { + String comment = "Certify request resource: " + resourceUUID; + return changeLifeCycleOfAsset(resourceUUID, AssetTypeEnum.RESOURCES, LifeCycleStatesEnum.CERTIFY, sdncModifierDetails, comment); + } + + + + + + private static RestResponse changeLifeCycleOfAsset(String assetUUID, AssetTypeEnum assetTypeEnum, LifeCycleStatesEnum lifeCycleStatesEnum, User sdncModifierDetails, String comment) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.POST_EXTERNAL_API_CHANGE_LIFE_CYCLE_OF_ASSET, config.getCatalogBeHost(), config.getCatalogBePort(), assetTypeEnum.getValue(), assetUUID, lifeCycleStatesEnum.getState()); + + Map additionalHeaders = new HashMap(); + + additionalHeaders.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + additionalHeaders.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + String jsonBody = "{\"userRemarks\": \"" + comment + "\"}"; + + RestResponse res = sendPost(url, jsonBody, sdncModifierDetails.getUserId(), acceptHeaderData, additionalHeaders); + + return res; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public static RestResponse changeResourceState(ResourceReqDetails resourceDetails, User sdncModifierDetails, + String version, LifeCycleStatesEnum LifeCycleStatesEnum) throws IOException { + return changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum, + createLifecycleCommentJson(COMMENT)); + } + + public static RestResponse changeResourceState(ResourceReqDetails resourceDetails, User sdncModifierDetails, + String version, LifeCycleStatesEnum LifeCycleStatesEnum, String LifecycleChangeInfo) throws IOException { + + return changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum, LifecycleChangeInfo); + + } + + public static RestResponse changeResourceState(ResourceReqDetails resourceDetails, User sdncModifierDetails, + LifeCycleStatesEnum LifeCycleStatesEnum) throws IOException { + + return changeResourceState(resourceDetails, sdncModifierDetails, LifeCycleStatesEnum, + createLifecycleCommentJson(COMMENT)); + + } + + public static RestResponse changeResourceState(ResourceReqDetails resourceDetails, String modifierUserId, + LifeCycleStatesEnum LifeCycleStatesEnum) throws IOException { + User user = new User(); + user.setUserId(modifierUserId); + return changeResourceState(resourceDetails, user, LifeCycleStatesEnum, createLifecycleCommentJson(COMMENT)); + } + + private static RestResponse changeResourceState(ResourceReqDetails resourceDetails, User sdncModifierDetails, + LifeCycleStatesEnum LifeCycleStatesEnum, String LifecycleChangeInfo) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.CHANGE_RESOURCE_LIFECYCLE_STATE, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetails.getUniqueId(), LifeCycleStatesEnum); + // System.out.println("url: " + url); + + RestResponse LifeCycleStatesEnumResourceResponse = sendPost(url, LifecycleChangeInfo, + sdncModifierDetails.getUserId(), acceptHeaderData); + if (LifeCycleStatesEnumResourceResponse.getErrorCode() == STATUS_CODE_SUCCESS) { + String stateFromJsonResponse = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumResourceResponse.getResponse(), "lifecycleState"); + resourceDetails.setVersion(ResponseParser.getVersionFromResponse(LifeCycleStatesEnumResourceResponse)); + resourceDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(LifeCycleStatesEnumResourceResponse)); + if (stateFromJsonResponse != null) { + resourceDetails.setLifecycleState(LifecycleStateEnum.valueOf(stateFromJsonResponse)); + } + } + return LifeCycleStatesEnumResourceResponse; + } + + public static RestResponse changeServiceState(ServiceReqDetails serviceDetails, User sdncModifierDetails, + String version, LifeCycleStatesEnum LifeCycleStatesEnum) throws Exception { + { + return changeServiceState(serviceDetails, sdncModifierDetails, version, LifeCycleStatesEnum, + createLifecycleCommentJson(COMMENT)); + } + } + + public static RestResponse changeServiceState(ServiceReqDetails serviceDetails, User sdncModifierDetails, + LifeCycleStatesEnum LifeCycleStatesEnum) throws Exception { + { + return changeServiceState(serviceDetails, sdncModifierDetails, null, LifeCycleStatesEnum, + createLifecycleCommentJson(COMMENT)); + } + } + + public static RestResponse changeServiceState(ServiceReqDetails serviceDetails, User sdncModifierDetails, + LifeCycleStatesEnum LifeCycleStatesEnum, String lifecycleChangeInfo) throws Exception { + { + return changeServiceState(serviceDetails, sdncModifierDetails, null, LifeCycleStatesEnum, + lifecycleChangeInfo); + } + } + + public static RestResponse changeServiceState(ServiceReqDetails serviceDetails, User sdncModifierDetails, + String version, LifeCycleStatesEnum LifeCycleStatesEnum, String lifecycleChangeInfo) throws Exception { + + Config config = Utils.getConfig(); + Map headersMap = prepareHeadersMap(sdncModifierDetails); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.CHANGE_SERVICE_LIFECYCLE_STATE, config.getCatalogBeHost(), + config.getCatalogBePort(), serviceDetails.getUniqueId(), LifeCycleStatesEnum); + // System.out.println("url: " + url); + RestResponse LifeCycleStatesEnumServiceResponse = http.httpSendPost(url, lifecycleChangeInfo, headersMap); + if (LifeCycleStatesEnumServiceResponse.getErrorCode() == STATUS_CODE_SUCCESS) { + String serviceUniqueId = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumServiceResponse.getResponse(), "uniqueId"); + serviceDetails.setUniqueId(serviceUniqueId); + String serviceVersion = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumServiceResponse.getResponse(), "version"); + serviceDetails.setVersion(serviceVersion); + String stateFromJsonResponse = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumServiceResponse.getResponse(), "lifecycleState"); + serviceDetails.setLifecycleState(LifecycleStateEnum.valueOf(stateFromJsonResponse)); + } + return LifeCycleStatesEnumServiceResponse; + } + + public static RestResponse changeProductState(Product product, User sdncModifierDetails, + LifeCycleStatesEnum LifeCycleStatesEnum, String lifecycleChangeInfo) throws Exception { + { + return _changeProductState(product, sdncModifierDetails, LifeCycleStatesEnum, lifecycleChangeInfo); + } + } + + public static RestResponse changeProductState(Product product, User sdncModifierDetails, + LifeCycleStatesEnum LifeCycleStatesEnum) throws Exception { + { + return _changeProductState(product, sdncModifierDetails, LifeCycleStatesEnum, COMMENT); + } + } + + public static RestResponse changeProductState(ProductReqDetails productDetails, User sdncModifierDetails, + LifeCycleStatesEnum LifeCycleStatesEnum) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.CHANGE_PRODUCT_LIFECYCLE_STATE, config.getCatalogBeHost(), + config.getCatalogBePort(), productDetails.getUniqueId(), LifeCycleStatesEnum); + RestResponse LifeCycleStatesEnumServiceResponse = sendPost(url, createLifecycleCommentJson(COMMENT), + sdncModifierDetails.getUserId(), acceptHeaderData); + if (LifeCycleStatesEnumServiceResponse.getErrorCode() == STATUS_CODE_SUCCESS) { + String productUniqueId = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumServiceResponse.getResponse(), "uniqueId"); + productDetails.setUniqueId(productUniqueId); + String productVersion = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumServiceResponse.getResponse(), "version"); + productDetails.setVersion(productVersion); + String newLifecycleState = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumServiceResponse.getResponse(), "lifecycleState"); + productDetails.setLifecycleState(LifecycleStateEnum.valueOf(newLifecycleState)); + } + return LifeCycleStatesEnumServiceResponse; + + } + + public static RestResponse changeComponentState(Component component, User sdncModifierDetails, + LifeCycleStatesEnum LifeCycleStatesEnum) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.CHANGE_COMPONENT_LIFECYCLE_STATE, config.getCatalogBeHost(), + config.getCatalogBePort(), ComponentTypeEnum.findParamByType(component.getComponentType()), + component.getUniqueId(), LifeCycleStatesEnum); + RestResponse LifeCycleStatesEnumServiceResponse = sendPost(url, createLifecycleCommentJson(COMMENT), + sdncModifierDetails.getUserId(), acceptHeaderData); + if (LifeCycleStatesEnumServiceResponse.getErrorCode() == STATUS_CODE_SUCCESS) { + String productUniqueId = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumServiceResponse.getResponse(), "uniqueId"); + component.setUniqueId(productUniqueId); + String productVersion = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumServiceResponse.getResponse(), "version"); + component.setVersion(productVersion); + String newLifecycleState = ResponseParser + .getValueFromJsonResponse(LifeCycleStatesEnumServiceResponse.getResponse(), "lifecycleState"); + component.setLifecycleState(LifecycleStateEnum.valueOf(newLifecycleState)); + } + return LifeCycleStatesEnumServiceResponse; + + } + + public static RestResponse certifyResource(ResourceReqDetails resourceDetails) throws Exception { + RestResponse restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKIN); + // if (restResponseResource.getErrorCode() == 200){ + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + // }else + // return restResponseResource; + User testerDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + if (restResponseResource.getErrorCode() == 200) { + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, testerDetails, + LifeCycleStatesEnum.STARTCERTIFICATION); + } else + return restResponseResource; + if (restResponseResource.getErrorCode() == 200) { + restResponseResource = LifecycleRestUtils.changeResourceState(resourceDetails, testerDetails, + LifeCycleStatesEnum.CERTIFY); + if (restResponseResource.getErrorCode() == 200) { + String newVersion = ResponseParser.getVersionFromResponse(restResponseResource); + resourceDetails.setVersion(newVersion); + resourceDetails.setLifecycleState(LifecycleStateEnum.CERTIFIED); + resourceDetails.setLastUpdaterUserId(testerDetails.getUserId()); + resourceDetails.setLastUpdaterFullName(testerDetails.getFullName()); + String uniqueIdFromRresponse = ResponseParser.getUniqueIdFromResponse(restResponseResource); + resourceDetails.setUniqueId(uniqueIdFromRresponse); + } + } + return restResponseResource; + } + + public static RestResponse certifyService(ServiceReqDetails serviceDetails) throws Exception { + RestResponse restResponseService = LifecycleRestUtils.changeServiceState(serviceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKIN); + // if (restResponseService.getErrorCode() == 200){ + restResponseService = LifecycleRestUtils.changeServiceState(serviceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CERTIFICATIONREQUEST); + // }else + // return restResponseService; + if (restResponseService.getErrorCode() == 200) { + restResponseService = LifecycleRestUtils.changeServiceState(serviceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION); + } else + return restResponseService; + if (restResponseService.getErrorCode() == 200) { + User testerDetails = ElementFactory.getDefaultUser(UserRoleEnum.TESTER); + restResponseService = LifecycleRestUtils.changeServiceState(serviceDetails, testerDetails, + LifeCycleStatesEnum.CERTIFY); + if (restResponseService.getErrorCode() == 200) { + String newVersion = ResponseParser.getVersionFromResponse(restResponseService); + serviceDetails.setVersion(newVersion); + serviceDetails.setLifecycleState(LifecycleStateEnum.CERTIFIED); + serviceDetails.setLastUpdaterUserId(testerDetails.getUserId()); + serviceDetails.setLastUpdaterFullName(testerDetails.getFullName()); + String uniqueIdFromRresponse = ResponseParser.getUniqueIdFromResponse(restResponseService); + serviceDetails.setUniqueId(uniqueIdFromRresponse); + } + } + return restResponseService; + } + + private static RestResponse _changeProductState(Product product, User sdncModifierDetails, + LifeCycleStatesEnum LifeCycleStatesEnum, String lifecycleChangeInfo) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.CHANGE_PRODUCT_LIFECYCLE_STATE, config.getCatalogBeHost(), + config.getCatalogBePort(), product.getUniqueId(), LifeCycleStatesEnum); + RestResponse LifeCycleStatesEnumServiceResponse = sendPost(url, createLifecycleCommentJson(lifecycleChangeInfo), + sdncModifierDetails.getUserId(), acceptHeaderData); + + return LifeCycleStatesEnumServiceResponse; + } + + public static String createLifecycleCommentJson(String commentContent) { + String res = null; + if (commentContent != null) { + res = "{\"userRemarks\": \"" + commentContent + "\"}"; + } + return res; + } + + public static void checkLCS_Response(RestResponse response) { + checkStatusCode(response, "change lifecycle request failed", false, STATUS_CODE_SUCCESS); + } + + private static Map prepareHeadersMap(User sdncModifierDetails) { + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderData); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + return headersMap; + } + + public static RestResponse changeDistributionStatus(ServiceReqDetails serviceDetails, String version, User user, + String userRemarks, DistributionStatusEnum reqDistributionStatus) throws Exception { + String uniqueId = serviceDetails.getUniqueId(); + Config config = Utils.getConfig(); + String environmentName = "PROD-Andreys-Only"; +// String environmentName = ConfigurationManager.getConfigurationManager().getDistributionEngineConfiguration().getEnvironments().get(0); + DistributionStatusEnum distributionStatusEnum = DistributionStatusEnum.findState(reqDistributionStatus.getValue()); + switch(distributionStatusEnum){ + case DISTRIBUTION_APPROVED: + return sendApproveDistribution(user, uniqueId, userRemarks); + case DISTRIBUTED: + String url = String.format(Urls.ACTIVATE_DISTRIBUTION, config.getCatalogBeHost(), config.getCatalogBePort(), uniqueId, environmentName); + return sendDistrState(user, userRemarks, url); + case DISTRIBUTION_REJECTED: + return rejectDistribution(user, userRemarks, uniqueId); + default: + return null; + + } + +// if (reqDistributionStatus == DistributionStatusEnum.DISTRIBUTION_APPROVED) { +// return sendApproveDistribution(user, uniqueId, userRemarks); +// } else if (reqDistributionStatus == DistributionStatusEnum.DISTRIBUTION_REJECTED) { +// return rejectDistribution(user, userRemarks, uniqueId); +// } else if (reqDistributionStatus == DistributionStatusEnum.DISTRIBUTED) { +// Config config = Utils.getConfig(); +// // String url = +// // String.format("http://%s:%s/sdc2/rest/v1/catalog/services/%s/tempUrlToBeDeleted", +// // config.getCatalogBeHost(), config.getCatalogBePort(), uniqueId); +// String url = String.format(Urls.ACTIVATE_DISTRIBUTION, config.getCatalogBeHost(), config.getCatalogBePort(), +// uniqueId, "PROD"); +// return sendDistrState(user, userRemarks, url); +// } else +// return null; + + } + + public static RestResponse sendApproveDistribution(User sdncModifierDetails, String uniqueId, String userRemarks) + throws FileNotFoundException, IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.APPROVE_DISTRIBUTION, config.getCatalogBeHost(), config.getCatalogBePort(), + uniqueId); + return sendDistrState(sdncModifierDetails, userRemarks, url); + } + + public static RestResponse rejectDistribution(ServiceReqDetails serviceDetails, String version, User user, + String userRemarks) throws Exception { + return rejectDistribution(user, userRemarks, serviceDetails.getUniqueId()); + } + + public static RestResponse rejectDistribution(User user, String userRemarks, String uniqueId) + throws FileNotFoundException, IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.REJECT_DISTRIBUTION, config.getCatalogBeHost(), config.getCatalogBePort(), + uniqueId); + return sendDistrState(user, userRemarks, url); + } + + private static RestResponse sendDistrState(User user, String userRemarks, String url) throws IOException { + Map headersMap = prepareHeadersMap(user); + Map userRemarksMap = new HashMap(); + userRemarksMap.put("userRemarks", userRemarks); + + String serviceBodyJson = new JSONObject().toJSONString(userRemarksMap); + + HttpRequest httpRequest = new HttpRequest(); + logger.debug(url); + logger.debug("Send POST request to create service: {}", url); + logger.debug("Service body: {}", serviceBodyJson); + logger.debug("Service headers: {}", headersMap); + RestResponse rejectDistributionResponse = httpRequest.httpSendPost(url, serviceBodyJson, headersMap); + + return rejectDistributionResponse; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ProductRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ProductRestUtils.java new file mode 100644 index 0000000000..93c0d05f87 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ProductRestUtils.java @@ -0,0 +1,196 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.IOException; + +import com.google.gson.Gson; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProductRestUtils extends BaseRestUtils { + private static Gson gson = new Gson(); + private static Logger logger = LoggerFactory.getLogger(ProductRestUtils.class.getName()); + + public static RestResponse createProduct(ProductReqDetails product, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_PRODUCT, config.getCatalogBeHost(), config.getCatalogBePort()); + String serviceBodyJson = gson.toJson(product); + + logger.debug("Send POST request to create service: {}", url); + logger.debug("Service body: {}", serviceBodyJson); + + RestResponse res = sendPost(url, serviceBodyJson, user.getUserId(), acceptHeaderData); + if (res.getErrorCode() == STATUS_CODE_CREATED) { + product.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); + product.setVersion(ResponseParser.getVersionFromResponse(res)); + product.setUUID(ResponseParser.getUuidFromResponse(res)); + // Creator details never change after component is created - Ella, + // 12/1/2016 + product.setCreatorUserId(user.getUserId()); + product.setCreatorFullName(user.getFullName()); + product.setLastUpdaterFullName(user.getFullName()); + product.setLastUpdaterUserId(user.getUserId()); + product.setLastUpdaterFullName(user.getFullName()); + product.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + product.setVersion("0.1"); + String lastUpdate = ResponseParser.getValueFromJsonResponse(res.getResponse(), "lastUpdateDate"); + product.setLastUpdateDate(Long.parseLong(lastUpdate, 10)); + product.setCreationDate(Long.parseLong(lastUpdate, 10)); + } + return res; + } + + public static RestResponse updateProduct(ProductReqDetails product, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_PRODUCT, config.getCatalogBeHost(), config.getCatalogBePort(), + product.getUniqueId()); + String serviceBodyJson = gson.toJson(product); + + logger.debug("Send POST request to create service: {}", url); + logger.debug("Service body: {}", serviceBodyJson); + + RestResponse res = sendPut(url, serviceBodyJson, user.getUserId(), acceptHeaderData); + if (res.getErrorCode() == STATUS_CODE_CREATED) { + product.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); + product.setVersion(ResponseParser.getVersionFromResponse(res)); + product.setUUID(ResponseParser.getUuidFromResponse(res)); + // Creator details never change after component is created - Ella, + // 12/1/2016 + product.setCreatorUserId(user.getUserId()); + product.setCreatorFullName(user.getFullName()); + product.setLastUpdaterFullName(user.getFullName()); + product.setLastUpdaterUserId(user.getUserId()); + product.setLastUpdaterFullName(user.getFullName()); + product.setLifecycleState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + String valueFromJsonResponse = ResponseParser.getValueFromJsonResponse(res.getResponse(), "version"); + product.setVersion(valueFromJsonResponse); + String lastUpdate = ResponseParser.getValueFromJsonResponse(res.getResponse(), "lastUpdateDate"); + product.setLastUpdateDate(Long.parseLong(lastUpdate, 10)); + product.setCreationDate(Long.parseLong(lastUpdate, 10)); + } + return res; + } + + public static RestResponse createProduct_Invalid_Json(String userId) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_PRODUCT, config.getCatalogBeHost(), config.getCatalogBePort()); + + RestResponse res = sendPost(url, "kukumuku", userId, acceptHeaderData); + return res; + } + + public static RestResponse deleteProduct(String id, String userId) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_PRODUCT, config.getCatalogBeHost(), config.getCatalogBePort(), id); + return sendDelete(url, userId); + } + + public static RestResponse getProduct(String productId) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_PRODUCT, config.getCatalogBeHost(), config.getCatalogBePort(), productId); + logger.debug("Send GET request to get product: {}", url); + + return sendGet(url, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER).getUserId()); + } + + public static RestResponse getProduct(String productId, String userId) throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_PRODUCT, config.getCatalogBeHost(), config.getCatalogBePort(), productId); + logger.debug("Send GET request to get product: {}", url); + + return sendGet(url, userId); + } + + public static RestResponse getFollowed(String userId) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_FOLLWED_LIST, config.getCatalogBeHost(), config.getCatalogBePort()); + logger.debug("Send GET request to get user followed page: {}", url); + return sendGet(url, userId); + + } + + public static RestResponse changeProductLifeCycle(Product product, User userModifier, LifeCycleStatesEnum lifeCycle) + throws Exception { + String checkinComment = "my comment"; + RestResponse changeLifeCycleResponse = LifecycleRestUtils.changeProductState(product, userModifier, lifeCycle, + checkinComment); + if (changeLifeCycleResponse.getErrorCode() == STATUS_CODE_SUCCESS) { + product.setLastUpdaterUserId(userModifier.getUserId()); + product.setLastUpdaterFullName(userModifier.getFullName()); + String latestVersion = ResponseParser.getValueFromJsonResponse(changeLifeCycleResponse.getResponse(), + "version"); + product.setVersion(latestVersion); + String lifecycleState = ResponseParser.getValueFromJsonResponse(changeLifeCycleResponse.getResponse(), + "lifecycleState"); + product.setLifecycleState((LifecycleStateEnum.valueOf(lifecycleState))); + String uniqueId = ResponseParser.getValueFromJsonResponse(changeLifeCycleResponse.getResponse(), + "uniqueId"); + product.setUniqueId(uniqueId); + String lastUpdate = ResponseParser.getValueFromJsonResponse(changeLifeCycleResponse.getResponse(), + "lastUpdateDate"); + product.setLastUpdateDate((Long.parseLong(lastUpdate, 10))); + String uuid = ResponseParser.getValueFromJsonResponse(changeLifeCycleResponse.getResponse(), "uuid"); + product.setUUID(uuid); + } + return changeLifeCycleResponse; + } + + public static RestResponse changeServiceInstanceVersion(String componentUniqueId, + String serviceInstanceToReplaceUniqueId, String serviceUniqueId, User sdncModifierDetails, + ComponentTypeEnum componentType) throws IOException { + Config config = Utils.getConfig(); + String resourceUid = ("{\"componentUid\":\"" + serviceUniqueId + "\"}"); + String url = String.format(Urls.CHANGE__RESOURCE_INSTANCE_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), ComponentTypeEnum.findParamByType(componentType), componentUniqueId, + serviceInstanceToReplaceUniqueId); + RestResponse changeResourceInstanceVersion = sendPost(url, resourceUid, sdncModifierDetails.getUserId(), + acceptHeaderData); + return changeResourceInstanceVersion; + + } + + public static RestResponse getProductByNameAndVersion(String productName, String productVersion, String userId) + throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_PRODUCT_BY_NAME_AND_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), productName, productVersion); + logger.debug("Send GET request to get product by name and version: {}", url); + return sendGet(url, userId); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/PropertyRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/PropertyRestUtils.java new file mode 100644 index 0000000000..b035694407 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/PropertyRestUtils.java @@ -0,0 +1,310 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PropertyRestUtils extends BaseRestUtils { + private static Logger logger = LoggerFactory.getLogger(PropertyRestUtils.class.getName()); + + public static RestResponse createProperty(String resourceId, String body, User user) throws Exception { + Config config = Config.instance(); + String url = String.format(Urls.CREATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceId); + + return sendPost(url, body, user.getUserId(), acceptHeaderData); + } + + public static RestResponse updateProperty(String resourceId, String propertyId, String body, User user) + throws Exception { + Config config = Config.instance(); + + String url = String.format(Urls.UPDATE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceId, propertyId); + return sendPut(url, body, user.getUserId(), acceptHeaderData); + } + + public static RestResponse getProperty(String resourceId, String propertyId, User user) throws Exception { + Config config = Config.instance(); + String url = String.format(Urls.GET_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), resourceId, + propertyId); + return sendGet(url, user.getUserId()); + } + + public static RestResponse deleteProperty(String resourceId, String propertyId, User user) throws Exception { + Config config = Config.instance(); + String url = String.format(Urls.DELETE_PROPERTY, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceId, propertyId); + + return sendDelete(url, user.getUserId()); + } + + public static ComponentInstanceProperty getPropFromListByPropNameAndType(List propList, + String propNameToUpdate, String propTypeToUpdate) { + for (ComponentInstanceProperty componentInstanceProperty : propList) { + if (componentInstanceProperty.getName().equals(propNameToUpdate) + && componentInstanceProperty.getType().equals(propTypeToUpdate)) { + return componentInstanceProperty; + } + } + return null; + } + + public static ComponentInstanceProperty getPropFromListByPropNameTypeAndPath( + List propList, String propNameToUpdate, String propTypeToUpdate, + List path) { + for (ComponentInstanceProperty componentInstanceProperty : propList) { + if (componentInstanceProperty.getPath() == null) { + return getPropFromListByPropNameAndType(propList, propNameToUpdate, propTypeToUpdate); + } + if (componentInstanceProperty.getName().equals(propNameToUpdate) + && componentInstanceProperty.getType().equals(propTypeToUpdate) + && path.containsAll(componentInstanceProperty.getPath())) { + return componentInstanceProperty; + } + } + return null; + } + + public static ComponentInstanceProperty getPropFromListByPropIdAndPath(List propList, + String propId, List path) { + + for (ComponentInstanceProperty componentInstanceProperty : propList) { + if (path != null) { + if (componentInstanceProperty.getUniqueId().equals(propId) + && componentInstanceProperty.getPath().equals(path)) { + return componentInstanceProperty; + } + } else { + if (componentInstanceProperty.getUniqueId().equals(propId)) { + return componentInstanceProperty; + } + } + } + return null; + } + + public static void comparePropertyLists(List expectedList, + List actualList, Boolean isUpdate) { + + assertTrue( + "list size are not equals, expected size is: " + expectedList.size() + " ,actual: " + actualList.size(), + expectedList.size() == actualList.size()); + Boolean flag = false; + for (ComponentInstanceProperty expectedcompInstProp : expectedList) { + for (ComponentInstanceProperty actualcompInstProp : actualList) { + flag = comparePropertyObjects(expectedcompInstProp, actualcompInstProp, isUpdate); + if (flag) { + break; + } + } + } + // System.out.println("expected: " + expectedList + ", actual: " + + // actualList); + logger.debug("expected: {}, actual: {}",expectedList,actualList); + assertTrue("actual lists does not contain all uniqeIds", flag); + } + + public static Boolean comparePropertyObjects(ComponentInstanceProperty expectedCompInstProp, + ComponentInstanceProperty actualCompInstProp, Boolean isUpdate) { + String uniqueId = expectedCompInstProp.getUniqueId(); + String type = expectedCompInstProp.getType(); + String defaulValue = expectedCompInstProp.getDefaultValue(); + if (actualCompInstProp.getUniqueId().equals(uniqueId) + && actualCompInstProp.getPath().equals(expectedCompInstProp.getPath())) { + assertTrue("expected type is: " + type + " ,actual: " + actualCompInstProp.getType(), + actualCompInstProp.getType().equals(type)); + if (defaulValue == null) { + assertTrue( + "expected defaulValue is: " + defaulValue + " ,actual: " + actualCompInstProp.getDefaultValue(), + actualCompInstProp.getDefaultValue() == defaulValue); + } else { + assertTrue( + "expected defaulValue is: " + defaulValue + " ,actual: " + actualCompInstProp.getDefaultValue(), + actualCompInstProp.getDefaultValue().equals(defaulValue)); + } + if (isUpdate) { + assertTrue( + "actual [Value] parameter " + actualCompInstProp.getName() + + "should equal to expected [Value]: " + actualCompInstProp.getValue() + " ,Value: " + + actualCompInstProp.getValue(), + actualCompInstProp.getValue().equals(expectedCompInstProp.getValue())); + assertNotNull("valueId is null", actualCompInstProp.getValueUniqueUid()); + } else { + if (defaulValue == null) { + assertTrue( + "actual [Value] parameter " + actualCompInstProp.getName() + + "should equal to expected [defaultValue]: " + actualCompInstProp.getValue() + + " ,defaultValue: " + actualCompInstProp.getDefaultValue(), + actualCompInstProp.getValue() == expectedCompInstProp.getDefaultValue()); + } else { + assertTrue( + "actual [Value] parameter " + actualCompInstProp.getName() + + "should equal to expected [defaultValue]: " + actualCompInstProp.getValue() + + " ,defaultValue: " + actualCompInstProp.getDefaultValue(), + actualCompInstProp.getValue().equals(expectedCompInstProp.getDefaultValue())); + } + assertNull("valueId is not null", actualCompInstProp.getValueUniqueUid()); + } + return true; + } + return false; + } + + public static List addResourcePropertiesToList(Resource resource, + List listToFill) { + for (PropertyDefinition prop : resource.getProperties()) { + listToFill.add(new ComponentInstanceProperty(prop, null, null)); + } + return listToFill; + } + + public static List addComponentInstPropertiesToList(Component component, + List listToFill, String componentId) { + + if (componentId != null) { + List list = component.getComponentInstancesProperties().get(componentId); + for (ComponentInstanceProperty prop : list) { + ComponentInstanceProperty componentInstanceProperty = new ComponentInstanceProperty(prop, null, null); + componentInstanceProperty.setPath(prop.getPath()); + componentInstanceProperty.setValueUniqueUid(prop.getValueUniqueUid()); + componentInstanceProperty.setValue(prop.getValue()); + listToFill.add(componentInstanceProperty); + } + } else { + Map> componentInstancesProperties = component + .getComponentInstancesProperties(); + for (Map.Entry> componentInstanceProperties : componentInstancesProperties + .entrySet()) { + for (ComponentInstanceProperty prop : componentInstanceProperties.getValue()) { + ComponentInstanceProperty componentInstanceProperty = new ComponentInstanceProperty(prop, null, + null); + componentInstanceProperty.setPath(prop.getPath()); + componentInstanceProperty.setValueUniqueUid(prop.getValueUniqueUid()); + componentInstanceProperty.setValue(prop.getValue()); + listToFill.add(componentInstanceProperty); + } + } + } + + if (component.getComponentType().getValue().equals("Resource")) { + for (PropertyDefinition prop : ((Resource) component).getProperties()) { + listToFill.add(new ComponentInstanceProperty(prop, null, null)); + } + } + return listToFill; + } + + public static ComponentInstanceProperty getCompPropInstListByInstIdAndPropName(Component component, + ComponentInstance componentInstanceDetails, String name, String type) { + List propList = component.getComponentInstancesProperties() + .get(componentInstanceDetails.getUniqueId()); + if (propList != null) { + return getPropFromListByPropNameAndType(propList, name, type); + } + return null; + } + + private static void updatePropertyListWithPathParameter(Resource resource, List path, + List expectedPropertyList) { + List propertyList = resource.getProperties(); + for (PropertyDefinition propertyDefinition : propertyList) { + ComponentInstanceProperty propDetailsToRemove = PropertyRestUtils.getPropFromListByPropNameAndType( + expectedPropertyList, propertyDefinition.getName(), propertyDefinition.getType()); + ComponentInstanceProperty propDetailsToAdd = propDetailsToRemove; + propDetailsToAdd.setPath(path); + expectedPropertyList.remove(propDetailsToRemove); + expectedPropertyList.add(propDetailsToAdd); + } + } + + private static void updatePropertyListWithPathParameterOnCompInst(Service service, List path, + List expectedPropertyList) { + List servicePropertyList = new ArrayList<>(); + servicePropertyList = PropertyRestUtils.addComponentInstPropertiesToList(service, servicePropertyList, + path.get(0)); + + for (ComponentInstanceProperty serviceCompInstProperty : servicePropertyList) { + ComponentInstanceProperty propDetailsToRemove = PropertyRestUtils.getPropFromListByPropNameTypeAndPath( + expectedPropertyList, serviceCompInstProperty.getName(), serviceCompInstProperty.getType(), + serviceCompInstProperty.getPath()); + ComponentInstanceProperty propDetailsToAdd = propDetailsToRemove; + List tempPathList = new ArrayList(); + for (String tempPath : path) { + tempPathList.add(tempPath); + } + // path parameter can not contain the same service unique ID twice + if (propDetailsToAdd.getPath() != null + && !propDetailsToAdd.getPath().get(0).contains(service.getUniqueId())) { + if (!propDetailsToAdd.getPath().containsAll(tempPathList)) { + tempPathList.addAll(propDetailsToAdd.getPath()); + } + } + propDetailsToAdd.setPath(tempPathList); + expectedPropertyList.remove(propDetailsToRemove); + expectedPropertyList.add(propDetailsToAdd); + } + } + + public static void updatePropertyListWithPathOnResource(ComponentInstance componentInstDetails, Resource resource, + List list, Component container) { + List path = new ArrayList<>(); + if (container != null) { + List componentInstances = container.getComponentInstances(); + for (ComponentInstance componentInstance : componentInstances) { + if (componentInstance.getNormalizedName().equals(componentInstDetails.getNormalizedName())) { + path.add(componentInstance.getUniqueId()); + break; + } + } + + } else { + path.add(componentInstDetails.getUniqueId()); + } + updatePropertyListWithPathParameter(resource, path, list); + } + + public static void updatePropertyListWithPathOnComponentInstance(ComponentInstance componentInstDetails, + Service service, List list) { + List path = new ArrayList<>(); + path.add(componentInstDetails.getUniqueId()); + updatePropertyListWithPathParameterOnCompInst(service, path, list); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtils.java new file mode 100644 index 0000000000..e08ef6523f --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtils.java @@ -0,0 +1,679 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import static org.testng.AssertJUnit.assertEquals; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.http.client.ClientProtocolException; +import org.json.JSONException; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.RelationshipInstData; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ComponentInstanceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ImportReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.common.util.GeneralUtility; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ResourceRestUtils extends BaseRestUtils { + private static Logger logger = LoggerFactory.getLogger(ResourceRestUtils.class.getName()); + + // ****** CREATE ******* + + public static RestResponse createResource(ResourceReqDetails resourceDetails, User sdncModifierDetails) + throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort()); + + String userId = sdncModifierDetails.getUserId(); + + Map headersMap = prepareHeadersMap(userId); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(resourceDetails); + String calculateMD5 = GeneralUtility.calculateMD5ByString(userBodyJson); + headersMap.put(HttpHeaderEnum.Content_MD5.getValue(), calculateMD5); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + // System.out.println(userBodyJson); + RestResponse createResourceResponse = http.httpSendPost(url, userBodyJson, headersMap); + if (createResourceResponse.getErrorCode() == STATUS_CODE_CREATED) { + resourceDetails.setUUID(ResponseParser.getUuidFromResponse(createResourceResponse)); + resourceDetails.setVersion(ResponseParser.getVersionFromResponse(createResourceResponse)); + resourceDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(createResourceResponse)); + String lastUpdaterUserId = ResponseParser.getValueFromJsonResponse(createResourceResponse.getResponse(), + "lastUpdaterUserId"); + resourceDetails.setLastUpdaterUserId(lastUpdaterUserId); + String lastUpdaterFullName = ResponseParser.getValueFromJsonResponse(createResourceResponse.getResponse(), + "lastUpdaterFullName"); + resourceDetails.setLastUpdaterFullName(lastUpdaterFullName); + // Creator details never change after component is created - Ella, + // 12/1/2016 + resourceDetails.setCreatorUserId(userId); + resourceDetails.setCreatorFullName(sdncModifierDetails.getFullName()); + } + return createResourceResponse; + + } + + public static RestResponse createImportResource(ImportReqDetails importReqDetails, User sdncModifierDetails, + Map additionalHeaders) throws JSONException, IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort()); + String userId = sdncModifierDetails.getUserId(); + + Gson gson = new Gson(); + String resourceImportBodyJson = gson.toJson(importReqDetails); + HttpRequest http = new HttpRequest(); + // System.out.println(url); + // System.out.println(resourceImportBodyJson); + + Map headersMap = prepareHeadersMap(userId); + if (additionalHeaders != null) { + headersMap.putAll(additionalHeaders); + } else { + headersMap.put(HttpHeaderEnum.Content_MD5.getValue(), + ArtifactRestUtils.calculateMD5(resourceImportBodyJson)); + } + + RestResponse createResourceResponse = http.httpSendPost(url, resourceImportBodyJson, headersMap); + if (createResourceResponse.getErrorCode() == STATUS_CODE_CREATED) { + importReqDetails.setVersion(ResponseParser.getVersionFromResponse(createResourceResponse)); + importReqDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(createResourceResponse)); + // Creator details never change after component is created - Ella, + // 12/1/2016 + importReqDetails.setCreatorUserId(userId); + importReqDetails.setCreatorFullName(sdncModifierDetails.getFullName()); + importReqDetails + .setToscaResourceName(ResponseParser.getToscaResourceNameFromResponse(createResourceResponse)); + importReqDetails.setDerivedList(ResponseParser.getDerivedListFromJson(createResourceResponse)); + } + return createResourceResponse; + + } + + // ***** DELETE **** + public static RestResponse deleteResource(ResourceReqDetails resourceDetails, User sdncModifierDetails, + String version) throws IOException { + + if (resourceDetails.getUniqueId() != null) { + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_RESOURCE_BY_NAME_AND_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceDetails.getName(), version); + return sendDelete(url, sdncModifierDetails.getUserId()); + } else { + return null; + } + + } + + public static RestResponse markResourceToDelete(String resourceId, String userId) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceId); + RestResponse sendDelete = sendDelete(url, userId); + + return sendDelete; + + } + + public static RestResponse deleteResource(String resourceId, String userId) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceId); + RestResponse sendDelete = sendDelete(url, userId); + + deleteMarkedResources(userId); + + return sendDelete; + + } + + public static void deleteMarkedResources(String userId) throws IOException { + String url; + Config config = Utils.getConfig(); + url = String.format(Urls.DELETE_MARKED_RESOURCES, config.getCatalogBeHost(), config.getCatalogBePort()); + sendDelete(url, userId); + } + + public static RestResponse deleteResourceByNameAndVersion(User sdncModifierDetails, String resourceName, + String resourceVersion) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_RESOURCE_BY_NAME_AND_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceName, resourceVersion); + RestResponse sendDelete = sendDelete(url, sdncModifierDetails.getUserId()); + + deleteMarkedResources(sdncModifierDetails.getUserId()); + + return sendDelete; + } + + public static Boolean deleteResourceByNameAndVersion(String resourceName, String resourceVersion) + throws IOException { + RestResponse deleteResponse = ResourceRestUtils.deleteResourceByNameAndVersion( + ElementFactory.getDefaultUser(UserRoleEnum.ADMIN), resourceName, resourceVersion); + return checkErrorCode(deleteResponse); + } + + public static Boolean removeResource(String resourceId) + throws FileNotFoundException, IOException, ClientProtocolException { + RestResponse response = deleteResource(resourceId, + ElementFactory.getDefaultUser(UserRoleEnum.ADMIN).getUserId()); + return checkErrorCode(response); + } + + // ************** GET ************* + public static RestResponse getResource(User sdncModifierDetails, String uniqueId) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), uniqueId); + return sendGet(url, sdncModifierDetails.getUserId()); + } + + public static RestResponse getModule(User sdncModifierDetails, String componentId, String moduleId) + throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_MODULE_BY_ID, config.getCatalogBeHost(), config.getCatalogBePort(), + componentId, moduleId); + return sendGet(url, sdncModifierDetails.getUserId()); + } + + public static RestResponse getLatestResourceFromCsarUuid(User sdncModifierDetails, String csarUuid) + throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_RESOURCE_BY_CSAR_UUID, config.getCatalogBeHost(), config.getCatalogBePort(), + csarUuid); + return sendGet(url, sdncModifierDetails.getUserId()); + } + + public static RestResponse getResource(ResourceReqDetails resourceDetails, User sdncModifierDetails) + throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceDetails.getUniqueId()); + return sendGet(url, sdncModifierDetails.getUserId()); + } + + public static RestResponse getResourceByNameAndVersion(String userId, String resourceName, String resourceVersion) + throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_RESOURCE_BY_NAME_AND_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), resourceName, resourceVersion); + + return sendGet(url, userId); + } + + public static RestResponse getResourceList(User sdncModifierDetails) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_FOLLWED_LIST, config.getCatalogBeHost(), config.getCatalogBePort()); + + return sendGet(url, sdncModifierDetails.getUserId()); + + } + + public static RestResponse getResourceListFilterByCategory(User sdncModifierDetails, String componentType, String category) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_FILTERED_ASSET_LIST, config.getCatalogBeHost(), config.getCatalogBePort(), componentType, "category=" + category); + + Map headersMap = prepareHeadersMap(sdncModifierDetails.getUserId()); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + return sendGet(url, sdncModifierDetails.getUserId(), headersMap); + + } + + public static RestResponse getResourceListFilterBySubCategory(User sdncModifierDetails, String componentType, String subcategory) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_FILTERED_ASSET_LIST, config.getCatalogBeHost(), config.getCatalogBePort(), componentType, "subCategory=" + subcategory); + + Map headersMap = prepareHeadersMap(sdncModifierDetails.getUserId()); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + return sendGet(url, sdncModifierDetails.getUserId(), headersMap); + + } + + public static RestResponse getResourceListFilterByCriteria(User sdncModifierDetails, String componentType, String criteria, String value) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_FILTERED_ASSET_LIST, config.getCatalogBeHost(), config.getCatalogBePort(), componentType, criteria + "=" + value); + + Map headersMap = prepareHeadersMap(sdncModifierDetails.getUserId()); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + + return sendGet(url, sdncModifierDetails.getUserId(), headersMap); + + } + + public static RestResponse getResource(String resourceId) throws ClientProtocolException, IOException { + return getResource(ElementFactory.getDefaultUser(UserRoleEnum.ADMIN), resourceId); + } + + public static RestResponse getLatestResourceFromCsarUuid(String csarUuid) + throws ClientProtocolException, IOException { + return getLatestResourceFromCsarUuid(ElementFactory.getDefaultUser(UserRoleEnum.ADMIN), csarUuid); + } + + public static RestResponse getResourceLatestVersionList(User sdncModifierDetails) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_RESOURCE_lATEST_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort()); + + return sendGet(url, sdncModifierDetails.getUserId()); + + } + + public static RestResponse putAllCategoriesTowardsCatalogFeWithUuidNotAllowed(String uuid) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_ALL_CATEGORIES_FE, config.getCatalogFeHost(), config.getCatalogFePort(), + BaseRestUtils.RESOURCE_COMPONENT_TYPE); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderData); + headersMap.put(HttpHeaderEnum.X_ECOMP_REQUEST_ID_HEADER.getValue(), uuid); + HttpRequest http = new HttpRequest(); + + logger.debug("Send PUT request to get all categories (should be 405): {}", url); + return http.httpSendByMethod(url, "PUT", null, headersMap); + } + + public static RestResponse getAllTagsTowardsCatalogBe() throws IOException { + + Config config = Utils.getConfig(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_ALL_TAGS, config.getCatalogBeHost(), config.getCatalogBePort()); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderData); + + return http.httpSendGet(url, headersMap); + + } + + public static RestResponse getAllPropertyScopesTowardsCatalogBe() throws IOException { + + Config config = Utils.getConfig(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_PROPERTY_SCOPES_LIST, config.getCatalogBeHost(), config.getCatalogBePort()); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), "cs0008"); + + return http.httpSendGet(url, headersMap); + + } + + public static RestResponse getAllArtifactTypesTowardsCatalogBe() throws IOException { + + Config config = Utils.getConfig(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_ALL_ARTIFACTS, config.getCatalogBeHost(), config.getCatalogBePort()); + + Map headersMap = new HashMap(); + + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), "cs0008"); + + return http.httpSendGet(url, headersMap); + + } + + public static RestResponse getConfigurationTowardsCatalogBe() throws IOException { + + Config config = Utils.getConfig(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_CONFIGURATION, config.getCatalogBeHost(), config.getCatalogBePort()); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), "cs0008"); + + return http.httpSendGet(url, headersMap); + + } + + public static RestResponse sendOptionsTowardsCatalogFeWithUuid() throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_ALL_CATEGORIES_FE, config.getCatalogFeHost(), config.getCatalogFePort(), + BaseRestUtils.RESOURCE_COMPONENT_TYPE); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderData); + HttpRequest http = new HttpRequest(); + + logger.debug("Send OPTIONS request for categories: {}", url); + return http.httpSendByMethod(url, "OPTIONS", null, headersMap); + } + + // ********** UPDATE ************* + public static RestResponse updateResourceMetadata(ResourceReqDetails updatedResourceDetails, + User sdncModifierDetails, String uniqueId, String encoding) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_RESOURCE_METADATA, config.getCatalogBeHost(), config.getCatalogBePort(), + uniqueId); + + String ContentTypeString = String.format("%s;%s", contentTypeHeaderData, encoding); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(updatedResourceDetails); + String userId = sdncModifierDetails.getUserId(); + + RestResponse updateResourceResponse = sendPut(url, userBodyJson, userId, ContentTypeString); + + updatedResourceDetails.setVersion(ResponseParser.getVersionFromResponse(updateResourceResponse)); + updatedResourceDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(updateResourceResponse)); + + return updateResourceResponse; + } + + public static RestResponse updateResourceTEST(Resource resource, User sdncModifierDetails, String uniqueId, + String encoding) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_RESOURCE_METADATA, config.getCatalogBeHost(), config.getCatalogBePort(), + uniqueId); + + String ContentTypeString = String.format("%s;%s", contentTypeHeaderData, encoding); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(resource); + String userId = sdncModifierDetails.getUserId(); + + RestResponse updateResourceResponse = sendPut(url, userBodyJson, userId, ContentTypeString); + + // String resourceUniqueId = + // ResponseParser.getValueFromJsonResponse(updateResourceResponse.getResponse(), + // "uniqueId"); + // updatedResourceDetails.setUniqueId(resourceUniqueId); + // String resourceVersion = + // ResponseParser.getValueFromJsonResponse(updateResourceResponse.getResponse(), + // "version"); + // updatedResourceDetails.setUniqueId(resourceVersion); + + return updateResourceResponse; + } + + public static RestResponse updateResourceMetadata(ResourceReqDetails updatedResourceDetails, + User sdncModifierDetails, String uniqueId) throws Exception { + return updateResourceMetadata(updatedResourceDetails, sdncModifierDetails, uniqueId, ""); + } + + public static RestResponse updateResourceMetadata(String json, User sdncModifierDetails, String resourceId) + throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_RESOURCE_METADATA, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceId); + String userId = sdncModifierDetails.getUserId(); + + RestResponse updateResourceResponse = sendPut(url, json, userId, contentTypeHeaderData); + + return updateResourceResponse; + } + + public static RestResponse updateResource(ResourceReqDetails resourceDetails, User sdncModifierDetails, + String resourceId) throws IOException { + + String userId = sdncModifierDetails.getUserId(); + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceId); + + Map headersMap = prepareHeadersMap(userId); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(resourceDetails); + String calculateMD5 = GeneralUtility.calculateMD5ByString(userBodyJson); + headersMap.put(HttpHeaderEnum.Content_MD5.getValue(), calculateMD5); + HttpRequest http = new HttpRequest(); + RestResponse updateResourceResponse = http.httpSendPut(url, userBodyJson, headersMap); + if (updateResourceResponse.getErrorCode() == STATUS_CODE_UPDATE_SUCCESS) { + resourceDetails.setUUID(ResponseParser.getUuidFromResponse(updateResourceResponse)); + resourceDetails.setVersion(ResponseParser.getVersionFromResponse(updateResourceResponse)); + resourceDetails.setUniqueId(ResponseParser.getUniqueIdFromResponse(updateResourceResponse)); + String lastUpdaterUserId = ResponseParser.getValueFromJsonResponse(updateResourceResponse.getResponse(), + "lastUpdaterUserId"); + resourceDetails.setLastUpdaterUserId(lastUpdaterUserId); + String lastUpdaterFullName = ResponseParser.getValueFromJsonResponse(updateResourceResponse.getResponse(), + "lastUpdaterFullName"); + resourceDetails.setLastUpdaterFullName(lastUpdaterFullName); + resourceDetails.setCreatorUserId(userId); + resourceDetails.setCreatorFullName(sdncModifierDetails.getFullName()); + } + return updateResourceResponse; + } + + public static RestResponse createResourceInstance(ResourceReqDetails resourceDetails, User modifier, + String vfResourceUniqueId) throws Exception { + ComponentInstanceReqDetails resourceInstanceReqDetails = ElementFactory + .getComponentResourceInstance(resourceDetails); + RestResponse createResourceInstanceResponse = ComponentInstanceRestUtils.createComponentInstance( + resourceInstanceReqDetails, modifier, vfResourceUniqueId, ComponentTypeEnum.RESOURCE); + ResourceRestUtils.checkCreateResponse(createResourceInstanceResponse); + return createResourceInstanceResponse; + } + + public static RestResponse associateResourceInstances(JSONObject body, User sdncModifierDetails, + Component component) throws IOException { + + Config config = Utils.getConfig(); + Gson gson = new Gson(); + String bodyJson = gson.toJson(body); + component.getComponentType(); + String componentType = ComponentTypeEnum.findParamByType(component.getComponentType()); + String url = String.format(Urls.ASSOCIATE__RESOURCE_INSTANCE, config.getCatalogBeHost(), + config.getCatalogBePort(), componentType, component.getUniqueId()); + return sendPost(url, bodyJson, sdncModifierDetails.getUserId(), null); + + } + + public static RestResponse getFollowedList(User sdncModifierDetails) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_FOLLWED_LIST, config.getCatalogBeHost(), config.getCatalogBePort()); + return sendGet(url, sdncModifierDetails.getUserId()); + } + + public static List restResponseToResourceObjectList(String restResponse) { + JsonElement jelement = new JsonParser().parse(restResponse); + JsonArray jsonArray = jelement.getAsJsonArray(); + List restResponseArray = new ArrayList<>(); + Resource resource = null; + for (int i = 0; i < jsonArray.size(); i++) { + String resourceString = (String) jsonArray.get(i).toString(); + resource = ResponseParser.convertResourceResponseToJavaObject(resourceString); + restResponseArray.add(resource); + } + + return restResponseArray; + + } + + public static Resource getResourceObjectFromResourceListByUid(List resourceList, String uid) { + if (resourceList != null && resourceList.size() > 0) { + for (Resource resource : resourceList) { + if (resource.getUniqueId().equals(uid)) + return resource; + } + } else + return null; + return null; + } + + // =======================================resource + // associate================================================== + public static RestResponse associate2ResourceInstances(Component container, ComponentInstance fromNode, + ComponentInstance toNode, String assocType, User sdncUserDetails) throws IOException { + return associate2ResourceInstances(container, fromNode.getUniqueId(), toNode.getUniqueId(), assocType, + sdncUserDetails); + } + + public static RestResponse associate2ResourceInstances(Component component, String fromNode, String toNode, + String assocType, User sdncUserDetails) throws IOException { + + RelationshipInstData relationshipInstData = new RelationshipInstData(); + Map> capabilitiesMap = component.getCapabilities(); + Map> requirementMap = component.getRequirements(); + List capabilitiesList = capabilitiesMap.get(assocType); + List requirementList = requirementMap.get(assocType); + + RequirementDefinition requirementDefinitionFrom = getRequirementDefinitionByOwnerId(requirementList, fromNode); + CapabilityDefinition capabilityDefinitionTo = getCapabilityDefinitionByOwnerId(capabilitiesList, toNode); + relationshipInstData.setCapabilityOwnerId(capabilityDefinitionTo.getOwnerId()); + relationshipInstData.setCapabiltyId(capabilityDefinitionTo.getUniqueId()); + relationshipInstData.setRequirementOwnerId(requirementDefinitionFrom.getOwnerId()); + relationshipInstData.setRequirementId(requirementDefinitionFrom.getUniqueId()); + + JSONObject assocBody = assocBuilder(relationshipInstData, capabilityDefinitionTo, requirementDefinitionFrom, + toNode, fromNode); + return ResourceRestUtils.associateResourceInstances(assocBody, sdncUserDetails, component); + + } + + private static JSONObject assocBuilder(RelationshipInstData relationshipInstData, + CapabilityDefinition capabilityDefinitionTo, RequirementDefinition requirementDefinitionFrom, String toNode, + String fromNode) { + + String type = capabilityDefinitionTo.getType(); + String requirement = requirementDefinitionFrom.getName(); + String capability = requirementDefinitionFrom.getName(); + + JSONObject wrapper = new JSONObject(); + JSONArray relationshipsArray = new JSONArray(); + JSONObject relationship = new JSONObject(); + JSONObject simpleObject = new JSONObject(); + + relationship.put("type", type); + simpleObject.put("relationship", relationship); + simpleObject.put("requirement", requirement); + simpleObject.put("capability", capability); + simpleObject.put("capabilityUid", relationshipInstData.getCapabiltyId()); + simpleObject.put("capabilityOwnerId", relationshipInstData.getCapabilityOwnerId()); + simpleObject.put("requirementOwnerId", relationshipInstData.getRequirementOwnerId()); + simpleObject.put("requirementUid", relationshipInstData.getRequirementId()); + relationshipsArray.add(simpleObject); + + ArrayList relationships = new ArrayList(relationshipsArray); + wrapper.put("fromNode", fromNode); + wrapper.put("toNode", toNode); + wrapper.put("relationships", relationships); + return wrapper; + + } + + private static CapabilityDefinition getCapabilityDefinitionByOwnerId( + List capabilityDefinitionList, String ownerId) { + + for (CapabilityDefinition capabilityDefinition : capabilityDefinitionList) { + if (capabilityDefinition.getOwnerId().equals(ownerId)) { + return capabilityDefinition; + } + } + return null; + } + + private static RequirementDefinition getRequirementDefinitionByOwnerId( + List requirementDefinitionList, String ownerId) { + + for (RequirementDefinition requirementDefinition : requirementDefinitionList) { + if (requirementDefinition.getOwnerId().equals(ownerId)) { + return requirementDefinition; + } + } + return null; + } + + public static String getRiUniqueIdByRiName(Component component, String resourceInstanceName) { + + List componentInstances = component.getComponentInstances(); + String name = null; + for (ComponentInstance componentInstance : componentInstances) { + if (componentInstance.getName().equals(resourceInstanceName)) { + name = componentInstance.getUniqueId(); + break; + } + } + return name; + } + + public static Resource convertResourceGetResponseToJavaObject(ResourceReqDetails resourceDetails) + throws IOException { + RestResponse response = ResourceRestUtils.getResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + assertEquals("Check response code after get resource", 200, response.getErrorCode().intValue()); + return ResponseParser.convertResourceResponseToJavaObject(response.getResponse()); + } + + public static RestResponse changeResourceInstanceVersion(String containerUniqueId, String instanceToReplaceUniqueId, + String newResourceUniqueId, User sdncModifierDetails, ComponentTypeEnum componentType) throws IOException { + return ProductRestUtils.changeServiceInstanceVersion(containerUniqueId, instanceToReplaceUniqueId, + newResourceUniqueId, sdncModifierDetails, componentType); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtilsExternalAPI.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtilsExternalAPI.java new file mode 100644 index 0000000000..10f573cf0e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResourceRestUtilsExternalAPI.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.util.Map; + +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceExternalReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.common.util.GeneralUtility; + +import com.google.gson.Gson; + +public class ResourceRestUtilsExternalAPI extends BaseRestUtils { + + public static RestResponse createResource(ResourceExternalReqDetails resourceDetails, User sdncModifierDetails) + throws Exception { + + Config config = Utils.getConfig(); + String url = String.format(Urls.POST_EXTERNAL_API_CREATE_RESOURCE, config.getCatalogBeHost(), config.getCatalogBePort()); + + String userId = sdncModifierDetails.getUserId(); + Map headersMap = prepareHeadersMap(userId); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(resourceDetails); + String calculateMD5 = GeneralUtility.calculateMD5ByString(userBodyJson); + headersMap.put(HttpHeaderEnum.Content_MD5.getValue(), calculateMD5); + headersMap.put(HttpHeaderEnum.AUTHORIZATION.getValue(), authorizationHeader); + headersMap.put(HttpHeaderEnum.X_ECOMP_INSTANCE_ID.getValue(), "ci"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + HttpRequest http = new HttpRequest(); + RestResponse createResourceResponse = http.httpSendPost(url, userBodyJson, headersMap); + + return createResourceResponse; + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResponseParser.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResponseParser.java new file mode 100644 index 0000000000..ad9f482bc1 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ResponseParser.java @@ -0,0 +1,605 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.Version; +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.JsonDeserializer; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.module.SimpleModule; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintJacksonDeserialiser; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceRespJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.ServiceDistributionStatus; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class ResponseParser { + + // comment by Andrey, for test only + // public static void main(String[] args) { + // String response = + // "{\"uniqueId\":\"52eb0139-a855-47b9-a0e6-c90f0a90b1d2\",\"resourceName\":\"importResource4test\",\"resourceVersion\":\"0.1\",\"creatorUserId\":\"jh0003\",\"creatorFullName\":\"Jimmy + // Hendrix\",\"lastUpdaterUserId\":\"jh0003\",\"lastUpdaterFullName\":\"Jimmy + // Hendrix\",\"creationDate\":1446742241514,\"lastUpdateDate\":1446742241514,\"description\":\"Represents + // a generic software component that can be managed and run by a Compute + // Node + // Type.\",\"icon\":\"defaulticon\",\"tags\":[\"importResource4test\"],\"category\":\"Generic/Infrastructure\",\"lifecycleState\":\"NOT_CERTIFIED_CHECKOUT\",\"derivedFrom\":[\"tosca.nodes.Root\"],\"artifacts\":{},\"deploymentArtifacts\":{},\"properties\":[{\"uniqueId\":\"52eb0139-a855-47b9-a0e6-c90f0a90b1d2.port\",\"type\":\"integer\",\"required\":false,\"description\":\"the + // port the DBMS service will listen to for data and + // requests\",\"password\":false,\"name\":\"port\",\"parentUniqueId\":\"52eb0139-a855-47b9-a0e6-c90f0a90b1d2\",\"definition\":true},{\"uniqueId\":\"52eb0139-a855-47b9-a0e6-c90f0a90b1d2.root_password\",\"type\":\"string\",\"required\":false,\"description\":\"the + // optional root password for the DBMS + // service\",\"password\":false,\"name\":\"root_password\",\"parentUniqueId\":\"52eb0139-a855-47b9-a0e6-c90f0a90b1d2\",\"definition\":true}],\"interfaces\":{\"standard\":{\"type\":\"tosca.interfaces.node.lifecycle.Standard\",\"uniqueId\":\"tosca.interfaces.node.lifecycle.standard\",\"operations\":{\"stop\":{\"uniqueId\":\"tosca.interfaces.node.lifecycle.standard.stop\",\"description\":\"Standard + // lifecycle stop + // operation.\",\"definition\":false},\"start\":{\"uniqueId\":\"tosca.interfaces.node.lifecycle.standard.start\",\"description\":\"Standard + // lifecycle start + // operation.\",\"definition\":false},\"delete\":{\"uniqueId\":\"tosca.interfaces.node.lifecycle.standard.delete\",\"description\":\"Standard + // lifecycle delete + // operation.\",\"definition\":false},\"create\":{\"uniqueId\":\"tosca.interfaces.node.lifecycle.standard.create\",\"description\":\"Standard + // lifecycle create + // operation.\",\"definition\":false},\"configure\":{\"uniqueId\":\"tosca.interfaces.node.lifecycle.standard.configure\",\"description\":\"Standard + // lifecycle configure + // operation.\",\"definition\":false}},\"definition\":false}},\"capabilities\":{\"feature\":{\"uniqueId\":\"capability.8313348e-3623-4f4a-9b8f-d2fbadaf9a31.feature\",\"type\":\"tosca.capabilities.Node\"},\"feature2\":{\"uniqueId\":\"capability.52eb0139-a855-47b9-a0e6-c90f0a90b1d2.feature2\",\"type\":\"tosca.capabilities.Node\"}},\"requirements\":{\"dependency\":{\"uniqueId\":\"8313348e-3623-4f4a-9b8f-d2fbadaf9a31.dependency\",\"capability\":\"tosca.capabilities.Node\",\"node\":\"tosca.nodes.Root\",\"relationship\":\"tosca.relationships.DependsOn\"},\"dependency2\":{\"uniqueId\":\"52eb0139-a855-47b9-a0e6-c90f0a90b1d2.dependency2\",\"capability\":\"tosca.capabilities.Node\",\"node\":\"tosca.nodes.importResource4test\",\"relationship\":\"tosca.relationships.DependsOn\"}},\"vendorName\":\"ATT + // (Tosca)\",\"vendorRelease\":\"1.0.0.wd03\",\"contactId\":\"jh0003\",\"systemName\":\"Importresource4test\",\"additionalInformation\":[{\"uniqueId\":\"52eb0139-a855-47b9-a0e6-c90f0a90b1d2.additionalinformation\",\"lastCreatedCounter\":0,\"parentUniqueId\":\"52eb0139-a855-47b9-a0e6-c90f0a90b1d2\",\"parameters\":[]}],\"allVersions\":{\"0.1\":\"52eb0139-a855-47b9-a0e6-c90f0a90b1d2\"},\"abstract\":false,\"highestVersion\":true,\"uuid\":\"2e91a2df-b066-49bb-abde-4c1c01e409db\"}"; + // convertResourceResponseToJavaObject(response); + // } + + private static final String INVARIANT_UUID = "invariantUUID"; + public static final String UNIQUE_ID = "uniqueId"; + public static final String VERSION = "version"; + public static final String UUID = "uuid"; + public static final String NAME = "name"; + public static final String ORIGIN_TYPE = "originType"; + public static final String TOSCA_RESOURCE_NAME = "toscaResourceName"; + + static Logger logger = Logger.getLogger(ResponseParser.class.getName()); + + public static String getValueFromJsonResponse(String response, String fieldName) { + try { + JSONObject jsonResp = (JSONObject) JSONValue.parse(response); + Object fieldValue = jsonResp.get(fieldName); + return fieldValue.toString(); + + } catch (Exception e) { + return null; + } + + } + + public static String getUniqueIdFromResponse(RestResponse response) { + return getValueFromJsonResponse(response.getResponse(), UNIQUE_ID); + } + + public static String getInvariantUuid(RestResponse response) { + return getValueFromJsonResponse(response.getResponse(), INVARIANT_UUID); + } + + public static String getUuidFromResponse(RestResponse response) { + return getValueFromJsonResponse(response.getResponse(), UUID); + } + + public static String getNameFromResponse(RestResponse response) { + return getValueFromJsonResponse(response.getResponse(), NAME); + } + + public static String getVersionFromResponse(RestResponse response) { + return ResponseParser.getValueFromJsonResponse(response.getResponse(), VERSION); + } + + public static String getComponentTypeFromResponse(RestResponse response) { + return ResponseParser.getValueFromJsonResponse(response.getResponse(), ORIGIN_TYPE); + } + + public static String getToscaResourceNameFromResponse(RestResponse response) { + return getValueFromJsonResponse(response.getResponse(), TOSCA_RESOURCE_NAME); + } + + @SuppressWarnings("unchecked") + public static ResourceRespJavaObject parseJsonListReturnResourceDetailsObj(RestResponse restResponse, + String resourceType, String searchPattern, String expectedResult) throws Exception { + + // Gson gson = new Gson; + + JsonElement jElement = new JsonParser().parse(restResponse.getResponse()); + JsonObject jObject = jElement.getAsJsonObject(); + JsonArray arrayOfObjects = (JsonArray) jObject.get(resourceType); + Gson gson = new Gson(); + Map map = new HashMap(); + ResourceRespJavaObject jsonToJavaObject = new ResourceRespJavaObject(); + + for (int counter = 0; counter < arrayOfObjects.size(); counter++) { + JsonObject jHitObject = (JsonObject) arrayOfObjects.get(counter); + + map = (Map) gson.fromJson(jHitObject.toString(), map.getClass()); + if (map.get(searchPattern).toString().contains(expectedResult)) { + + jsonToJavaObject = gson.fromJson(jObject, ResourceRespJavaObject.class); + break; + } + } + return jsonToJavaObject; + + } + + public static Resource convertResourceResponseToJavaObject(String response) { + + ObjectMapper mapper = new ObjectMapper(); + final SimpleModule module = new SimpleModule("customerSerializationModule", + new Version(1, 0, 0, "static version")); + JsonDeserializer deserializer = new PropertyConstraintJacksonDeserialiser(); + addDeserializer(module, PropertyConstraint.class, deserializer); + + mapper.registerModule(module); + Resource resource = null; + try { +// TODO Andrey L. uncomment line below in case to ignore on unknown properties, not recommended +// mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); + resource = mapper.readValue(response, Resource.class); + + logger.debug(resource.toString()); + } catch (IOException e) { + try { + List resources = Arrays.asList(mapper.readValue(response.toString(), Resource[].class)); + resource = resources.get(0); + } catch (Exception e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + + return resource; + } + + public static ComponentInstanceProperty convertPropertyResponseToJavaObject(String response) { + + ObjectMapper mapper = new ObjectMapper(); + final SimpleModule module = new SimpleModule("customerSerializationModule", + new Version(1, 0, 0, "static version")); + JsonDeserializer desrializer = new PropertyConstraintJacksonDeserialiser(); + addDeserializer(module, PropertyConstraint.class, desrializer); + + mapper.registerModule(module); + ComponentInstanceProperty propertyDefinition = null; + try { + propertyDefinition = mapper.readValue(response, ComponentInstanceProperty.class); + logger.debug(propertyDefinition.toString()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return propertyDefinition; + } + + public static String toJson(Object object) { + Gson gson = new Gson(); + return gson.toJson(object); + } + + public static ArtifactDefinition convertArtifactDefinitionResponseToJavaObject(String response) { + ObjectMapper mapper = new ObjectMapper(); + ArtifactDefinition artifactDefinition = null; + try { + + artifactDefinition = mapper.readValue(response, ArtifactDefinition.class); + logger.debug(artifactDefinition.toString()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return artifactDefinition; + + } + + public static ArtifactReqDetails convertArtifactReqDetailsToJavaObject(String response) { + + ArtifactReqDetails artifactReqDetails = null; + Gson gson = new Gson(); + artifactReqDetails = gson.fromJson(response, ArtifactReqDetails.class); + return artifactReqDetails; + } + + public static T parseToObject(String json, Class clazz) { + Gson gson = new Gson(); + T object; + try { + object = gson.fromJson(json, clazz); + } catch (Exception e) { + object = parseToObjectUsingMapper(json, clazz); + } + return object; + } + + public static T parseToObjectUsingMapper(String json, Class clazz) { + // Generic convert + ObjectMapper mapper = new ObjectMapper(); + T object = null; + final SimpleModule module = new SimpleModule("customerSerializationModule", + new Version(1, 0, 0, "static version")); + JsonDeserializer desrializer = new PropertyConstraintJacksonDeserialiser(); + addDeserializer(module, PropertyConstraint.class, desrializer); + mapper.registerModule(module); + try { + object = mapper.readValue(json, clazz); + // System.out.println("Class: "+clazz.getSimpleName()+", json: + // "+json); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return object; + } + + public static ArtifactReqDetails convertArtifactDefinitionToArtifactReqDetailsObject( + ArtifactDefinition artifactDefinition) { + + ArtifactReqDetails artifactReqDetails = null; + Gson gson = new Gson(); + String artDef = gson.toJson(artifactDefinition); + artifactReqDetails = gson.fromJson(artDef, ArtifactReqDetails.class); + return artifactReqDetails; + } + + public static void addDeserializer(SimpleModule module, Class clazz, + final JsonDeserializer deserializer) { + module.addDeserializer(clazz, deserializer); + } + + public static Service convertServiceResponseToJavaObject(String response) { + + ObjectMapper mapper = new ObjectMapper(); + final SimpleModule module = new SimpleModule("customerSerializationModule", + new Version(1, 0, 0, "static version")); + JsonDeserializer deserializer = new PropertyConstraintJacksonDeserialiser(); + addDeserializer(module, PropertyConstraint.class, deserializer); + + mapper.registerModule(module); + Service service = null; + try { + service = mapper.readValue(response, Service.class); + logger.debug(service.toString()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return service; + } + + public static Product convertProductResponseToJavaObject(String response) { + + ObjectMapper mapper = new ObjectMapper(); + + final SimpleModule module = new SimpleModule("customerSerializationModule", + new Version(1, 0, 0, "static version")); + JsonDeserializer desrializer = new PropertyConstraintJacksonDeserialiser(); + addDeserializer(module, PropertyConstraint.class, desrializer); + + mapper.registerModule(module); + + Product product = null; + try { + product = mapper.readValue(response, Product.class); + logger.debug(product.toString()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return product; + } + + public static ComponentInstance convertComponentInstanceResponseToJavaObject(String response) { + + ObjectMapper mapper = new ObjectMapper(); + final SimpleModule module = new SimpleModule("customerSerializationModule", + new Version(1, 0, 0, "static version")); + JsonDeserializer desrializer = new PropertyConstraintJacksonDeserialiser(); + addDeserializer(module, PropertyConstraint.class, desrializer); + + mapper.registerModule(module); + ComponentInstance componentInstance = null; + try { + componentInstance = mapper.readValue(response, ComponentInstance.class); + logger.debug(componentInstance.toString()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return componentInstance; + } + + public static List getValuesFromJsonArray(RestResponse message) throws Exception { + List artifactTypesArrayFromApi = new ArrayList(); + + org.json.JSONObject responseObject = new org.json.JSONObject(message.getResponse()); + JSONArray jArr = responseObject.getJSONArray("artifactTypes"); + + for (int i = 0; i < jArr.length(); i++) { + org.json.JSONObject jObj = jArr.getJSONObject(i); + String value = jObj.get("name").toString(); + + artifactTypesArrayFromApi.add(value); + } + return artifactTypesArrayFromApi; + } + + public static String calculateMD5Header(ArtifactReqDetails artifactDetails) { + Gson gson = new Gson(); + String jsonBody = gson.toJson(artifactDetails); + // calculate MD5 for json body + return calculateMD5(jsonBody); + + } + + public static String calculateMD5(String data) { + String calculatedMd5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(data); + // encode base-64 result + byte[] encodeBase64 = Base64.encodeBase64(calculatedMd5.getBytes()); + String encodeBase64Str = new String(encodeBase64); + return encodeBase64Str; + + } + + public static List> getAuditFromMessage(Map auditingMessage) { + List> auditList = new ArrayList>(); + // JsonElement jElement = new JsonParser().parse(auditingMessage); + // JsonObject jObject = jElement.getAsJsonObject(); + // JsonObject hitsObject = (JsonObject) jObject.get("hits"); + // JsonArray hitsArray = (JsonArray) hitsObject.get("hits"); + // + // Iterator hitsIterator = hitsArray.iterator(); + // while(hitsIterator.hasNext()) + // { + // JsonElement nextHit = hitsIterator.next(); + // JsonObject jHitObject = nextHit.getAsJsonObject(); + // JsonObject jSourceObject = (JsonObject) jHitObject.get("_source"); + // + // Gson gson=new Gson(); + // String auditUnparsed = jSourceObject.toString(); + // + // Map map = new HashMap(); + // map = (Map) gson.fromJson(auditUnparsed, + // map.getClass()); + + auditList.add(auditingMessage); + // } + return auditList; + } + + public static List parseCategories(RestResponse getAllCategoriesRest) { + + List categories = new ArrayList<>(); + try { + JsonElement jElement = new JsonParser().parse(getAllCategoriesRest.getResponse()); + JsonArray cagegories = jElement.getAsJsonArray(); + Iterator iter = cagegories.iterator(); + while (iter.hasNext()) { + JsonElement next = iter.next(); + CategoryDefinition category = ResponseParser.parseToObject(next.toString(), CategoryDefinition.class); + categories.add(category); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return categories; + } + + public static JSONArray getListFromJson(RestResponse res, String field) throws JSONException { + String valueFromJsonResponse = getValueFromJsonResponse(res.getResponse(), field); + JSONArray jArr = new JSONArray(valueFromJsonResponse); + + return jArr; + } + + public static List getDerivedListFromJson(RestResponse res) throws JSONException { + JSONArray listFromJson = getListFromJson(res, "derivedList"); + List lst = new ArrayList(); + for (int i = 0; i < listFromJson.length(); i++) { + lst.add(listFromJson.getString(i)); + } + + return lst; + } + + public static Map convertStringToMap(String obj) { + Map object = (Map) JSONValue.parse(obj); + return object; + } + + public static List> getListOfMapsFromJson(RestResponse res, String field) throws Exception { + List> list = new ArrayList>(); + JSONArray listFromJson = getListFromJson(res, field); + for (int i = 0; i < listFromJson.length(); i++) { + Map convertStringToMap = convertStringToMap(listFromJson.getString(i)); + list.add(convertStringToMap); + } + return list; + + } + + public static Map getJsonValueAsMap(RestResponse response, String key) { + String valueField = getValueFromJsonResponse(response.getResponse(), key); + Map convertToMap = convertStringToMap(valueField); + return convertToMap; + } + + public static String getJsonObjectValueByKey(String metadata, String key) { + JsonElement jelement = new JsonParser().parse(metadata); + + JsonObject jobject = jelement.getAsJsonObject(); + Object obj = jobject.get(key); + if (obj == null) { + return null; + } else { + return obj.toString(); + } + } + + public static Map> convertCatalogResponseToJavaObject(String response) { + + // Map> map = new HashMap>(); + Map> map = new HashMap>(); + + JsonElement jElement = new JsonParser().parse(response); + JsonObject jObject = jElement.getAsJsonObject(); + JsonArray jArrReousrces = jObject.getAsJsonArray("resources"); + JsonArray jArrServices = jObject.getAsJsonArray("services"); + JsonArray jArrProducts = jObject.getAsJsonArray("products"); + + if (jArrReousrces != null && jArrServices != null && jArrProducts != null){ + + + //////// RESOURCE///////////////////////////// + ArrayList restResponseArray = new ArrayList<>(); + Component component = null; + for (int i = 0; i < jArrReousrces.size(); i++) { + String resourceString = (String) jArrReousrces.get(i).toString(); + component = ResponseParser.convertResourceResponseToJavaObject(resourceString); + restResponseArray.add(component); + } + + map.put("resources", restResponseArray); + + ///////// SERVICE///////////////////////////// + + restResponseArray = new ArrayList<>(); + component = null; + for (int i = 0; i < jArrServices.size(); i++) { + String resourceString = (String) jArrServices.get(i).toString(); + component = ResponseParser.convertServiceResponseToJavaObject(resourceString); + restResponseArray.add(component); + } + + map.put("services", restResponseArray); + + ///////// PRODUCT///////////////////////////// + restResponseArray = new ArrayList<>(); + component = null; + for (int i = 0; i < jArrProducts.size(); i++) { + String resourceString = (String) jArrProducts.get(i).toString(); + component = ResponseParser.convertProductResponseToJavaObject(resourceString); + restResponseArray.add(component); + } + + map.put("products", restResponseArray); + + } + else { + map.put("resources", new ArrayList<>()); + map.put("services", new ArrayList<>()); + map.put("products", new ArrayList<>()); + } + + return map; + + } + + + public static Map convertServiceDistributionStatusToObject(String response) throws ParseException { + + Map serviceDistributionStatusMap = new HashMap(); + ServiceDistributionStatus serviceDistributionStatusObject = null; + + JsonElement jElement = new JsonParser().parse(response); + JsonObject jObject = jElement.getAsJsonObject(); + JsonArray jDistrStatusArray = jObject.getAsJsonArray("distributionStatusOfServiceList"); + + for (int i = 0; i < jDistrStatusArray.size(); i++){ + Gson gson = new Gson(); + String servDistrStatus = gson.toJson(jDistrStatusArray.get(i)); + serviceDistributionStatusObject = gson.fromJson(servDistrStatus, ServiceDistributionStatus.class); + serviceDistributionStatusMap.put(Utils.getEpochTimeFromUTC(serviceDistributionStatusObject.getTimestamp()), serviceDistributionStatusObject); + } + + return serviceDistributionStatusMap; + + } + + public static Map getPropertiesNameType(RestResponse restResponse) + throws JSONException { + Map propertiesMap = new HashMap(); + JSONArray propertiesList = getListFromJson(restResponse, "properties"); + for (int i = 0; i < propertiesList.length() ; i ++){ + JSONObject prop = (JSONObject) JSONValue.parse(propertiesList.get(i).toString()); + String propName = prop.get("name").toString(); + String propType = prop.get("type").toString(); + propertiesMap.put(propName, propType); + } + + return propertiesMap; + } + + public static ResourceAssetStructure getDataOutOfSearchExternalAPIResponseForResourceName(String response, String resourceName) { + Gson gson = new Gson(); + JsonElement jsonElement = new JsonParser().parse(response); + JsonArray jsonArray = jsonElement.getAsJsonArray(); + for(JsonElement jElement: jsonArray) { + ResourceAssetStructure parsedResponse = gson.fromJson(jElement, ResourceAssetStructure.class); + + if(resourceName.contains(parsedResponse.getName()) && parsedResponse.getName().contains(resourceName)) { + return parsedResponse; + } + } + + return null; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ServiceRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ServiceRestUtils.java new file mode 100644 index 0000000000..a93587dbbc --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/ServiceRestUtils.java @@ -0,0 +1,296 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +public class ServiceRestUtils extends BaseRestUtils { + private static Logger logger = LoggerFactory.getLogger(ServiceRestUtils.class.getName()); + private final static String cacheControl = "no-cache"; + private final static String contentTypeHeaderData = "application/json"; + private final static String acceptHeaderDate = "application/json"; + // ****** CREATE ******* + + private static Gson gson = new Gson(); + + public static RestResponse deleteService(String serviceName, String version, User sdncModifierDetails) + throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_SERVICE_BY_NAME_AND_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), serviceName, version); + + String userId = sdncModifierDetails.getUserId(); + RestResponse sendDelete = sendDelete(url, userId); + deleteMarkedServices(userId); + return sendDelete; + } + + public static RestResponse markServiceToDelete(String resourceId, String userId) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), + resourceId); + RestResponse sendDelete = sendDelete(url, userId); + + return sendDelete; + + } + + public static RestResponse deleteServiceById(String serviceId, String userId) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DELETE_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), + serviceId); + RestResponse sendDelete = sendDelete(url, userId); + deleteMarkedServices(userId); + return sendDelete; + } + + public static void deleteMarkedServices(String userId) throws IOException { + String url; + Config config = Utils.getConfig(); + url = String.format(Urls.DELETE_MARKED_SERVICES, config.getCatalogBeHost(), config.getCatalogBePort()); + sendDelete(url, userId); + } + + public static RestResponse createService(ServiceReqDetails service, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.CREATE_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort()); + String serviceBodyJson = gson.toJson(service); + + logger.debug("Send POST request to create service: {}", url); + logger.debug("Service body: {}", serviceBodyJson); + + RestResponse res = sendPost(url, serviceBodyJson, user.getUserId(), acceptHeaderData); + if (res.getErrorCode() == STATUS_CODE_CREATED) { + service.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); + service.setVersion(ResponseParser.getVersionFromResponse(res)); + service.setUUID(ResponseParser.getUuidFromResponse(res)); + // Creator details never change after component is created - Ella, + // 12/1/2016 + service.setCreatorUserId(user.getUserId()); + service.setCreatorFullName(user.getFullName()); + } + + return res; + } + + public static RestResponse updateService(ServiceReqDetails service, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.UPDATE_SERVICE_METADATA, config.getCatalogBeHost(), config.getCatalogBePort(), + service.getUniqueId()); + String serviceBodyJson = gson.toJson(service); + + logger.debug("Send PUT request to create service: {}", url); + logger.debug("Service body: {}", serviceBodyJson); + + RestResponse res = sendPut(url, serviceBodyJson, user.getUserId(), acceptHeaderData); + if (res.getErrorCode() == STATUS_CODE_CREATED) { + service.setUniqueId(ResponseParser.getUniqueIdFromResponse(res)); + service.setVersion(ResponseParser.getVersionFromResponse(res)); + } + + return res; + } + + public static RestResponse getService(String serviceId) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), serviceId); + return getServiceFromUrl(url, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), false); + } + + public static RestResponse getService(ServiceReqDetails serviceReqDetails, User sdncModifierDetails) + throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), + serviceReqDetails.getUniqueId()); + return getServiceFromUrl(url, sdncModifierDetails, false); + } + + public static RestResponse getService(String serviceId, User sdncModifierDetails) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_SERVICE, config.getCatalogBeHost(), config.getCatalogBePort(), serviceId); + return getServiceFromUrl(url, sdncModifierDetails, false); + } + + public static RestResponse getServiceByNameAndVersion(User sdncModifierDetails, String serviceName, + String serviceVersion) throws IOException { + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_SERVICE_BY_NAME_AND_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), serviceName, serviceVersion); + return getServiceFromUrl(url, sdncModifierDetails, false); + } + + public static RestResponse getServiceFromUrl(String url, User sdncModifierDetails, boolean isCached) + throws IOException { + Map headersMap = prepareHeadersMap(sdncModifierDetails, isCached); + HttpRequest http = new HttpRequest(); + logger.debug("Send GET request to create service: {}", url); + logger.debug("Service headers: {}", headersMap); + RestResponse sendGetServerRequest = http.httpSendGet(url, headersMap); + + return sendGetServerRequest; + } + + public static Map prepareHeadersMap(User sdncModifierDetails, boolean isCached) { + Map headersMap = new HashMap(); + if (isCached) + headersMap.put(HttpHeaderEnum.CACHE_CONTROL.getValue(), cacheControl); + + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + return headersMap; + } + + public static RestResponse approveServiceDistribution(String serviceId, String userId) throws Exception { + return changeServiceDistributionState(serviceId, userId, Urls.APPROVE_DISTRIBUTION); + } + + public static RestResponse rejectServiceDistribution(String serviceId, String userId) throws Exception { + return changeServiceDistributionState(serviceId, userId, Urls.REJECT_DISTRIBUTION); + } + + // Benny + public static RestResponse rejectServiceDistribution(String serviceId, String userId, String comment) + throws Exception { + Config config = Utils.getConfig(); + String url = String.format(Urls.REJECT_DISTRIBUTION, config.getCatalogBeHost(), config.getCatalogBePort(), + serviceId); + String userBodyJson = gson.toJson(comment); + return sendPost(url, userBodyJson, userId, acceptHeaderData); + + } + + private static RestResponse changeServiceDistributionState(String serviceId, String userId, String distributionUrl) + throws Exception { + Config config = Utils.getConfig(); + String url = String.format(distributionUrl, config.getCatalogBeHost(), config.getCatalogBePort(), serviceId); + String defComment = "{ userRemarks : \"this is an test\" }"; + String userBodyJson = gson.toJson(defComment); + return sendPost(url, userBodyJson, userId, acceptHeaderData); + + } + + public static RestResponse getServiceLatestVersionList(User sdncModifierDetails) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.GET_SERVICE_lATEST_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort()); + + return sendGet(url, sdncModifierDetails.getUserId()); + + } + + public static RestResponse createServiceByHttpMethod(ServiceReqDetails serviceDetails, User sdncModifierDetails, + String method, String urls) throws IOException { + Map headersMap = prepareHeadersMap(sdncModifierDetails, true); + + Config config = Utils.getConfig(); + String serviceBodyJson = gson.toJson(serviceDetails); + HttpRequest http = new HttpRequest(); + String url = String.format(urls, config.getCatalogBeHost(), config.getCatalogBePort()); + // TODO: ADD AUTHENTICATION IN REQUEST + logger.debug(url); + logger.debug("Send {} request to create user: {}",method,url); + logger.debug("User body: {}", serviceBodyJson); + logger.debug("User headers: {}", headersMap); + RestResponse sendCreateUserRequest = http.httpSendByMethod(url, method, serviceBodyJson, headersMap); + + return sendCreateUserRequest; + + } + + public static RestResponse deleteServiceByNameAndVersion(User sdncModifierDetails, String serviceName, + String serviceVersion) throws IOException { + Config config = Utils.getConfig(); + + Map headersMap = prepareHeadersMap(sdncModifierDetails, true); + + HttpRequest http = new HttpRequest(); + + String url = String.format(Urls.DELETE_SERVICE_BY_NAME_AND_VERSION, config.getCatalogBeHost(), + config.getCatalogBePort(), serviceName, serviceVersion); + RestResponse deleteResponse = http.httpSendDelete(url, headersMap); + + return deleteResponse; + } + + public static RestResponse getFollowed(User user) throws Exception { + Config config = Utils.getConfig(); + + HttpRequest httpRequest = new HttpRequest(); + + String url = String.format(Urls.GET_FOLLWED_LIST, config.getCatalogBeHost(), config.getCatalogBePort()); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), user.getUserId()); + + RestResponse getResourceNotAbstarctResponse = httpRequest.httpSendGet(url, headersMap); + + return getResourceNotAbstarctResponse; + } + + public static JSONArray getListArrayFromRestResponse(RestResponse restResponse) { + String json = restResponse.getResponse(); + JSONObject jsonResp = (JSONObject) JSONValue.parse(json); + JSONArray servicesArray = (JSONArray) jsonResp.get("services"); + + logger.debug("services= {}", servicesArray); + + return servicesArray; + } + + public static RestResponse getDistributionServiceList(Service service, User user) throws IOException { + + Config config = Utils.getConfig(); + String url = String.format(Urls.DISTRIBUTION_SERVICE_LIST, config.getCatalogBeHost(), config.getCatalogBePort(), service.getUUID()); + return getServiceFromUrl(url, user, false); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/UserRestUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/UserRestUtils.java new file mode 100644 index 0000000000..881e9469dd --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/rest/UserRestUtils.java @@ -0,0 +1,299 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.rest; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.run.StartTest; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +public class UserRestUtils extends BaseRestUtils { + + static Gson gson = new Gson(); + + static Logger logger = LoggerFactory.getLogger(UserRestUtils.class.getName()); + static String contentTypeHeaderData = "application/json"; + static String acceptHeaderDate = "application/json"; + + public UserRestUtils() { + super(); + + StartTest.enableLogger(); + } + + public static RestResponse createUser(User sdncUserDetails, User sdncModifierDetails) throws IOException { + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + String userBodyJson = gson.toJson(sdncUserDetails); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.CREATE_USER, config.getCatalogBeHost(), config.getCatalogBePort()); + + logger.debug("Send POST request to create user: {}", url); + logger.debug("User body: {}", userBodyJson); + logger.debug("User headers: {}", headersMap); + RestResponse sendCreateUserRequest = http.httpSendPost(url, userBodyJson, headersMap); + + return sendCreateUserRequest; + + } + + public static RestResponse deactivateUser(User sdncUserDetails, User sdncModifierDetails) throws IOException { + return deleteUser(sdncUserDetails, sdncModifierDetails, true); + } + + public static RestResponse deActivateUser(User sdncUserDetails, User sdncModifierDetails) throws IOException { + return deleteUser(sdncUserDetails, sdncModifierDetails, false); + } + + public static RestResponse deleteUser(User sdncUserDetails, User sdncModifierDetails, boolean isForceDelete) + throws IOException { + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + if (isForceDelete) { + headersMap.put(User.FORCE_DELETE_HEADER_FLAG, User.FORCE_DELETE_HEADER_FLAG); + } + + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.DELETE_USER, config.getCatalogBeHost(), config.getCatalogBePort(), + sdncUserDetails.getUserId()); + RestResponse sendDeleteUserRequest = http.httpSendDelete(url, headersMap); + return sendDeleteUserRequest; + + } + + public static RestResponse updateUser(User sdncUserDetails, User sdncModifierDetails) + throws IOException, CloneNotSupportedException { + + Config config = Utils.getConfig(); + User user = new User(sdncModifierDetails); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + user.setUserId(StringUtils.EMPTY); + user.setRole(StringUtils.EMPTY); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(user); + logger.debug("userBodyJson: {}", userBodyJson); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.UPDATE_USER, config.getCatalogBeHost(), config.getCatalogBePort(), + sdncModifierDetails.getUserId()); + RestResponse sendUpdateUserRequest = http.httpSendPost(url, userBodyJson, headersMap); + + return sendUpdateUserRequest; + } + + /// Benny + public static RestResponse updateUserRole(User sdncUserDetails, User sdncModifierDetails, String userIdToUpdate) + throws IOException { + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + Gson gson = new Gson(); + String userBodyJson = gson.toJson(sdncUserDetails); + logger.debug("userBodyJson: {}", userBodyJson); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.UPDATE_USER_ROLE, config.getCatalogBeHost(), config.getCatalogBePort(), + userIdToUpdate); + RestResponse sendUpdateUserRequest = http.httpSendPost(url, userBodyJson, headersMap); + + return sendUpdateUserRequest; + + } + + public static RestResponse getUser(User sdncUserDetails, User sdncModifierDetails) throws IOException { + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_USER, config.getCatalogBeHost(), config.getCatalogBePort(), + sdncUserDetails.getUserId()); + RestResponse sendGetUserRequest = http.httpSendGet(url, headersMap); + return sendGetUserRequest; + + } + + public static RestResponse getUserRole(User sdncUserDetails, User sdncModifierDetails) throws IOException { + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_USER_ROLE, config.getCatalogBeHost(), config.getCatalogBePort(), + sdncUserDetails.getUserId()); + RestResponse sendGetUserRequest = http.httpSendGet(url, headersMap); + return sendGetUserRequest; + + } + + + + public static RestResponse getAllAdminUsers(User sdncModifierDetails) throws IOException { + + Config config = Utils.getConfig(); + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + + // Gson gson = new Gson(); + // String userBodyJson = gson.toJson(sdncModifierDetails); + // System.out.println(userBodyJson); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_ALL_ADMIN_USERS, config.getCatalogBeHost(), config.getCatalogBePort()); + logger.debug("Send following url: {} and headers: {}",url, headersMap.toString()); + RestResponse sendGetUserRequest = http.httpSendGet(url, headersMap); + + return sendGetUserRequest; + + } + + // US571255 + public static RestResponse getUsersByRoles(User sdncModifierDetails, String roles) throws IOException { + + Config config = Utils.getConfig(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + HttpRequest http = new HttpRequest(); + String url; + if (roles == "/") { + url = String.format(Urls.GET_ALL_USERS, config.getCatalogBeHost(), config.getCatalogBePort()); + } else { + url = String.format(Urls.GET_USERS_BY_ROLES, config.getCatalogBeHost(), config.getCatalogBePort(), roles); + + } + logger.debug("Send following url: {} and headers: {}",url, headersMap.toString()); + RestResponse sendGetUserRequest = http.httpSendGet(url, headersMap); + return sendGetUserRequest; + } + + public static RestResponse getUsersByRolesHttpCspAtuUidIsMissing(User sdncModifierDetails, String roles) + throws Exception { + + Config config = Utils.getConfig(); + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncModifierDetails.getUserId()); + headersMap.remove("USER_ID"); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.GET_USERS_BY_ROLES, config.getCatalogBeHost(), config.getCatalogBePort(), + roles); + logger.debug( + "Send following url without USER_ID header : " + url + " headers: " + headersMap.toString()); + + RestResponse sendGetUserRequest = http.httpSendGet(url, headersMap); + return sendGetUserRequest; + } + + public static RestResponse authorizedUserTowardsCatalogBe(User sdncUserDetails) throws IOException { + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + if (sdncUserDetails.getFirstName() != null) { + headersMap.put(HttpHeaderEnum.HTTP_CSP_FIRSTNAME.getValue(), sdncUserDetails.getFirstName()); + } + if (sdncUserDetails.getLastName() != null) { + headersMap.put(HttpHeaderEnum.HTTP_CSP_LASTNAME.getValue(), sdncUserDetails.getLastName()); + } + if (sdncUserDetails.getEmail() != null) { + headersMap.put(HttpHeaderEnum.HTTP_CSP_EMAIL.getValue(), sdncUserDetails.getEmail()); + } + + logger.debug("headersMap: {}", headersMap.toString()); + + Config config = Utils.getConfig(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.AUTHORIZE_USER, config.getCatalogBeHost(), config.getCatalogBePort()); + logger.debug("Send GET request to login as seal user : {}", url); + return http.httpSendGet(url, headersMap); + } + + public static RestResponse authorizedUserTowardsCatalogBeQA(User sdncUserDetails) throws IOException { + + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + if (sdncUserDetails.getFirstName() != null) { + headersMap.put(HttpHeaderEnum.HTTP_CSP_FIRSTNAME.getValue(), sdncUserDetails.getFirstName()); + } + if (sdncUserDetails.getLastName() != null) { + headersMap.put(HttpHeaderEnum.HTTP_CSP_LASTNAME.getValue(), sdncUserDetails.getLastName()); + } + if (sdncUserDetails.getEmail() != null) { + headersMap.put(HttpHeaderEnum.HTTP_CSP_EMAIL.getValue(), sdncUserDetails.getEmail()); + } + + logger.debug("headersMap: {}", headersMap.toString()); + + Config config = Utils.getConfig(); + HttpRequest http = new HttpRequest(); + String url = String.format(Urls.AUTHORIZE_USER, config.getCatalogBeHost(), config.getCatalogBePort()); + logger.debug("Send GET request to login as seal user : {}", url); + return http.httpSendGet(url, headersMap); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ArtifactValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ArtifactValidationUtils.java new file mode 100644 index 0000000000..b211cb723b --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ArtifactValidationUtils.java @@ -0,0 +1,226 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.JsonProcessingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.resources.data.ESArtifactData; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Decoder; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.FileUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class ArtifactValidationUtils { + + private static String desc = "description"; + private static String artifactType = "artifactType"; + private static String artifactName = "artifactName"; + private static String artifactChecksum = "artifactChecksum"; + private static String uniqueId = "uniqueId"; + protected Utils utils; + + public static void validateInformationalArtifact(ArtifactReqDetails expectedArtifact, + Map actualArtifact) { + assertTrue("description is not as expected", + expectedArtifact.getDescription().equals(actualArtifact.get(desc).toString())); + assertTrue("artifactType is not as expected", + expectedArtifact.getArtifactType().toUpperCase().equals(actualArtifact.get(artifactType).toString())); + assertTrue("artifactName is not as expected", + expectedArtifact.getArtifactName().equals(actualArtifact.get(artifactName).toString())); + assertTrue("uniqueId is not as expected", + expectedArtifact.getUniqueId().equals(actualArtifact.get(uniqueId).toString())); + assertTrue("description is not as expected", expectedArtifact.getArtifactLabel().toLowerCase() + .equals(actualArtifact.get("artifactLabel").toString())); + } + + public static void validateArtifactsNumberInComponent(Component component, ArtifactGroupTypeEnum artifactGroupType, + ArtifactTypeEnum artifactType, int expectedNumber) { + Map deploymentArtifacts; + int counter = 0; + if (artifactGroupType == ArtifactGroupTypeEnum.DEPLOYMENT) { + deploymentArtifacts = component.getDeploymentArtifacts(); + } else { + deploymentArtifacts = component.getArtifacts(); + } + if (deploymentArtifacts != null) { + for (ArtifactDefinition artifactDefinition : deploymentArtifacts.values()) { + if (artifactDefinition.getArtifactType().equals(artifactType.getType())) { + counter++; + } + } + } + assertEquals("Unexpected number of " + artifactGroupType.getType() + " artifacts in component", expectedNumber, + counter); + } + + // Benny + public static void validateArtifactsNumberInComponentInstance(ComponentInstance componentInstance, + ArtifactGroupTypeEnum artifactGroupType, ArtifactTypeEnum artifactType, int expectedNumber) { + Map deploymentArtifacts = null; + int counter = 0; + if (artifactGroupType == ArtifactGroupTypeEnum.DEPLOYMENT) { + deploymentArtifacts = componentInstance.getDeploymentArtifacts(); + } + if (deploymentArtifacts != null) { + for (ArtifactDefinition artifactDefinition : deploymentArtifacts.values()) { + if (artifactDefinition.getArtifactType().equals(artifactType.getType())) { + counter++; + } + } + } + assertEquals("Unexpected number of " + artifactGroupType.getType() + " artifacts in component", expectedNumber, + counter); + } + + public static ESArtifactData parseArtifactRespFromES(RestResponse resResponse) + throws JsonParseException, JsonProcessingException, Exception { + String bodyToParse = resResponse.getResponse(); + JsonElement jElement = new JsonParser().parse(bodyToParse); + JsonElement jsourceElement = jElement.getAsJsonObject().get("_source"); + + ObjectMapper mapper = new ObjectMapper(); + ESArtifactData esArtifactObject = mapper.readValue(jsourceElement.toString(), ESArtifactData.class); + + return esArtifactObject; + + } + + public static void validateArtifactReqVsResp(ArtifactReqDetails expectedArtifactDetails, + ArtifactDefinition actualArtifactJavaObject) { + String expected; + + expected = expectedArtifactDetails.getArtifactName(); + if (expected == null) + expected = ""; + assertEquals("artifact name is not correct ", expected, actualArtifactJavaObject.getArtifactName()); + + expected = expectedArtifactDetails.getArtifactType(); + if (expected == null) + expected = ""; + assertEquals("artifact type is not correct ", expected, actualArtifactJavaObject.getArtifactType()); + + expected = expectedArtifactDetails.getDescription(); + if (expected == null) + expected = ""; + assertEquals("artifact description is not correct ", expected, actualArtifactJavaObject.getDescription()); + + expected = expectedArtifactDetails.getArtifactLabel(); + if (expected == null || expected == "") { + expected = expectedArtifactDetails.getArtifactName().toLowerCase().substring(0, + expectedArtifactDetails.getArtifactName().lastIndexOf(".")); + // expected = tmp.substring(0, + // artifactInfo.getArtifactName().lastIndexOf(".")); + } + assertEquals("artifact label is not correct ", expected, actualArtifactJavaObject.getArtifactLabel()); + + expected = expectedArtifactDetails.getUrl(); + if (expected != "") { + assertEquals(expected, actualArtifactJavaObject.getApiUrl()); + assertEquals(expectedArtifactDetails.getArtifactDisplayName(), + actualArtifactJavaObject.getArtifactDisplayName()); + } + + // assertEquals(validChecksum, + // actualArtifactJavaObject.getArtifactChecksum()); + + // expected = expectedArtifactDetails.getArtifactDisplayName(); + // if (expected != "") + // { + // assertEquals(expected, + // actualArtifactJavaObject.getArtifactDisplayName()); + // } + + boolean actual = actualArtifactJavaObject.getMandatory(); + assertEquals(expectedArtifactDetails.isMandatory(), actual); + + if (actualArtifactJavaObject.getServiceApi()) { + + boolean actual2 = actualArtifactJavaObject.getServiceApi(); + assertEquals(expectedArtifactDetails.isServiceApi(), actual2); + } + + } + + public static void validateEsArtifactReqVsResp(ArtifactReqDetails expectedArtifactInfo, + ESArtifactData esArtifactData) throws Exception { + String expectedArtifactUid = expectedArtifactInfo.getUniqueId(); + if (expectedArtifactUid == null) + expectedArtifactUid = ""; + assertEquals("artifact name is not correct ", expectedArtifactUid, esArtifactData.getId()); + + String actualPayload = Decoder.encode(esArtifactData.getData().array()); + assertEquals("artifact payloadData is not correct ", expectedArtifactInfo.getPayload(), actualPayload); + } + + public static List getListOfArtifactFromFolder(String folderName) throws IOException, Exception { + Config config = Utils.getConfig(); + String sourceDir = config.getResourceConfigDir(); + String testResourcesPath = sourceDir + File.separator + folderName; + List listofFiles = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + return listofFiles; + } + + public static ArtifactReqDetails replaceDefaultArtWithArtFromList_(ArtifactReqDetails heatArtifactDetails, + String heatExtension, String folderName, int positionInlist) throws IOException, Exception { + + Config config = Utils.getConfig(); + String ext = heatExtension; + String sourceDir = config.getResourceConfigDir(); + String testResourcesPath = sourceDir + File.separator + folderName; + List listFileName = FileUtils.getFileListFromBaseDirectoryByTestName(testResourcesPath); + String payload = FileUtils.loadPayloadFile(listFileName, ext, true); + heatArtifactDetails.setPayload(payload); + heatArtifactDetails.setArtifactName(listFileName.get(positionInlist) + "." + ext); + return heatArtifactDetails; + } + + public static ArtifactReqDetails replaceDefaultArtWithArtFromList(ArtifactReqDetails heatArtifactDetails, + String heatExtension, String folderName, int positionInlist) throws IOException, Exception { + List listOfArtifactFromFolder = getListOfArtifactFromFolder(folderName); + String payload = FileUtils.loadPayloadFileFromListUsingPosition(listOfArtifactFromFolder, heatExtension, true, + positionInlist); + heatArtifactDetails.setPayload(payload); + heatArtifactDetails.setArtifactName(heatArtifactDetails.getArtifactType() + + listOfArtifactFromFolder.get(positionInlist) + "." + heatExtension); + return heatArtifactDetails; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/AuditValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/AuditValidationUtils.java new file mode 100644 index 0000000000..7a5b7bb546 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/AuditValidationUtils.java @@ -0,0 +1,1418 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.javatuples.Pair; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.AuditEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.AuditJsonKeysEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ComponentType; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedAuthenticationAudit; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedCategoryAudit; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedDistDownloadAudit; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedEcomConsumerAudit; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedExternalAudit; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedGetUserListAudit; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedProductAudit; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedUserCRUDAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.run.StartTest; +import org.openecomp.sdc.ci.tests.utils.ArtifactUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.cassandra.CassandraUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils.CategoryAuditJsonKeysEnum; +import org.openecomp.sdc.ci.tests.utils.rest.ConsumerRestUtils.EcompConsumerAuditJsonKeysEnum; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; + +import com.datastax.driver.core.ColumnDefinitions; +import com.datastax.driver.core.Row; + +public class AuditValidationUtils { + protected static Logger logger = Logger.getLogger(AuditValidationUtils.class.getName()); + private static final String auditKeySpaceName = "sdcaudit"; + + public AuditValidationUtils() { + super(); + + StartTest.enableLogger(); + logger = Logger.getLogger(AuditValidationUtils.class.getName()); + + } + + public static String buildAuditDescription(ErrorInfo errorInfo, List variables) { + + String auditDesc = errorInfo.getMessageId() + ": " + errorInfo.getMessage(); + if(! variables.isEmpty() && variables.get(0) != null && ! variables.get(0).isEmpty()){ + for (int i = 0; i < variables.size(); i++) { + if (auditDesc.contains("%" + (i + 1))) { + auditDesc = auditDesc.replace("%" + (i + 1), variables.get(i)); + } + } + } + return auditDesc; + } + + public static String getModifierString(String userName, String uid) { + + if (userName.isEmpty() && uid.isEmpty()) + return "(UNKNOWN)"; + + StringBuilder sb = new StringBuilder(); + sb.append(userName).append("(").append(uid).append(")"); + return sb.toString(); + + } + + public static void validateAuditDownloadExternalAPI(ExpectedResourceAuditJavaObject resourceAuditJavaObject, + String action, String body, boolean checkAllFields) throws Exception { + Map actualAuditRecords = new HashMap(); + // Andrey's comment + // actualAuditRecords = parseAuditResourceByAction(action, body); + actualAuditRecords = parseAuditResourceByAction(action, null); + + // List> actualAuditRecords = new + // ArrayList>(); + // actualAuditRecords = parseAuditResourceByActionToList(action, body); + + validateField(actualAuditRecords, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(actualAuditRecords, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceName()); + validateField(actualAuditRecords, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceType()); + + validateField(actualAuditRecords, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), + resourceAuditJavaObject.getStatus()); + validateField(actualAuditRecords, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), + resourceAuditJavaObject.getDesc()); + + // validateField(actualAuditRecords, + // AuditJsonKeysEnum.CONSUMER_ID.getAuditJsonKeyName(), + // resourceAuditJavaObject.getCONSUMER_ID()); + // validateField(actualAuditRecords, + // AuditJsonKeysEnum.RESOURCE_URL.getAuditJsonKeyName(), + // resourceAuditJavaObject.getRESOURCE_URL()); + + } + + public static void validateAudit(ExpectedResourceAuditJavaObject resourceAuditJavaObject, String action, + String body, boolean checkAllFields) throws Exception { + Map actualAuditRecords = new HashMap(); + // Andrey's comment + // actualAuditRecords = parseAuditResourceByAction(action, body); + actualAuditRecords = parseAuditResourceByAction(action, null); + + if ((resourceAuditJavaObject.getModifierName() != null) && (resourceAuditJavaObject.getModifierUid() != null)) { + resourceAuditJavaObject.setModifierUid(getModifierString(resourceAuditJavaObject.getModifierName(), + resourceAuditJavaObject.getModifierUid())); + } + + validateField(actualAuditRecords, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(actualAuditRecords, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceName()); + validateField(actualAuditRecords, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceType()); + validateField(actualAuditRecords, AuditJsonKeysEnum.PREV_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getPrevVersion()); + validateField(actualAuditRecords, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getCurrVersion()); + + validateField(actualAuditRecords, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), + resourceAuditJavaObject.getModifierUid()); + validateField(actualAuditRecords, AuditJsonKeysEnum.PREV_STATE.getAuditJsonKeyName(), + resourceAuditJavaObject.getPrevState()); + validateField(actualAuditRecords, AuditJsonKeysEnum.CURR_STATE.getAuditJsonKeyName(), + resourceAuditJavaObject.getCurrState()); + validateField(actualAuditRecords, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), + resourceAuditJavaObject.getStatus()); + // validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), + // Double.parseDouble(resourceAuditJavaObject.getStatus())); + validateField(actualAuditRecords, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), + resourceAuditJavaObject.getDesc()); + validateField(actualAuditRecords, AuditJsonKeysEnum.COMMENT.getAuditJsonKeyName(), + resourceAuditJavaObject.getComment()); + // validateField(map2, + // AuditJsonKeysEnum.ARTIFACT_DATA.getAuditJsonKeyName(), + // resourceAuditJavaObject.getArtifactData()); + validateField(actualAuditRecords, AuditJsonKeysEnum.TOSCA_NODE_TYPE.getAuditJsonKeyName(), + resourceAuditJavaObject.getToscaNodeType()); + validateField(actualAuditRecords, AuditJsonKeysEnum.CURR_ARTIFACT_UUID.getAuditJsonKeyName(), + resourceAuditJavaObject.getCurrArtifactUuid()); + validateField(actualAuditRecords, AuditJsonKeysEnum.PREV_ARTIFACT_UUID.getAuditJsonKeyName(), + resourceAuditJavaObject.getPrevArtifactUuid()); + + validateAtifactDataField(actualAuditRecords, AuditJsonKeysEnum.ARTIFACT_DATA.getAuditJsonKeyName(), + resourceAuditJavaObject.getArtifactData(), checkAllFields); + } + + public static void validateExternalAudit(ExpectedExternalAudit externalAuditObject, String action, + Map body) throws Exception { + + Map actualAuditRecord = new HashMap(); + actualAuditRecord = parseAuditResourceByAction(action, body); + + validateField(actualAuditRecord, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(actualAuditRecord, AuditJsonKeysEnum.CONSUMER_ID.getAuditJsonKeyName(), + externalAuditObject.getCONSUMER_ID()); + // TODO + validateField(actualAuditRecord, AuditJsonKeysEnum.RESOURCE_URL.getAuditJsonKeyName(), + externalAuditObject.getRESOURCE_URL()); + //TODO + validateField(actualAuditRecord, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), + externalAuditObject.getRESOURCE_NAME()); + validateField(actualAuditRecord, AuditJsonKeysEnum.SERVICE_INSTANCE_ID.getAuditJsonKeyName(), + externalAuditObject.getSERVICE_INSTANCE_ID()); + //TODO + validateField(actualAuditRecord, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + externalAuditObject.getRESOURCE_TYPE()); + validateField(actualAuditRecord, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), + externalAuditObject.getSTATUS()); + validateField(actualAuditRecord, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), + externalAuditObject.getDESC()); + //TODO +// validateField(actualAuditRecord, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), +// externalAuditObject.getMODIFIER()); + validateField(actualAuditRecord, AuditJsonKeysEnum.PREV_ARTIFACT_UUID.getAuditJsonKeyName(), + externalAuditObject.getPREV_ARTIFACT_UUID()); + validateField(actualAuditRecord, AuditJsonKeysEnum.CURR_ARTIFACT_UUID.getAuditJsonKeyName(), + externalAuditObject.getCURR_ARTIFACT_UUID()); + //TODO + validateField(actualAuditRecord, AuditJsonKeysEnum.ARTIFACT_DATA.getAuditJsonKeyName(), + externalAuditObject.getARTIFACT_DATA()); + + } + + public enum ArtifactDataFieldEnum { + attGroup, artLable, artType, artName, artTimeout, artPayloadUUID, artVersion, artUUID + } + + private static void validateAtifactDataField(Map map, String auditJsonKeyName, + String expectedArtifactData, boolean checkAllFields) { + Map expectedArtifactDataFileds = new HashMap(); + Map actualAtifactDataFileds = new HashMap(); + if (expectedArtifactData != null) { + String[] expected = expectedArtifactData.split(","); + + assertTrue("Audit field " + auditJsonKeyName + " not found", map.containsKey(auditJsonKeyName)); + String actualValue = (String) map.get(auditJsonKeyName); + String[] actual = actualValue.split(","); + + if (expected.length == 1 && actual.length == 1) { + assertEquals(expectedArtifactData, actualValue); + return; + } + + assertEquals(ArtifactDataFieldEnum.values().length, expected.length); + assertEquals(ArtifactDataFieldEnum.values().length, actual.length); + + for (ArtifactDataFieldEnum field : ArtifactDataFieldEnum.values()) { + + expectedArtifactDataFileds.put(field, expected[field.ordinal()]); + actualAtifactDataFileds.put(field, actual[field.ordinal()]); + } + for (Map.Entry entry : expectedArtifactDataFileds.entrySet()) { + ArtifactDataFieldEnum field = entry.getKey(); + if (checkAllFields || (!field.equals(ArtifactDataFieldEnum.artVersion) + && !field.equals(ArtifactDataFieldEnum.artUUID))) { + assertTrue("Audit field ArtifactData dosn't containt " + field, + actualAtifactDataFileds.containsKey(field)); + assertEquals("Audit field ArtifactData dosn't equal " + field, + expectedArtifactDataFileds.get(field), actualAtifactDataFileds.get(field)); + } + + } + } + } + + // //Benny + public static void validateEcompConsumerAudit(ExpectedEcomConsumerAudit ecompConsumerAuditJavaObject, String action) + throws Exception { + + String fixedAction = BaseRestUtils.encodeUrlForDownload(action); + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(fixedAction, null); + + validateField(map2, EcompConsumerAuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), + ecompConsumerAuditJavaObject.getModifier()); + validateField(map2, EcompConsumerAuditJsonKeysEnum.ECOMP_USER.getAuditJsonKeyName(), + ecompConsumerAuditJavaObject.getEcomUser()); + validateField(map2, EcompConsumerAuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), + ecompConsumerAuditJavaObject.getStatus()); + validateField(map2, EcompConsumerAuditJsonKeysEnum.DESC.getAuditJsonKeyName(), + ecompConsumerAuditJavaObject.getDesc()); + validateField(map2, EcompConsumerAuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + } + + public static void ecompConsumerAuditSuccess(String action, ConsumerDataDefinition consumerDataDefinition, + User user, int status) throws Exception { + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(action); + expectedEcomConsumerAuditJavaObject.setEcomUser( + consumerDataDefinition.getConsumerName() + "," + consumerDataDefinition.getConsumerSalt().toLowerCase() + + "," + consumerDataDefinition.getConsumerPassword().toLowerCase()); + expectedEcomConsumerAuditJavaObject.setStatus(String.valueOf(status)); + expectedEcomConsumerAuditJavaObject.setDesc("OK"); + expectedEcomConsumerAuditJavaObject.setModifier(user.getFullName() + "(" + user.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, action); + } + + public static void createEcompConsumerAuditFailure(String action, ConsumerDataDefinition consumerDataDefinition, + User user, ActionStatus errorMessage, Object... variables) throws Exception { + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(errorMessage.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + expectedEcomConsumerAuditJavaObject.setAction(action); + expectedEcomConsumerAuditJavaObject.setEcomUser( + consumerDataDefinition.getConsumerName() + "," + consumerDataDefinition.getConsumerSalt().toLowerCase() + + "," + consumerDataDefinition.getConsumerPassword().toLowerCase()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc(variables)); + expectedEcomConsumerAuditJavaObject.setModifier(user.getFullName() + "(" + user.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, action); + } + + public static void deleteEcompConsumerAuditFailure(String action, ConsumerDataDefinition consumerDataDefinition, + User user, ActionStatus errorMessage, Object... variables) throws Exception { + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(errorMessage.name()); + ExpectedEcomConsumerAudit expectedEcomConsumerAuditJavaObject = new ExpectedEcomConsumerAudit(); + // String auditAction = ADD_ECOMP_USER_CREDENTIALS_AUDIT_ACTION; + expectedEcomConsumerAuditJavaObject.setAction(action); + expectedEcomConsumerAuditJavaObject.setEcomUser(consumerDataDefinition.getConsumerName()); + expectedEcomConsumerAuditJavaObject.setStatus(errorInfo.getCode().toString()); + expectedEcomConsumerAuditJavaObject.setDesc(errorInfo.getAuditDesc(variables)); + expectedEcomConsumerAuditJavaObject.setModifier(user.getFullName() + "(" + user.getUserId() + ")"); + AuditValidationUtils.validateEcompConsumerAudit(expectedEcomConsumerAuditJavaObject, action); + } + + ////////////////////// US571255 + public static void GetListOfUsersByRolesAuditFailure(String action, String roles, int status, User userModifier, + ActionStatus errorMessage, Object... variables) throws Exception { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(errorMessage.name()); + ExpectedGetUserListAudit expectedGetListOfUsersAuditJavaObject = new ExpectedGetUserListAudit(); // String + // auditAction + // = + // ADD_ECOMP_USER_CREDENTIALS_AUDIT_ACTION; + expectedGetListOfUsersAuditJavaObject.setAction(action); + expectedGetListOfUsersAuditJavaObject.setStatus(String.valueOf(status)); + expectedGetListOfUsersAuditJavaObject.setDesc(errorInfo.getAuditDesc(variables)); + + expectedGetListOfUsersAuditJavaObject.setDetails(roles); + if (errorMessage == ActionStatus.USER_INACTIVE || errorMessage == ActionStatus.MISSING_INFORMATION) { + expectedGetListOfUsersAuditJavaObject.setModifier("(UNKNOWN)"); + } else { + expectedGetListOfUsersAuditJavaObject + .setModifier(userModifier.getFullName() + "(" + userModifier.getUserId() + ")"); + } + AuditValidationUtils.validateAuditGetListOfUsersByRoles(expectedGetListOfUsersAuditJavaObject, action); + } + + public static void GetListOfUsersByRolesAuditSuccess(String action, String roles, User user, int status) + throws Exception { + ExpectedGetUserListAudit expectedGetListOfUsersAuditJavaObject = new ExpectedGetUserListAudit(); + expectedGetListOfUsersAuditJavaObject.setAction(action); + expectedGetListOfUsersAuditJavaObject.setStatus(String.valueOf(status)); + expectedGetListOfUsersAuditJavaObject.setDesc("OK"); + expectedGetListOfUsersAuditJavaObject.setModifier(user.getFullName() + "(" + user.getUserId() + ")"); + expectedGetListOfUsersAuditJavaObject.setDetails(roles); + validateAuditGetListOfUsersByRoles(expectedGetListOfUsersAuditJavaObject, action); + } + + public static void validateAuditGetListOfUsersByRoles(ExpectedGetUserListAudit GetListOfUsersAuditJavaObject, + String action) throws Exception { + + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, null); + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), GetListOfUsersAuditJavaObject.getStatus()); + validateField(map2, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), + GetListOfUsersAuditJavaObject.getModifier()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), + GetListOfUsersAuditJavaObject.getDesc()); + validateField(map2, AuditJsonKeysEnum.DETAILS.getAuditJsonKeyName(), + GetListOfUsersAuditJavaObject.getDetails()); + } + + public static void validateAuditImport(ExpectedResourceAuditJavaObject resourceAuditJavaObject, String action) + throws Exception { + + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, null); + + resourceAuditJavaObject.setModifierUid( + getModifierString(resourceAuditJavaObject.getModifierName(), resourceAuditJavaObject.getModifierUid())); + + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceType()); + validateField(map2, AuditJsonKeysEnum.PREV_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getPrevVersion()); + validateField(map2, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getCurrVersion()); + validateField(map2, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), resourceAuditJavaObject.getModifierUid()); + validateField(map2, AuditJsonKeysEnum.PREV_STATE.getAuditJsonKeyName(), resourceAuditJavaObject.getPrevState()); + validateField(map2, AuditJsonKeysEnum.CURR_STATE.getAuditJsonKeyName(), resourceAuditJavaObject.getCurrState()); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), resourceAuditJavaObject.getStatus()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), resourceAuditJavaObject.getDesc()); + + } + + public static void validateAuditDistribution(ExpectedResourceAuditJavaObject resourceAuditJavaObject, String action) + throws Exception { + + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, null); + + resourceAuditJavaObject.setModifierUid( + getModifierString(resourceAuditJavaObject.getModifierName(), resourceAuditJavaObject.getModifierUid())); + + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceName()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceType()); + validateField(map2, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getCurrVersion()); + validateField(map2, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), resourceAuditJavaObject.getModifierUid()); + validateField(map2, AuditJsonKeysEnum.CURR_STATE.getAuditJsonKeyName(), resourceAuditJavaObject.getCurrState()); + validateField(map2, AuditJsonKeysEnum.DPREV_STATUS.getAuditJsonKeyName(), + resourceAuditJavaObject.getDprevStatus()); + validateField(map2, AuditJsonKeysEnum.DCURR_STATUS.getAuditJsonKeyName(), + resourceAuditJavaObject.getDcurrStatus()); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), resourceAuditJavaObject.getStatus()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), resourceAuditJavaObject.getDesc()); + validateField(map2, AuditJsonKeysEnum.COMMENT.getAuditJsonKeyName(), resourceAuditJavaObject.getComment()); + validateField(map2, AuditJsonKeysEnum.DID.getAuditJsonKeyName(), resourceAuditJavaObject.getDistributionId()); + + } + + // Benny + public static void validateAudit_Distribution(ExpectedResourceAuditJavaObject resourceAuditJavaObject, + String action) throws Exception { + + List> actionToList = getAuditListByAction(resourceAuditJavaObject.getAction(), 1); + Map map2 = actionToList.get(0); + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceName()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceType()); + validateField(map2, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getCurrVersion()); + validateField(map2, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), resourceAuditJavaObject.getMODIFIER()); + validateField(map2, AuditJsonKeysEnum.CURR_STATE.getAuditJsonKeyName(), resourceAuditJavaObject.getCurrState()); + validateField(map2, AuditJsonKeysEnum.DPREV_STATUS.getAuditJsonKeyName(), + resourceAuditJavaObject.getDprevStatus()); + validateField(map2, AuditJsonKeysEnum.DCURR_STATUS.getAuditJsonKeyName(), + resourceAuditJavaObject.getDcurrStatus()); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), resourceAuditJavaObject.getStatus()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), resourceAuditJavaObject.getDesc()); + validateField(map2, AuditJsonKeysEnum.COMMENT.getAuditJsonKeyName(), resourceAuditJavaObject.getComment()); + + } + + public void validateAuditNotification(ExpectedResourceAuditJavaObject resourceAuditJavaObject, String action) + throws Exception { + + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, null); + + resourceAuditJavaObject.setModifierUid( + getModifierString(resourceAuditJavaObject.getModifierName(), resourceAuditJavaObject.getModifierUid())); + + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceName()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceType()); + validateField(map2, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getCurrVersion()); + validateField(map2, AuditJsonKeysEnum.CURR_STATE.getAuditJsonKeyName(), resourceAuditJavaObject.getCurrState()); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), resourceAuditJavaObject.getStatus()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), resourceAuditJavaObject.getDesc()); + validateField(map2, AuditJsonKeysEnum.DID.getAuditJsonKeyName(), resourceAuditJavaObject.getDistributionId()); + validateField(map2, AuditJsonKeysEnum.TOPIC_NAME.getAuditJsonKeyName(), resourceAuditJavaObject.getTopicName()); + + } + + public static void validateAudit(ExpectedDistDownloadAudit expectedDistDownloadAudit, String action) + throws Exception { + + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, null); + + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), expectedDistDownloadAudit.getStatus()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), expectedDistDownloadAudit.getDesc()); + validateField(map2, AuditJsonKeysEnum.CONSUMER_ID.getAuditJsonKeyName(), + expectedDistDownloadAudit.getConsumerId()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_URL.getAuditJsonKeyName(), + expectedDistDownloadAudit.getResourceUrl()); + } + + public static void validateAuditExternalSearchAPI(ExpectedExternalAudit expectedDistDownloadAudit, String action, Map body) + throws Exception { + + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, body); + + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), expectedDistDownloadAudit.getSTATUS()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), expectedDistDownloadAudit.getDESC()); + validateField(map2, AuditJsonKeysEnum.CONSUMER_ID.getAuditJsonKeyName(), + expectedDistDownloadAudit.getCONSUMER_ID()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_URL.getAuditJsonKeyName(), + expectedDistDownloadAudit.getRESOURCE_URL()); + } + + public static void validateAuditExternalCreateResource(ExpectedResourceAuditJavaObject expectedExternalAudit, String action, Map body) throws Exception { + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, body); + + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), expectedExternalAudit.getResourceName()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), expectedExternalAudit.getResourceType()); + validateField(map2, AuditJsonKeysEnum.CONSUMER_ID.getAuditJsonKeyName(), expectedExternalAudit.getCONSUMER_ID()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_URL.getAuditJsonKeyName(), expectedExternalAudit.getRESOURCE_URL()); + validateField(map2, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), expectedExternalAudit.getMODIFIER()); + + validateField(map2, AuditJsonKeysEnum.PREV_VERSION.getAuditJsonKeyName(), expectedExternalAudit.getPrevVersion()); + validateField(map2, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), expectedExternalAudit.getCurrVersion()); + validateField(map2, AuditJsonKeysEnum.PREV_STATE.getAuditJsonKeyName(), expectedExternalAudit.getPrevState()); + validateField(map2, AuditJsonKeysEnum.CURR_STATE.getAuditJsonKeyName(), expectedExternalAudit.getCurrState()); + + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), expectedExternalAudit.getStatus()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), expectedExternalAudit.getDesc()); + } + + public static void validateAuditExternalChangeAssetLifeCycle(ExpectedResourceAuditJavaObject expectedExternalAudit, String action, Map body) throws Exception { + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, body); + + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), expectedExternalAudit.getDesc()); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), expectedExternalAudit.getStatus()); + + validateField(map2, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), expectedExternalAudit.getResourceType()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), expectedExternalAudit.getResourceName()); + validateField(map2, AuditJsonKeysEnum.CONSUMER_ID.getAuditJsonKeyName(), expectedExternalAudit.getCONSUMER_ID()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_URL.getAuditJsonKeyName(), expectedExternalAudit.getRESOURCE_URL()); + validateField(map2, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), expectedExternalAudit.getMODIFIER()); + + validateField(map2, AuditJsonKeysEnum.PREV_VERSION.getAuditJsonKeyName(), expectedExternalAudit.getPrevVersion()); + validateField(map2, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), expectedExternalAudit.getCurrVersion()); + validateField(map2, AuditJsonKeysEnum.PREV_STATE.getAuditJsonKeyName(), expectedExternalAudit.getPrevState()); + validateField(map2, AuditJsonKeysEnum.CURR_STATE.getAuditJsonKeyName(), expectedExternalAudit.getCurrState()); + + + // TODO: Remove comment +// validateField(map2, AuditJsonKeysEnum.INVARIANT_UUID.getAuditJsonKeyName(), expectedExternalAudit.getINVARIANT_UUID()); + } + + public void validateAuditDeploy(ExpectedResourceAuditJavaObject resourceAuditJavaObject, String action) + throws Exception { + + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, null); + + resourceAuditJavaObject.setModifierUid( + getModifierString(resourceAuditJavaObject.getModifierName(), resourceAuditJavaObject.getModifierUid())); + + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceName()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceType()); + validateField(map2, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getCurrVersion()); + validateField(map2, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), resourceAuditJavaObject.getModifierUid()); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), resourceAuditJavaObject.getStatus()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), resourceAuditJavaObject.getDesc()); + validateField(map2, AuditJsonKeysEnum.DID.getAuditJsonKeyName(), resourceAuditJavaObject.getDistributionId()); + + } + + public static void validateAuditProduct(ExpectedProductAudit productExpectedAudit, String action, + AuditJsonKeysEnum... additionalFields) throws Exception { + + Map map2 = new HashMap(); + map2 = parseAuditResourceByAction(action, null); + + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), + productExpectedAudit.getRESOURCE_NAME()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + productExpectedAudit.getRESOURCE_TYPE()); + validateField(map2, AuditJsonKeysEnum.PREV_VERSION.getAuditJsonKeyName(), + productExpectedAudit.getPREV_VERSION()); + validateField(map2, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), + productExpectedAudit.getCURR_VERSION()); + validateField(map2, AuditJsonKeysEnum.PREV_STATE.getAuditJsonKeyName(), productExpectedAudit.getPREV_STATE()); + validateField(map2, AuditJsonKeysEnum.CURR_STATE.getAuditJsonKeyName(), productExpectedAudit.getCURR_STATE()); + validateField(map2, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), productExpectedAudit.getMODIFIER()); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), productExpectedAudit.getSTATUS()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), productExpectedAudit.getDESC()); + validateField(map2, AuditJsonKeysEnum.SERVICE_INSTANCE_ID.getAuditJsonKeyName(), + productExpectedAudit.getSERVICE_INSTANCE_ID()); + if (additionalFields != null) { + List fieldsList = Arrays.asList(additionalFields); + if (fieldsList.contains(AuditJsonKeysEnum.COMMENT)) { + validateField(map2, AuditJsonKeysEnum.COMMENT.getAuditJsonKeyName(), productExpectedAudit.getCOMMENT()); + } + } + } + + private static List> getAuditListByAction(String action, int expectedNumOfAudit) + throws Exception { + List> actionToList = parseAuditResourceByActionToList(action, null); + assertEquals("recieved different audits number than expected", expectedNumOfAudit, actionToList.size()); + return actionToList; + } + + public static void validateAuthenticationAudit(ExpectedAuthenticationAudit expectedAudit) throws Exception { + List> actionToList = getAuditListByAction(expectedAudit.getAction(), 1); + assertEquals("expected number of ES action is 1", 1, actionToList.size()); + + Map map = actionToList.get(0); + validateField(map, AuditEnum.ACTION.getValue(), expectedAudit.getAction()); + validateField(map, AuditEnum.URL.getValue(), expectedAudit.getUrl()); + validateField(map, AuditEnum.USER.getValue(), expectedAudit.getUser()); + validateField(map, AuditEnum.AUTH_STATUS.getValue(), expectedAudit.getAuthStatus()); + validateField(map, AuditEnum.REALM.getValue(), expectedAudit.getRealm()); + + } + + private static void validateField(Map actualAuditRecord, String jsonField, Object expectedValue) { + if (expectedValue == null) { + // || changed to && + if (actualAuditRecord.containsKey(jsonField)) { + assertTrue("Audit field " + jsonField + ": expected null, actual " + actualAuditRecord.get(jsonField), + actualAuditRecord.get(jsonField).toString().equals("null") + || actualAuditRecord.get(jsonField).toString().equals(Constants.EMPTY_STRING)); + } + + } else { + assertTrue("Audit field " + jsonField + " not found in actual", actualAuditRecord.containsKey(jsonField)); + Object foundValue = actualAuditRecord.get(jsonField); + compareElements(expectedValue, foundValue); + } + } + + public static void compareElements(Object expectedValue, Object foundValue) { + if (expectedValue instanceof String) { + assertTrue("Actual value " + foundValue + " is not string", foundValue instanceof String); + assertTrue("Expected " + expectedValue + " not equal to actual " + foundValue, + foundValue.equals(expectedValue)); + } + /* + * else if( expectedValue instanceof Number){ assertTrue(foundValue + * instanceof Number); assertTrue(foundValue == expectedValue); } + */ + else if (expectedValue instanceof Boolean) { + assertTrue(foundValue instanceof Boolean); + assertTrue(foundValue == expectedValue); + } else if (expectedValue instanceof Map) { + assertTrue(foundValue instanceof Map); + Map foundMap = (Map) foundValue; + Map excpectedMap = (Map) expectedValue; + assertTrue("size of maps is not equel", foundMap.size() == excpectedMap.size()); + Iterator foundkeyItr = foundMap.keySet().iterator(); + while (foundkeyItr.hasNext()) { + String foundKey = foundkeyItr.next(); + assertTrue(excpectedMap.containsKey(foundKey)); + compareElements(excpectedMap.get(foundKey), foundMap.get(foundKey)); + } + + } else if (expectedValue instanceof List) { + assertTrue(foundValue instanceof List); + List foundList = (List) foundValue; + List excpectedList = (List) expectedValue; + assertTrue("size of maps is not equel", foundList.size() == excpectedList.size()); + if( foundList.size() > 0 ){ + final Object elementInList = foundList.get(0); + if( !(elementInList instanceof List || elementInList instanceof Map) ){ + List tempList = new ArrayList<>(); + tempList.addAll(foundList); + for(Object expectedObj : excpectedList){ + if( tempList.contains(expectedObj)){ + tempList.remove(expectedObj); + } + else{ + assertTrue(false); + } + } + assertTrue("Lists are not equel", tempList.isEmpty()); + } + } + + } else { + assertTrue(foundValue.equals(expectedValue)); + } + } + + // public static Map parseAuditResourceByAction(String + // action, String body) throws Exception { + // + // Map auditingMessage = null; + // auditingMessage = retrieveAuditMessagesByPattern(action, null); + // + // return auditingMessage; + // + // } + + public static Map parseAuditResourceByAction(String action, Map body) throws Exception { + + Map auditingMessage = null; + auditingMessage = retrieveAuditMessagesByPattern(action, body, false); + + return auditingMessage; + + } + + // public static List> + // parseAuditResourceByActionToList(String action, String body) throws + // Exception { + // + // List> auditList = new ArrayList>(); + // + //// String auditingMessage = null; + // + // Map auditingMessage = null; + // auditingMessage = retrieveAuditMessagesByPattern(action); + // + // if (body == null) { + //// String pattern = "/_search?q=ACTION:\"" + action + "\""; + //// auditingMessage = retrieveAuditMessagesByPattern(action); + //// auditingMessage = retrieveAuditMessagesByPattern(pattern); + // } else { + //// auditingMessage = retrieveAuditMessagesUsingBody(body); + // } + // + // return ResponseParser.getAuditFromMessage(auditingMessage); + // + // } + + public static List> parseAuditResourceByActionToList(String action, + Map body) throws Exception { + + List> auditList = new ArrayList>(); + + // String auditingMessage = null; + + Map auditingMessage = null; + + if (body == null || body.isEmpty()) { + auditingMessage = retrieveAuditMessagesByPattern(action, null, false); + // String pattern = "/_search?q=ACTION:\"" + action + "\""; + // auditingMessage = retrieveAuditMessagesByPattern(action); + // auditingMessage = retrieveAuditMessagesByPattern(pattern); + } else { + auditingMessage = retrieveAuditMessagesByPattern(action, body, false); + // auditingMessage = retrieveAuditMessagesUsingBody(body); + } + + return ResponseParser.getAuditFromMessage(auditingMessage); + + } + + public JSONObject buildElasticQueryStringObject(String defaultField, String queryValue) throws JSONException { + + JSONObject query_string = new JSONObject(); + JSONObject jSONObject = new JSONObject(); + jSONObject.put("default_field", defaultField); + jSONObject.put("query", queryValue); + + query_string.put("query_string", jSONObject); + + return query_string; + } + + public static JSONObject buildElasticQueryBody(List listObjects) throws JSONException { + + JSONObject query = new JSONObject(); + JSONObject bool = new JSONObject(); + JSONObject must = new JSONObject(); + JSONArray mustA = new JSONArray(); + + for (int i = 0; i < listObjects.size(); i++) { + JSONObject match = new JSONObject(); + match.put("match", listObjects.get(i)); + mustA.put(match); + + } + + must.put("must", mustA); + bool.put("bool", must); + query.put("query", bool); + + return query; + } + + public static String retrieveAuditMessagesUsingBody(String query_string) throws IOException { + + Config config = Utils.getConfig(); + HttpRequest getAuditingMessage = new HttpRequest(); + Map headersMap = new HashMap(); + String body = query_string; + + String url = String.format(Urls.GET_SEARCH_DATA_FROM_ES, config.getEsHost(), config.getEsPort(), "_search"); + RestResponse restResponse = getAuditingMessage.httpSendPost(url, body, headersMap); + + return restResponse.getResponse(); + } + + public static Map retrieveAuditMessagesByPattern(String action, Map body, Boolean retryFlag) + throws IOException { + + // get cassandra table name by action + String esType = AuditingActionEnum.getActionByName(action).getAuditingEsType(); + Map resultsMap = new HashMap(); + + List> myFields = new ArrayList>(); + Pair myPair = new Pair( + AuditingFieldsKeysEnum.AUDIT_ACTION, action); + myFields.add(0, myPair); + if (body != null && !body.isEmpty()) { + for (Map.Entry mapElement : body.entrySet()) { + myFields.add(new Pair(mapElement.getKey(), mapElement.getValue())); + } + } + + List fetchFromTable = CassandraUtils.fetchFromTable(auditKeySpaceName, esType, myFields); + if(retryFlag){ + if(fetchFromTable.size() == 0){ + return resultsMap; + } + } +// assertTrue("expected on fetching from data base one record only, actual: " + fetchFromTable.size(), fetchFromTable.size() == 1); + + + + + Row row =null; + + if (fetchFromTable.size() > 1){ + List fetchFromTable2 = fetchFromTable; + fetchFromTable2.sort((p1, p2) -> p1.getTimestamp(1).compareTo(p2.getTimestamp(1))); + row = fetchFromTable2.get(fetchFromTable2.size() - 1); + } + else {row = fetchFromTable.get(0);} + + ColumnDefinitions columnDefinitions = row.getColumnDefinitions(); + + for (int i = 0; i < columnDefinitions.size(); i++) { + resultsMap.put(columnDefinitions.getName(i), row.getObject(columnDefinitions.getName(i)) == null ? "null" + : row.getObject(columnDefinitions.getName(i)).toString()); + } + + return resultsMap; + } + + // public static Map retrieveAuditMessagesByPattern(String pattern) throws + // IOException { + // + //// Config config = Utils.getConfig(); + //// HttpRequest getAuditingMessage = new HttpRequest(); + //// String url = String.format(Urls.GET_SEARCH_DATA_FROM_ES, + // config.getEsHost(), config.getEsPort(), pattern); + //// RestResponse restResponse = getAuditingMessage.httpSendGet(url, null); + // + //// get cassandra table name by action + // String esType = + // AuditingActionEnum.getActionByName(pattern).getAuditingEsType(); + //// AuditingActionEnum actionByName = + // AuditingActionEnum.getActionByName(pattern); + // + //// Map myFields= new + // HashMap(); + //// myFields.put(AuditingFieldsKeysEnum.AUDIT_ACTION , pattern); + // + // List> myFields = new + // ArrayList>(); + // Pair myPair = new + // Pair(AuditingFieldsKeysEnum.AUDIT_ACTION + // , pattern); + // myFields.add(0, myPair); + // + // + // List fetchFromTable = CassandraUtils.fetchFromTable("sdcaudit", + // esType, myFields); + // Row row = fetchFromTable.get(0); + // + // + // ColumnDefinitions columnDefinitions = row.getColumnDefinitions(); + //// String string = row.getString(columnDefinitions.getName(1)); + // + //// String metaData = row.getColumnDefinitions().toString(); + //// metaData =metaData.replaceAll("\\((.*?)\\)|\\[|\\]|Columns", ""); + //// List metaDataList = new + // ArrayList(Arrays.asList(metaData.split(", "))); + // + // + // + // Map resultsMap = new HashMap(); + // + // + // for (int i=0 ; i < columnDefinitions.size() ; i++){ + // resultsMap.put(columnDefinitions.getName(i) , + // row.getObject(columnDefinitions.getName(i)) == null ? "null" : + // row.getObject(columnDefinitions.getName(i)).toString()); + // } + //// for (String string : metaDataList) { + //// resultsMap.put(string , row.getString(string)); + //// } + //// + // + //// String dataString = fetchFromTable.toString(); + //// dataString = dataString.replaceAll("\\[|\\]|Row", ""); + //// List dataArray = new + // ArrayList(Arrays.asList(dataString.split(", "))); + //// + //// + //// Map resultsMap = new HashMap(); + //// for (int i=0 ; i> actionToList = getAuditListByAction(expectedAddUserAuditJavaObject.getAction(), 1); + Map map = actionToList.get(0); + validateField(map, UserAuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map, UserAuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), + expectedAddUserAuditJavaObject.getModifier()); + validateField(map, UserAuditJsonKeysEnum.USER_AFTER.getAuditJsonKeyName(), + expectedAddUserAuditJavaObject.getUserAfter()); + validateField(map, UserAuditJsonKeysEnum.USER_BEFORE.getAuditJsonKeyName(), + expectedAddUserAuditJavaObject.getUserBefore()); + validateField(map, UserAuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), + expectedAddUserAuditJavaObject.getStatus()); + validateField(map, UserAuditJsonKeysEnum.DESC.getAuditJsonKeyName(), expectedAddUserAuditJavaObject.getDesc()); + + } + + private static void categoryAuditFailureInternal(String action, CategoryDefinition categoryDataDefinition, + SubCategoryDefinition subCategoryDefinition, GroupingDefinition groupingDefinition, User user, + ActionStatus errorMessage, int status, String resourceType, Object... variables) throws Exception { + // validate audit + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(errorMessage.name()); + ExpectedCategoryAudit expectedCatrgoryAuditJavaObject = new ExpectedCategoryAudit(); + expectedCatrgoryAuditJavaObject.setAction(action); + expectedCatrgoryAuditJavaObject.setModifier(user.getFullName() + "(" + user.getUserId() + ")"); + expectedCatrgoryAuditJavaObject.setCategoryName(categoryDataDefinition.getName()); + String subCategoryName = (subCategoryDefinition != null ? subCategoryDefinition.getName() + : Constants.EMPTY_STRING); + expectedCatrgoryAuditJavaObject.setSubCategoryName(subCategoryName); + String groupingName = (groupingDefinition != null ? groupingDefinition.getName() : Constants.EMPTY_STRING); + expectedCatrgoryAuditJavaObject.setGroupingName(groupingName); + expectedCatrgoryAuditJavaObject.setResourceType(resourceType); + expectedCatrgoryAuditJavaObject.setStatus(String.valueOf(status)); + expectedCatrgoryAuditJavaObject.setDesc(errorInfo.getAuditDesc(variables)); + AuditValidationUtils.validateCategoryAudit(expectedCatrgoryAuditJavaObject, action); + } + + public static void validateGetCategoryHirarchy(ExpectedCategoryAudit expectedCatrgoryAuditJavaObject, String action) + throws Exception { + + List> actionToList = getAuditListByAction(expectedCatrgoryAuditJavaObject.getAction(), 1); + Map map = actionToList.get(0); + + expectedCatrgoryAuditJavaObject.setModifier(getModifierString(expectedCatrgoryAuditJavaObject.getModifierName(), + expectedCatrgoryAuditJavaObject.getModifierUid())); + validateField(map, CategoryAuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map, CategoryAuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getModifier()); + validateField(map, CategoryAuditJsonKeysEnum.DETAILS.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getDetails()); + validateField(map, CategoryAuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getStatus()); + validateField(map, CategoryAuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getDesc()); + + } + + public static void validateCategoryAudit(ExpectedCategoryAudit expectedCatrgoryAuditJavaObject, String action) + throws Exception { + + List> actionToList = getAuditListByAction(expectedCatrgoryAuditJavaObject.getAction(), 1); + Map map = actionToList.get(0); + validateField(map, CategoryAuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map, CategoryAuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getModifier()); + validateField(map, CategoryAuditJsonKeysEnum.CATEGORY_NAME.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getCategoryName()); + validateField(map, CategoryAuditJsonKeysEnum.SUB_CATEGORY_NAME.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getSubCategoryName()); + validateField(map, CategoryAuditJsonKeysEnum.GROUPING_NAME.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getGroupingName()); + validateField(map, CategoryAuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getResourceType()); + validateField(map, CategoryAuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getStatus()); + validateField(map, CategoryAuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), + expectedCatrgoryAuditJavaObject.getDesc()); + } + + public static void GetCategoryHierarchyAuditSuccess(String action, String componentType, User user, int status) + throws Exception { + ExpectedGetUserListAudit expectedGetListOfUsersAuditJavaObject = new ExpectedGetUserListAudit(); + expectedGetListOfUsersAuditJavaObject.setAction(action); + expectedGetListOfUsersAuditJavaObject.setStatus(String.valueOf(status)); + expectedGetListOfUsersAuditJavaObject.setDesc("OK"); + expectedGetListOfUsersAuditJavaObject.setModifier(user.getFullName() + "(" + user.getUserId() + ")"); + expectedGetListOfUsersAuditJavaObject.setDetails(componentType.toLowerCase()); + validateAuditGetListOfUsersByRoles(expectedGetListOfUsersAuditJavaObject, action); + } + + public static String buildArtifactDataAudit(ArtifactDefinition artifactDefinition) { + StringBuilder sb = new StringBuilder(); + if (artifactDefinition.getTimeout() == null) { + artifactDefinition.setTimeout(0); + } + if (artifactDefinition != null) { + sb.append(artifactDefinition.getArtifactGroupType() == null ? null + : artifactDefinition.getArtifactGroupType().getType()).append(",").append("'") + .append(artifactDefinition.getArtifactLabel()).append("'").append(",") + .append(artifactDefinition.getArtifactType()).append(",") + .append(artifactDefinition.getArtifactName()).append(",").append(artifactDefinition.getTimeout()) + .append(",").append(artifactDefinition.getEsId()); + sb.append(","); + if (artifactDefinition.getArtifactVersion() != null) { + sb.append(artifactDefinition.getArtifactVersion()); + } else { + sb.append(" "); + } + sb.append(","); + if (artifactDefinition.getArtifactUUID() != null) { + sb.append(artifactDefinition.getArtifactUUID()); + } else { + sb.append(" "); + } + } + + return sb.toString(); + } + + public static ExpectedResourceAuditJavaObject expectedMissingInformationAuditObject(String Action, + String resourceUid, ComponentType resourceType) throws FileNotFoundException { + ExpectedResourceAuditJavaObject expectedAudit = new ExpectedResourceAuditJavaObject(); + expectedAudit.setAction(Action); + expectedAudit.setResourceName(resourceUid); + expectedAudit.setResourceType(resourceType.getValue()); + expectedAudit.setPrevVersion(""); + expectedAudit.setCurrVersion(""); + expectedAudit.setModifierName(""); + expectedAudit.setModifierUid(""); + expectedAudit.setPrevState(""); + expectedAudit.setCurrState(""); + expectedAudit.setPrevArtifactUuid(""); + expectedAudit.setCurrArtifactUuid(""); + expectedAudit.setArtifactData(""); + expectedAudit.setStatus("403"); + expectedAudit.setDesc(buildAuditDescription( + new ErrorValidationUtils().parseErrorConfigYaml(ActionStatus.MISSING_INFORMATION.name()), + new ArrayList())); + return expectedAudit; + } + + public static ExpectedResourceAuditJavaObject expectedComponentNotFoundAuditObject(String Action, + String resourceUid, ComponentType resourceType, String artifactUid, User user, + ArrayList notFoundComponent) throws FileNotFoundException { + String desc = null; + + ExpectedResourceAuditJavaObject expectedAudit = new ExpectedResourceAuditJavaObject(); + expectedAudit.setAction(Action); + expectedAudit.setResourceName(resourceUid); + expectedAudit.setResourceType(resourceType.getValue()); + expectedAudit.setPrevVersion(""); + expectedAudit.setCurrVersion(""); + expectedAudit.setModifierName(user.getFirstName() + " " + user.getLastName()); + expectedAudit.setModifierUid(user.getUserId()); + expectedAudit.setPrevState(""); + expectedAudit.setCurrState(""); + expectedAudit.setPrevArtifactUuid(""); + expectedAudit.setCurrArtifactUuid(artifactUid); + expectedAudit.setArtifactData(""); + expectedAudit.setStatus("404"); + + if (resourceType.getValue() == ComponentType.SERVICE.getValue()) { + desc = buildAuditDescription( + new ErrorValidationUtils().parseErrorConfigYaml(ActionStatus.SERVICE_NOT_FOUND.name()), + notFoundComponent); + } else if (resourceType.getValue() == ComponentType.RESOURCE.getValue()) + desc = buildAuditDescription( + new ErrorValidationUtils().parseErrorConfigYaml(ActionStatus.RESOURCE_NOT_FOUND.name()), + notFoundComponent); + + expectedAudit.setDesc(desc); + return expectedAudit; + } + + public static ExpectedResourceAuditJavaObject expectedArtifactNotFoundAuditObject(String Action, String resourceUid, + ComponentType resourceType, String artifactUid, User user, String currState, String currVersion) + throws FileNotFoundException { + String desc = null; + + ExpectedResourceAuditJavaObject expectedAudit = new ExpectedResourceAuditJavaObject(); + expectedAudit.setAction(Action); + expectedAudit.setResourceName(resourceUid); + expectedAudit.setResourceType(resourceType.getValue()); + expectedAudit.setPrevVersion(""); + expectedAudit.setCurrVersion(currVersion); + expectedAudit.setModifierName(user.getFirstName() + " " + user.getLastName()); + expectedAudit.setModifierUid(user.getUserId()); + expectedAudit.setPrevState(""); + expectedAudit.setCurrState(currState); + expectedAudit.setPrevArtifactUuid(""); + expectedAudit.setCurrArtifactUuid(artifactUid); + expectedAudit.setArtifactData(""); + expectedAudit.setStatus("404"); + + desc = buildAuditDescription( + new ErrorValidationUtils().parseErrorConfigYaml(ActionStatus.ARTIFACT_NOT_FOUND.name()), + Arrays.asList("")); + + expectedAudit.setDesc(desc); + return expectedAudit; + } + + public static ExpectedResourceAuditJavaObject expectedArtifactNotFoundAuditObject(String Action, + String resourceName, ComponentType resourceType, String artifactUid, LifecycleStateEnum lifecycle, + User user, String currVersion) throws FileNotFoundException { + String desc = null; + + ExpectedResourceAuditJavaObject expectedAudit = new ExpectedResourceAuditJavaObject(); + expectedAudit.setAction(Action); + expectedAudit.setResourceName(resourceName); + expectedAudit.setResourceType(resourceType.getValue()); + expectedAudit.setPrevVersion(""); + expectedAudit.setCurrVersion(currVersion); + expectedAudit.setModifierName(user.getFirstName() + " " + user.getLastName()); + expectedAudit.setModifierUid(user.getUserId()); + expectedAudit.setPrevState(""); + expectedAudit.setCurrState(lifecycle.name()); + expectedAudit.setPrevArtifactUuid(""); + expectedAudit.setCurrArtifactUuid(artifactUid); + expectedAudit.setArtifactData(""); + expectedAudit.setStatus("404"); + + desc = buildAuditDescription( + new ErrorValidationUtils().parseErrorConfigYaml(ActionStatus.ARTIFACT_NOT_FOUND.name()), + new ArrayList()); + + expectedAudit.setDesc(desc); + return expectedAudit; + } + + public static ExpectedResourceAuditJavaObject expectedRestrictedOperationAuditObject(String Action, + String resourceNameOrUid, ComponentType resourceType, String artifactUid, User user, String currVersion, + String currState) throws FileNotFoundException { + String desc = null; + + ExpectedResourceAuditJavaObject expectedAudit = new ExpectedResourceAuditJavaObject(); + expectedAudit.setAction(Action); + expectedAudit.setResourceName(resourceNameOrUid); + expectedAudit.setResourceType(resourceType.getValue()); + expectedAudit.setPrevVersion(""); + expectedAudit.setCurrVersion(currVersion); + expectedAudit.setModifierName(user.getFirstName() + " " + user.getLastName()); + expectedAudit.setModifierUid(user.getUserId()); + expectedAudit.setPrevState(""); + expectedAudit.setCurrState(currState); + expectedAudit.setPrevArtifactUuid(""); + expectedAudit.setCurrArtifactUuid(artifactUid); + expectedAudit.setArtifactData(""); + expectedAudit.setStatus("409"); + + desc = buildAuditDescription( + new ErrorValidationUtils().parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()), + new ArrayList()); + + expectedAudit.setDesc(desc); + return expectedAudit; + } + + public static ExpectedResourceAuditJavaObject expectedInvalidContentAuditObject(String Action, String resourceName, + ComponentType resourceType, String artifactUid, User user, String currVersion, String currState, + ArrayList invalidContentList) throws FileNotFoundException { + return expectedInvalidContentAuditObject(ActionStatus.INVALID_CONTENT, Action, resourceName, resourceType, + artifactUid, user, currVersion, currState, invalidContentList); + } + + public static ExpectedResourceAuditJavaObject expectedInvalidContentAuditObject(ActionStatus actionStatus, + String Action, String resourceName, ComponentType resourceType, String artifactUid, User user, + String currVersion, String currState, ArrayList invalidContentList) throws FileNotFoundException { + String desc = null; + + ExpectedResourceAuditJavaObject expectedAudit = new ExpectedResourceAuditJavaObject(); + expectedAudit.setAction(Action); + expectedAudit.setResourceName(resourceName); + expectedAudit.setResourceType(resourceType.getValue()); + expectedAudit.setPrevVersion(""); + expectedAudit.setCurrVersion(currVersion); + expectedAudit.setModifierName(user.getFirstName() + " " + user.getLastName()); + expectedAudit.setModifierUid(user.getUserId()); + expectedAudit.setPrevState(""); + expectedAudit.setCurrState(currState); + expectedAudit.setPrevArtifactUuid(""); + expectedAudit.setCurrArtifactUuid(artifactUid); + expectedAudit.setArtifactData(""); + expectedAudit.setStatus("400"); + + desc = buildAuditDescription(new ErrorValidationUtils().parseErrorConfigYaml(actionStatus.name()), + invalidContentList); + + expectedAudit.setDesc(desc); + return expectedAudit; + } + + public static ExpectedResourceAuditJavaObject expectedSuccessAuditObject(String Action, String resourceName, + ComponentType resourceType, ArtifactReqDetails artifactReq, User user, String currVersion, String currState, + String prevArtifactUuid) throws FileNotFoundException { + ExpectedResourceAuditJavaObject expectedAudit = new ExpectedResourceAuditJavaObject(); + expectedAudit.setAction(Action); + expectedAudit.setResourceName(resourceName); + expectedAudit.setResourceType(resourceType.getValue()); + expectedAudit.setPrevVersion(""); + expectedAudit.setCurrVersion(currVersion); + expectedAudit.setModifierName(user.getFirstName() + " " + user.getLastName()); + expectedAudit.setModifierUid(user.getUserId()); + expectedAudit.setPrevState(""); + expectedAudit.setCurrState(currState); + expectedAudit.setPrevArtifactUuid(prevArtifactUuid); + expectedAudit.setCurrArtifactUuid(artifactReq.getUniqueId()); + expectedAudit + .setArtifactData(buildArtifactDataAudit(ArtifactUtils.convertArtifactReqToDefinition(artifactReq))); + expectedAudit.setStatus("200"); + expectedAudit.setDesc("OK"); + return expectedAudit; + } + + public static JSONObject filterAuditByUuid(String action, String uuid) throws Exception { + Map actionMap = new HashMap(); + actionMap.put("ACTION", action); + JSONObject actionJsonObject = new JSONObject(actionMap); + Map uuidMap = new HashMap(); + uuidMap.put("SERVICE_INSTANCE_ID", uuid); + JSONObject uuidJsonObject = new JSONObject(uuidMap); + + List filters = new ArrayList(Arrays.asList(actionJsonObject, uuidJsonObject)); + JSONObject body = buildElasticQueryBody(filters); + return body; + } + + public static void validateAudit(ExpectedResourceAuditJavaObject resourceAuditJavaObject, String action) + throws Exception { + List> actionToList = getAuditListByAction(resourceAuditJavaObject.getAction(), 1); + Map map2 = actionToList.get(0); + validateField(map2, AuditJsonKeysEnum.ACTION.getAuditJsonKeyName(), action); + validateField(map2, AuditJsonKeysEnum.RESOURCE_NAME.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceName()); + validateField(map2, AuditJsonKeysEnum.RESOURCE_TYPE.getAuditJsonKeyName(), + resourceAuditJavaObject.getResourceType()); + validateField(map2, AuditJsonKeysEnum.PREV_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getPrevVersion()); + validateField(map2, AuditJsonKeysEnum.CURR_VERSION.getAuditJsonKeyName(), + resourceAuditJavaObject.getCurrVersion()); + validateField(map2, AuditJsonKeysEnum.MODIFIER.getAuditJsonKeyName(), resourceAuditJavaObject.getMODIFIER()); + validateField(map2, AuditJsonKeysEnum.PREV_STATE.getAuditJsonKeyName(), resourceAuditJavaObject.getPrevState()); + validateField(map2, AuditJsonKeysEnum.CURR_STATE.getAuditJsonKeyName(), resourceAuditJavaObject.getCurrState()); + validateField(map2, AuditJsonKeysEnum.STATUS.getAuditJsonKeyName(), resourceAuditJavaObject.getStatus()); + validateField(map2, AuditJsonKeysEnum.DESCRIPTION.getAuditJsonKeyName(), resourceAuditJavaObject.getDesc()); + validateField(map2, AuditJsonKeysEnum.COMMENT.getAuditJsonKeyName(), resourceAuditJavaObject.getComment()); + } + + ////// service audit validation///////////////////// + + public static ExpectedResourceAuditJavaObject constructFieldsForAuditValidation(ServiceReqDetails serviceReqDetails, + String serviceVersion, User sdncUserDetails) { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + + expectedResourceAuditJavaObject.setAction("Create"); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + String userFirstLastName = sdncUserDetails.getFirstName() + " " + sdncUserDetails.getLastName(); + expectedResourceAuditJavaObject.setModifierName(userFirstLastName); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setResourceName(serviceReqDetails.getName()); + expectedResourceAuditJavaObject.setResourceType("Service"); + expectedResourceAuditJavaObject.setPrevVersion(String.valueOf(Float.parseFloat(serviceVersion) - 0.1f)); + expectedResourceAuditJavaObject.setCurrVersion(serviceVersion); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setComment(null); + + return expectedResourceAuditJavaObject; + + } + + public static ExpectedResourceAuditJavaObject constructFieldsForAuditValidation(ServiceReqDetails serviceReqDetails, + String serviceVersion, User sdncUserDetails, ActionStatus errorStatus, List variables) + throws FileNotFoundException { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = constructFieldsForAuditValidation( + serviceReqDetails, serviceVersion, sdncUserDetails); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(errorStatus.name()); + + expectedResourceAuditJavaObject.setStatus(errorInfo.getCode().toString()); + String auditDesc = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + expectedResourceAuditJavaObject.setDesc(auditDesc); + + return expectedResourceAuditJavaObject; + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/BaseValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/BaseValidationUtils.java new file mode 100644 index 0000000000..0d49d97302 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/BaseValidationUtils.java @@ -0,0 +1,117 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertEquals; + +import java.io.FileNotFoundException; +import java.util.Arrays; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.exception.ResponseFormat; +import org.testng.Assert; + +public class BaseValidationUtils { + + public static final int STATUS_CODE_SUCCESS = 200; + public static final int STATUS_CODE_CREATED = 201; + public static final int STATUS_CODE_DELETE = 204; + public static final int STATUS_CODE_NOT_FOUND = 404; + public static final int STATUS_CODE_SUCCESS_NO_CONTENT = 204; + public static final int STATUS_CODE_SUCCESS_DELETE = 204; + public static final int STATUS_CODE_INVALID_CONTENT = 400; + public static final int STATUS_CODE_MISSING_DATA = 400; + public static final int STATUS_CODE_MISSING_INFORMATION = 403; + public static final int STATUS_CODE_RESTRICTED_ACCESS = 403; + public static final int STATUS_CODE_RESTRICTED_OPERATION = 409; + public static final int STATUS_CODE_ALREADY_EXISTS = 409; + + // ------ + protected static Boolean checkErrorCode(RestResponse deleteResponse) { + if (deleteResponse.getErrorCode() == STATUS_CODE_SUCCESS + || deleteResponse.getErrorCode() == STATUS_CODE_DELETE) { + return true; + } + return false; + } + + // *** STATUS CODE VALIDATION UTIITIES **** + public static void checkStatusCode(RestResponse response, String assertMessage, boolean AND, int... statuses) { + int statusCode = response.getErrorCode(); + for (int status : statuses) { + if (AND && statusCode != status) { + Assert.fail(assertMessage + " status: " + statusCode); + } else if (statusCode == status) { + return; + } + } + if (!AND) { + Assert.fail(assertMessage + " status: " + statusCode); + } + } + + public static void checkDeleteResponse(RestResponse response) { + checkStatusCode(response, "delete request failed", false, STATUS_CODE_DELETE, STATUS_CODE_NOT_FOUND, + STATUS_CODE_SUCCESS); // STATUS_CODE_SUCCESS for deActivate user + } + + public static void checkCreateResponse(RestResponse response) { + checkStatusCode(response, "create request failed", false, STATUS_CODE_CREATED); + } + + public static void checkSuccess(RestResponse response) { + checkStatusCode(response, "request failed", false, STATUS_CODE_SUCCESS); + } + + public static void checkErrorResponse(RestResponse errorResponse, ActionStatus actionStatus, + String... expectedVariables) throws FileNotFoundException { + // Expected error + ErrorInfo expectedError = ErrorValidationUtils.parseErrorConfigYaml(actionStatus.name()); + String expectedMessage = expectedError.getMessage(); + + // Actual error + ResponseFormat responseFormat = ResponseParser.parseToObjectUsingMapper(errorResponse.getResponse(), + ResponseFormat.class); + String actualMessage = responseFormat.getText(); + String[] actualVariables = responseFormat.getVariables(); + + assertEquals("Unexpected error message", expectedMessage, actualMessage); + assertEquals("Unexpected error variables", Arrays.asList(expectedVariables), Arrays.asList(actualVariables)); + } + + public static void checkErrorMessageResponse(RestResponse errorResponse, ActionStatus actionStatus) + throws FileNotFoundException { + // Expected error + ErrorInfo expectedError = ErrorValidationUtils.parseErrorConfigYaml(actionStatus.name()); + String expectedMessage = expectedError.getMessage(); + + // Actual error + ResponseFormat responseFormat = ResponseParser.parseToObjectUsingMapper(errorResponse.getResponse(), + ResponseFormat.class); + String actualMessage = responseFormat.getText(); + + assertEquals("Unexpected error message", expectedMessage, actualMessage); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/CategoryValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/CategoryValidationUtils.java new file mode 100644 index 0000000000..d63a514b3a --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/CategoryValidationUtils.java @@ -0,0 +1,125 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.assertEquals; +import org.json.JSONObject; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils; + +public class CategoryValidationUtils { + + public static void verifyCategoryExistInGetResponse(RestResponse getAllCategoryRest, + CategoryDefinition categoryDefinition) { + + int categoriesNum = CategoryRestUtils.getMatchingCategoriesNum(getAllCategoryRest, categoryDefinition); + assertEquals("category " + categoryDefinition.getName() + " not found during get or found more than once", 1, + categoriesNum); + } + + public static void verifyCategoryNotExistsInGetResponse(RestResponse getAllCategoryRest, + CategoryDefinition categoryDefinition) { + + int categoriesNum = CategoryRestUtils.getMatchingCategoriesNum(getAllCategoryRest, categoryDefinition); + assertEquals("category " + categoryDefinition.getName() + " should't be found during get", 0, categoriesNum); + } + + public static void verifySubCategoryExistInGetResponse(RestResponse getAllCategoryRest, String parentCategoryId, + SubCategoryDefinition expectedSubCategoryDefinition) { + + int subCategoriesNum = CategoryRestUtils.getMatchingSubCategoriesNum(getAllCategoryRest, parentCategoryId, + expectedSubCategoryDefinition); + assertEquals( + "sub-category " + expectedSubCategoryDefinition.getName() + + " not found during get or found more than once for parentId " + parentCategoryId, + 1, subCategoriesNum); + } + + public static void verifyGroupingExistInGetResponse(RestResponse getAllCategoryRest, String parentCategoryId, + String subCategoryId, GroupingDefinition expectedGroupingDefinition) { + + int groupingNum = CategoryRestUtils.getMatchingGroupingNum(getAllCategoryRest, parentCategoryId, subCategoryId, + expectedGroupingDefinition); + assertEquals( + "sub-category " + expectedGroupingDefinition.getName() + + " not found during get or found more than once for parentId " + parentCategoryId, + 1, groupingNum); + } + + public static void verifyGroupingNotExistInGetResponse(RestResponse getAllCategoryRest, String parentCategoryId, + String subCategoryId, GroupingDefinition expectedGroupingDefinition) { + + int groupingNum = CategoryRestUtils.getMatchingGroupingNum(getAllCategoryRest, parentCategoryId, subCategoryId, + expectedGroupingDefinition); + assertEquals( + "sub-category " + expectedGroupingDefinition.getName() + + " not found during get or found more than once for parentId " + parentCategoryId, + 0, groupingNum); + } + + public static void verifySubCategoryNotExistsInGetResponse(RestResponse getAllCategoryRest, String parentCategoryId, + SubCategoryDefinition expectedSubCategoryDefinition) { + + int subCategoriesNum = CategoryRestUtils.getMatchingSubCategoriesNum(getAllCategoryRest, parentCategoryId, + expectedSubCategoryDefinition); + assertEquals("sub-category " + expectedSubCategoryDefinition.getName() + + " should't be found during get for parentId " + parentCategoryId, 0, subCategoriesNum); + } + + /// NEE Benny + public static void validateCreateGroupResponse(RestResponse createSubCategoryRest, + GroupingDefinition expectedGroupDefinition) throws Exception { + + String response = createSubCategoryRest.getResponse(); + JSONObject jobject = new JSONObject(response); + assertTrue(jobject.get("name").equals(expectedGroupDefinition.getName())); + assertTrue(jobject.get("normalizedName").equals(expectedGroupDefinition.getNormalizedName())); + // assertNotNull(jobject.get("normalizedName")); + assertNotNull(jobject.get("uniqueId")); + expectedGroupDefinition.setUniqueId(jobject.get("uniqueId").toString()); + + } + + public static void validateCreateSubCategoryResponse(RestResponse createSubCategoryRest, + SubCategoryDefinition expectedSubCategoryDefinition) throws Exception { + + String response = createSubCategoryRest.getResponse(); + JSONObject jobject = new JSONObject(response); + assertTrue(jobject.get("name").equals(expectedSubCategoryDefinition.getName())); + assertNotNull(jobject.get("normalizedName")); + assertNotNull(jobject.get("uniqueId")); + } + + public static void validateCreateCategoryResponse(RestResponse createCategoryRest, + CategoryDefinition expectedCategoryDefinition) throws Exception { + String response = createCategoryRest.getResponse(); + JSONObject jobject = new JSONObject(response); + assertTrue(jobject.get("name").equals(expectedCategoryDefinition.getName())); + assertTrue(jobject.get("normalizedName").equals(expectedCategoryDefinition.getNormalizedName())); + assertNotNull(jobject.get("uniqueId")); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/CsarValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/CsarValidationUtils.java new file mode 100644 index 0000000000..0fe11537e4 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/CsarValidationUtils.java @@ -0,0 +1,488 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.ci.tests.datatypes.GroupHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.TypeHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.utils.CsarParserUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ImportRestUtils; +import org.openecomp.sdc.common.rest.api.RestResponseAsByteArray; +import org.openecomp.sdc.common.util.ZipUtil; + +public class CsarValidationUtils { + + public static String getCsarPayload(String csarName, String fileLocation) throws Exception { + + RestResponseAsByteArray csar = ImportRestUtils.getCsar(csarName, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + assertTrue("Return response code different from 200", csar.getHttpStatusCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + Map readZip = null; + byte[] data = csar.getResponse(); + if (data != null && data.length > 0) { + readZip = ZipUtil.readZip(data); + + } + byte[] artifactsBs = readZip.get(fileLocation); + String str = new String(artifactsBs, StandardCharsets.UTF_8); + return str; + + } + + public static String getCsarPayload(File csarName, String fileLocation) throws Exception { + +// RestResponseAsByteArray csar = ImportRestUtils.getCsar(csarName, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); +// assertTrue("Return response code different from 200", csar.getHttpStatusCode() == BaseRestUtils.STATUS_CODE_SUCCESS); + Map readZip = null; + Path path = csarName.toPath(); + + byte[] data = Files.readAllBytes(path); + if (data != null && data.length > 0) { + readZip = ZipUtil.readZip(data); + } + byte[] artifactsBs = readZip.get(fileLocation); + String str = new String(artifactsBs, StandardCharsets.UTF_8); + return str; + + } + + public static void validateCsarVfArtifact(String csarUUID, Resource resource) throws Exception { + + List listTypeHeatMetaDefinition = CsarParserUtils.getListTypeHeatMetaDefinition(csarUUID); + assertTrue( + "check group count, expected: " + getGroupCount(listTypeHeatMetaDefinition) + ", actual: " + + resource.getGroups().size(), + getGroupCount(listTypeHeatMetaDefinition) == resource.getGroups().size()); + assertTrue( + "check artifact count, expected: " + getArtifactCount(listTypeHeatMetaDefinition, false) + ", actual: " + + resource.getDeploymentArtifacts().size(), + getArtifactCount(listTypeHeatMetaDefinition, false) == resource.getDeploymentArtifacts().size()); + + } + + /*public static List getListTypeHeatMetaDefinition(String csarUUID) throws Exception { + + String artifactHeatMetaLocation = "Artifacts/HEAT.meta"; + JSONParser parser = new JSONParser(); + String csarPayload = getCsarPayload(csarUUID, artifactHeatMetaLocation); + if (csarPayload != null) { + Object parse = parser.parse(csarPayload); + JSONObject jsonObject = (JSONObject) parse; + JSONObject jsonObjectImportStructure = (JSONObject) jsonObject.get("importStructure"); + List listHeatMetaDefenition = new ArrayList(); + listHeatMetaDefenition = getArtifactsByGroup(jsonObjectImportStructure, listHeatMetaDefenition); + return listHeatMetaDefenition; + } + return null; + + }*/ + + /*public static List getListTypeHeatMetaDefinition(File csarUUID) throws Exception { + + String artifactHeatMetaLocation = "Artifacts/HEAT.meta"; + JSONParser parser = new JSONParser(); + String csarPayload = getCsarPayload(csarUUID, artifactHeatMetaLocation); + if (csarPayload != null) { + Object parse = parser.parse(csarPayload); + JSONObject jsonObject = (JSONObject) parse; + JSONObject jsonObjectImportStructure = (JSONObject) jsonObject.get("importStructure"); + List listHeatMetaDefenition = new ArrayList(); + listHeatMetaDefenition = getArtifactsByGroup(jsonObjectImportStructure, listHeatMetaDefenition); + return listHeatMetaDefenition; + } + return null; + + }*/ + + private static Integer getGroupCount(List listHeatMetaDefenition) { + int count = 0; + for (TypeHeatMetaDefinition typeHeatMetaDefinition : listHeatMetaDefenition) { + count = count + typeHeatMetaDefinition.getGroupHeatMetaDefinition().size(); + } + return count; + } + + private static Integer getArtifactCount(List listHeatMetaDefenition, Boolean isEnvIncluded) { + int count = 0; + List uniqeArtifactList = new ArrayList<>(); + + for (TypeHeatMetaDefinition typeHeatMetaDefinition : listHeatMetaDefenition) { + for (GroupHeatMetaDefinition groupHeatMetaDefinition : typeHeatMetaDefinition + .getGroupHeatMetaDefinition()) { + if (isEnvIncluded) { + count = count + groupHeatMetaDefinition.getArtifactList().size(); + } else { + for (HeatMetaFirstLevelDefinition fileName : groupHeatMetaDefinition.getArtifactList()) { + if (!fileName.getFileName().contains(".env") && !uniqeArtifactList.contains(fileName)) { + uniqeArtifactList.add(fileName); + count = count + 1; + } + } + } + } + } + return count; + } + + /*protected static List getArtifactsByGroup(JSONObject jsonObjectImportStructure, List listHeatMetaDefenition) { + + @SuppressWarnings("unchecked") + Set typeSet = jsonObjectImportStructure.keySet(); + for (Object type : typeSet) { + TypeHeatMetaDefinition heatMetaDefenition = new TypeHeatMetaDefinition(); + log.debug(type.toString()); + log.debug("{}", jsonObjectImportStructure.get(type)); + JSONArray array = (JSONArray) jsonObjectImportStructure.get(type); + heatMetaDefenition.setTypeName((String) type); + List groupHeatMetaDefinitions = new ArrayList(); + heatMetaDefenition.setGroupHeatMetaDefinition(fetchArtifactByGroupFromJsonArray(array, groupHeatMetaDefinitions, true, false)); + listHeatMetaDefenition.add(heatMetaDefenition); + } + return listHeatMetaDefenition; + }*/ + +/* protected static List fetchArtifactByGroupFromJsonArray(JSONArray array, List listGroupHeatMetaDefinition, Boolean openNewGroup, Boolean isNested) { + + GroupHeatMetaDefinition groupHeatMetaDefinition; + + if (array != null) { + for (int i = 0; i < array.size(); i++) { + if (openNewGroup) { + groupHeatMetaDefinition = new GroupHeatMetaDefinition(); + int groupNumber = listGroupHeatMetaDefinition.size() + 1; + log.debug("groupName={}", groupNumber); + groupHeatMetaDefinition.setGroup(groupNumber); + listGroupHeatMetaDefinition.add(groupHeatMetaDefinition); + PropertyHeatMetaDefinition propertyHeatMetaDefinition = new PropertyHeatMetaDefinition(); + propertyHeatMetaDefinition.setName("isBase"); + propertyHeatMetaDefinition.setValue(false); + groupHeatMetaDefinition.setPropertyHeatMetaDefinition(propertyHeatMetaDefinition); + } + groupHeatMetaDefinition = listGroupHeatMetaDefinition.get(listGroupHeatMetaDefinition.size() - 1); + JSONObject jsonObject = (JSONObject) array.get(i); + fetchArtifactByGroupFromJsonObject(listGroupHeatMetaDefinition, groupHeatMetaDefinition, jsonObject, isNested); + } + } + return listGroupHeatMetaDefinition; + }*/ + + + /*public static void fetchArtifactByGroupFromJsonObject(List listGroupHeatMetaDefinition, GroupHeatMetaDefinition groupHeatMetaDefinition, JSONObject jsonObject, Boolean isNested) { + @SuppressWarnings("unchecked") + Set groupsKey = jsonObject.keySet(); + for (Object groupKey : groupsKey) { + String groupKeyStr = (String) groupKey; + if (groupKeyStr.equals("isBase")) { + PropertyHeatMetaDefinition propertyHeatMetaDefinition = new PropertyHeatMetaDefinition(); + propertyHeatMetaDefinition.setName(groupKeyStr); + propertyHeatMetaDefinition.setValue((boolean) jsonObject.get(groupKeyStr)); + if (!groupHeatMetaDefinition.getPropertyHeatMetaDefinition().equals(propertyHeatMetaDefinition)) { + groupHeatMetaDefinition.getPropertyHeatMetaDefinition().setValue((boolean) jsonObject.get(groupKeyStr)); + } + } + if (groupKeyStr.equals("fileName")) { + String artifactName = (String) jsonObject.get(groupKeyStr); + String artifactType = ArtifactTypeEnum.HEAT_ARTIFACT.getType(); + if(isNested){ + artifactType = ArtifactTypeEnum.HEAT_NESTED.getType(); + } + if(jsonObject.get("type") != null && isNested == false){ + artifactType = (String) jsonObject.get("type"); + } + HeatMetaFirstLevelDefinition heatMetaFirstLevelDefinition = new HeatMetaFirstLevelDefinition(artifactName, artifactType); + List listArtifactNames = groupHeatMetaDefinition.getArtifactList(); + listArtifactNames.add(heatMetaFirstLevelDefinition); + groupHeatMetaDefinition.setArtifactList(listArtifactNames); + } else { + if((groupKeyStr.equals("env"))){ + if (jsonObject.get(groupKeyStr) instanceof JSONObject){ + fetchArtifactByGroupFromJsonObject(listGroupHeatMetaDefinition, groupHeatMetaDefinition, (JSONObject) jsonObject.get(groupKeyStr), false); + }else{ + assertTrue("Expected object is JSONObject, but actual: " + jsonObject.get(groupKeyStr).getClass(), jsonObject.get(groupKeyStr).getClass().equals("JSONObject")); + } + } + if((groupKeyStr.equals("nested"))){ + if (jsonObject.get(groupKeyStr) instanceof JSONArray){ + fetchArtifactByGroupFromJsonArray((JSONArray) jsonObject.get(groupKeyStr), listGroupHeatMetaDefinition, false, true); + }else{ + assertTrue("Expected object is JSONArray, but actual: " + jsonObject.get(groupKeyStr).getClass(), jsonObject.get(groupKeyStr).getClass().equals("JSONArray")); + } + + }else if (!(groupKeyStr.equals("isBase") || groupKeyStr.equals("type") || groupKeyStr.equals("env"))) { + if (jsonObject.get(groupKeyStr) instanceof JSONArray){ + fetchArtifactByGroupFromJsonArray((JSONArray) jsonObject.get(groupKeyStr), listGroupHeatMetaDefinition, false, false); + }else{ + assertTrue("Expected object is JSONArray, but actual: " + jsonObject.get(groupKeyStr).getClass(), jsonObject.get(groupKeyStr).getClass().equals("JSONArray")); + } + } + } + } + }*/ + + /*public static List getListTypeHeatMetaDefinition(String csarUUID) throws Exception { + + String artifactHeatMetaLocation = "Artifacts/HEAT.meta"; + JSONParser parser = new JSONParser(); + String csarPayload = getCsarPayload(csarUUID, artifactHeatMetaLocation); + if (csarPayload != null) { + Object parse = parser.parse(csarPayload); + JSONObject jsonObject = (JSONObject) parse; + JSONObject jsonObjectImportStructure = (JSONObject) jsonObject.get("importStructure"); + List listHeatMetaDefenition = new ArrayList(); + listHeatMetaDefenition = getArtifactsByGroup(jsonObjectImportStructure, listHeatMetaDefenition); + return listHeatMetaDefenition; + } + return null; + + } + + protected static List getArtifactsByGroup(JSONObject jsonObjectImportStructure, + List listHeatMetaDefenition) { + + @SuppressWarnings("unchecked") + Set typeSet = jsonObjectImportStructure.keySet(); + for (Object type : typeSet) { + TypeHeatMetaDefinition heatMetaDefenition = new TypeHeatMetaDefinition(); + log.debug(type.toString()); + log.debug("{}", jsonObjectImportStructure.get(type)); + JSONArray array = (JSONArray) jsonObjectImportStructure.get(type); + heatMetaDefenition.setTypeName((String) type); + List groupHeatMetaDefinitions = new ArrayList(); + heatMetaDefenition.setGroupHeatMetaDefinition(fetchArtifactByGroup(array, groupHeatMetaDefinitions, true)); + listHeatMetaDefenition.add(heatMetaDefenition); + } + return listHeatMetaDefenition; + } + + protected static List fetchArtifactByGroup(JSONArray array, + List listGroupHeatMetaDefinition, Boolean openNewGroup) { + + GroupHeatMetaDefinition groupHeatMetaDefinition; + + if (array != null) { + for (int i = 0; i < array.size(); i++) { + if (openNewGroup) { + groupHeatMetaDefinition = new GroupHeatMetaDefinition(); + int groupNumber = listGroupHeatMetaDefinition.size() + 1; + log.debug("groupName={}", groupNumber); + groupHeatMetaDefinition.setGroup(groupNumber); + listGroupHeatMetaDefinition.add(groupHeatMetaDefinition); + PropertyHeatMetaDefinition propertyHeatMetaDefinition = new PropertyHeatMetaDefinition(); + propertyHeatMetaDefinition.setName("isBase"); + propertyHeatMetaDefinition.setValue(false); + groupHeatMetaDefinition.setPropertyHeatMetaDefinition(propertyHeatMetaDefinition); + } + groupHeatMetaDefinition = listGroupHeatMetaDefinition.get(listGroupHeatMetaDefinition.size() - 1); + JSONObject jsonObject = (JSONObject) array.get(i); + @SuppressWarnings("unchecked") + Set groupsKey = jsonObject.keySet(); + for (Object groupKey : groupsKey) { + String groupKeyStr = (String) groupKey; + if (groupKeyStr.equals("isBase")) { + PropertyHeatMetaDefinition propertyHeatMetaDefinition = new PropertyHeatMetaDefinition(); + propertyHeatMetaDefinition.setName(groupKeyStr); + propertyHeatMetaDefinition.setValue((boolean) jsonObject.get(groupKeyStr)); + if (!groupHeatMetaDefinition.getPropertyHeatMetaDefinition() + .equals(propertyHeatMetaDefinition)) { + groupHeatMetaDefinition.getPropertyHeatMetaDefinition() + .setValue((boolean) jsonObject.get(groupKeyStr)); + } + } + if (groupKeyStr.equals("fileName") || groupKeyStr.equals("env")) { + String artifactName = (String) jsonObject.get(groupKeyStr); + List listArtifactNames = groupHeatMetaDefinition.getArtifactList(); + listArtifactNames.add(artifactName); + groupHeatMetaDefinition.setArtifactList(listArtifactNames); + } else { + if (!groupKeyStr.equals("isBase")) { + fetchArtifactByGroup((JSONArray) jsonObject.get(groupKeyStr), listGroupHeatMetaDefinition, + false); + } + } + } + } + } + return listGroupHeatMetaDefinition; + } + + private static Integer getArtifactCount(List listHeatMetaDefenition, + Boolean isEnvIncluded) { + int count = 0; + List uniqeArtifactList = new ArrayList<>(); + + for (TypeHeatMetaDefinition typeHeatMetaDefinition : listHeatMetaDefenition) { + for (GroupHeatMetaDefinition groupHeatMetaDefinition : typeHeatMetaDefinition + .getGroupHeatMetaDefinition()) { + if (isEnvIncluded) { + count = count + groupHeatMetaDefinition.getArtifactList().size(); + } else { + for (String fileName : groupHeatMetaDefinition.getArtifactList()) { + if (!fileName.contains(".env") && !uniqeArtifactList.contains(fileName)) { + uniqeArtifactList.add(fileName); + count = count + 1; + } + } + } + } + } + return count; + } + + private static Integer getGroupCount(List listHeatMetaDefenition) { + int count = 0; + for (TypeHeatMetaDefinition typeHeatMetaDefinition : listHeatMetaDefenition) { + count = count + typeHeatMetaDefinition.getGroupHeatMetaDefinition().size(); + } + return count; + } + + private static String groupNameBuilder(Resource resource) { + String separator = "::"; + String module = "module-"; + String groupName = resource.getSystemName() + separator + module; + return groupName; + } + + public static void validateCsarVfArtifact(String csarUUID, Resource resource) throws Exception { + + List listTypeHeatMetaDefinition = getListTypeHeatMetaDefinition(csarUUID); + assertTrue( + "check group count, expected: " + getGroupCount(listTypeHeatMetaDefinition) + ", actual: " + + resource.getGroups().size(), + getGroupCount(listTypeHeatMetaDefinition) == resource.getGroups().size()); + assertTrue( + "check artifact count, expected: " + getArtifactCount(listTypeHeatMetaDefinition, false) + ", actual: " + + resource.getDeploymentArtifacts().size(), + getArtifactCount(listTypeHeatMetaDefinition, false) == resource.getDeploymentArtifacts().size()); + + } + + public static void validateToscaDefinitonObjectVsResource(ToscaDefinition toscaDefinition, Resource resource) + throws Exception { + + assertTrue( + "check resource instance count, expected: " + getResourceInstanceCount(toscaDefinition) + ", actual: " + + resource.getComponentInstances().size(), + getResourceInstanceCount(toscaDefinition) == resource.getComponentInstances().size()); + assertTrue( + "check resource instance relation count, expected: " + getResourceInstanceRelationCount(toscaDefinition) + + ", actual: " + resource.getComponentInstancesRelations().size(), + getResourceInstanceRelationCount(toscaDefinition) == resource.getComponentInstancesRelations().size()); + + } + + public static Integer getResourceInstanceCount(ToscaDefinition toscaDefinition) { + + return toscaDefinition.getTopology_template().getNode_templates().size(); + } + + public static Integer getResourceInstanceRelationCount(ToscaDefinition toscaDefinition) { + int count = 0; +// List toscaNodeTemplatesTopologyTemplateDefinition = toscaDefinition +// .getTopology_template().getToscaNodeTemplatesTopologyTemplateDefinition(); + Map toscaNodeTemplatesTopologyTemplateDefinition = toscaDefinition.getTopology_template().getNode_templates(); + for (int i = 0; i < toscaNodeTemplatesTopologyTemplateDefinition.size(); i++) { +// List requirements = toscaNodeTemplatesTopologyTemplateDefinition.get(i).getRequirements(); + + for(Entry entry: toscaDefinition.getTopology_template().getNode_templates().entrySet() ){ + if (entry.getValue().equals("requirements")){ + + } + } + + if (requirements != null) { + for (ToscaRequirementsNodeTemplatesDefinition requirement : requirements) { + if (requirement.getNode() != null) { + count = count + 1; + } + } + } + } + return count; + } + + // not finished yet + private static void validateCsarVfgroup(String csarUUID, Resource resource) { + + List groups = resource.getGroups(); + for (GroupDefinition groupDefinition : groups) { + List artifacts = groupDefinition.getArtifacts(); + assertTrue("group description is null", groupDefinition.getDescription() != null); + assertTrue("InvariantUUID is null", groupDefinition.getInvariantUUID() != null); + // groupDefinition.getMembers(); + assertTrue( + "name format mismatch, expected: " + groupNameBuilder(resource) + "[0-9], actual: " + + groupDefinition.getName(), + groupDefinition.getName().contains(groupNameBuilder(resource))); + // groupDefinition.getProperties(); + // groupDefinition.getPropertyValueCounter(); + assertTrue(groupDefinition.getType().equals(getGroupType())); + } + + String expectedCsarUUID = csarUUID; + // String expectedToscaResourceName = "org.openecomp.resource.vf." + + // WordUtils.capitalize(resourceDetails.getName().toLowerCase()); + // + // assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, + // resource.getCsarUUID()), + // expectedCsarUUID.equals(resource.getCsarUUID())); + // assertTrue("toscaResourceName : " + + // buildAssertMessage(expectedToscaResourceName, + // resource.getToscaResourceName()), + // expectedToscaResourceName.equals(resource.getToscaResourceName())); + // + // RestResponse getResourceResponse = + // ResourceRestUtils.getResource(resource.getUniqueId()); + // Resource getResource = + // ResponseParser.parseToObjectUsingMapper(getResourceResponse.getResponse(), + // Resource.class); + // assertTrue("csarUUID : " + buildAssertMessage(expectedCsarUUID, + // getResource.getCsarUUID()), + // expectedCsarUUID.equals(getResource.getCsarUUID())); + // assertTrue("toscaResourceName : " + + // buildAssertMessage(expectedToscaResourceName, + // getResource.getToscaResourceName()), + // expectedToscaResourceName.equals(getResource.getToscaResourceName())); + + } + + private static String getGroupType() { + return "org.openecomp.groups.VfModule"; + } +*/ + + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/DistributionValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/DistributionValidationUtils.java new file mode 100644 index 0000000000..46948d8f5b --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/DistributionValidationUtils.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertNotNull; + +import java.io.IOException; +import java.text.ParseException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.ci.tests.utils.DistributionUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; + +public class DistributionValidationUtils { + + public static Map verifyDistributedArtifactDownloadUsingDB(String distributionID, Map expectedArtifactsMapOfDistributedService, List distributionStatusEnumList) throws Exception { + + String action = "DStatus"; + int timer = 0; + int timeWaitPerArtifcat = 3; + if(expectedArtifactsMapOfDistributedService.size() != 0){ + timer = (expectedArtifactsMapOfDistributedService.size()/10*15 + expectedArtifactsMapOfDistributedService.size() * timeWaitPerArtifcat * distributionStatusEnumList.size() + 30) * 1000 ; + } + for (String distributionStatusList : distributionStatusEnumList){ + for (Entry url : expectedArtifactsMapOfDistributedService.entrySet()){ + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_ID, distributionID); + body.put(AuditingFieldsKeysEnum.AUDIT_DISTRIBUTION_RESOURCE_URL, url.getValue()); + body.put(AuditingFieldsKeysEnum.AUDIT_STATUS, distributionStatusList); + Map actualAuditRecord = new HashMap(); + actualAuditRecord = AuditValidationUtils.retrieveAuditMessagesByPattern(action, body, true); + while (timer != 0) { + if(actualAuditRecord.size() == 0 ){ + Thread.sleep(1000); + actualAuditRecord = AuditValidationUtils.retrieveAuditMessagesByPattern(action, body, true); + timer-=1000; + if(timer == 0 && actualAuditRecord.size() == 0){ + assertNotNull("audit record did not found in DB for artifact url: " + url.getValue(), null); + } + }else{ + timer = timer - timeWaitPerArtifcat * 1000; + break; + } + + } + } + } + return null; + } + + public static void validateDistributedArtifactsByAudit(Service service, List distributionStatusList) throws Exception, IOException, ParseException { + String distributionID; + AtomicOperationUtils.distributeService(service, true); + distributionID = DistributionUtils.getLatestServiceDistributionObject(service).getDistributionID(); + if(distributionID != null){ + Map expectedArtifactsMapOfDistributedService = DistributionUtils.getArtifactsMapOfDistributedService(service); + DistributionValidationUtils.verifyDistributedArtifactDownloadUsingDB(distributionID, expectedArtifactsMapOfDistributedService, distributionStatusList); + } + else{ + assertNotNull("distributionID is null", distributionID); + } + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ErrorValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ErrorValidationUtils.java new file mode 100644 index 0000000000..b79e4c63fc --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ErrorValidationUtils.java @@ -0,0 +1,120 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertEquals; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.List; +import java.util.Map; + +import org.yaml.snakeyaml.Yaml; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.ExceptionEnumType; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ErrorValidationUtils { + static Logger logger = LoggerFactory.getLogger(ErrorValidationUtils.class.getName()); + + public static void checkBodyResponseOnError(String errorType, List variables, String actualResponse) + throws FileNotFoundException, JSONException { + + ErrorInfo errorInfo = parseErrorConfigYaml(errorType); + JSONObject expectedResponseBody = null; + if (errorInfo.getMessageId() != null) { + if (errorInfo.getMessageId().contains("SVC")) { + expectedResponseBody = restExceptionFormatBuilder(errorInfo.getMessageId(), errorInfo.getMessage(), + variables, ExceptionEnumType.SERVICE_EXCEPTION.getValue()); + } else { + expectedResponseBody = restExceptionFormatBuilder(errorInfo.getMessageId(), errorInfo.getMessage(), + variables, ExceptionEnumType.POLICY_EXCPTION.getValue()); + } + } + actualResponse = actualResponse.replaceAll("\\n", ""); + logger.debug("actualResponse - {}", actualResponse); + logger.debug("expectedResponseBody - {}", expectedResponseBody); + assertEquals(expectedResponseBody, new JSONObject(actualResponse)); + } + + public static String checkUIResponseOnError(String errorType) + throws FileNotFoundException, JSONException { + + ErrorInfo errorInfo = parseErrorConfigYaml(errorType); + String messageId = errorInfo.getMessageId(); + + return messageId; + } + + public static JSONObject restExceptionFormatBuilder(String messageId, String text, List variables, + String type) { + + JSONObject simpleElements = new JSONObject(); + JSONObject exceptionType = new JSONObject(); + JSONObject requestError = new JSONObject(); + + try { + simpleElements.put("messageId", messageId); + simpleElements.put("text", text); + simpleElements.put("variables", variables); + exceptionType.put(type, simpleElements); + requestError.put("requestError", exceptionType); + + } catch (JSONException e) { + e.printStackTrace(); + } + + return requestError; + + } + + public static ErrorInfo parseErrorConfigYaml(String error) throws FileNotFoundException { + Yaml yaml = new Yaml(); + ErrorInfo errInfo = null; + Config config = Utils.getConfig(); + String errorConfigurationFile = config.getErrorConfigurationFile(); + File file = new File(errorConfigurationFile); + // File file = new + // File("../catalog-be/src/main/resources/config/error-configuration.yaml"); + InputStream inputStream = new FileInputStream(file); + Map map = (Map) yaml.load(inputStream); + // System.out.println(map.get("errors")); + @SuppressWarnings("unchecked") + Map errorMap = (Map) map.get("errors"); + @SuppressWarnings("unchecked") + Map errorInfo = (Map) errorMap.get(error); + + String message = (String) errorInfo.get("message"); + String messageId = (String) errorInfo.get("messageId"); + int code = (Integer) errorInfo.get("code"); + errInfo = new ErrorInfo(code, message, messageId); + + return errInfo; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ProductValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ProductValidationUtils.java new file mode 100644 index 0000000000..ba5114c1bc --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ProductValidationUtils.java @@ -0,0 +1,239 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.log4j.Logger; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.model.Product; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.GroupingDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest.ComponentOperationEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; + +public class ProductValidationUtils { + + static Logger logger = Logger.getLogger(ProductValidationUtils.class.getName()); + + public static void compareExpectedAndActualProducts(Product expectedProduct, Product actualProduct) { + compareExpectedAndActualProducts(expectedProduct, actualProduct, null); + } + + public static void compareExpectedAndActualProducts(Product expectedProduct, Product actualProduct, + ComponentOperationEnum operation) { + + assertEquals(expectedProduct.getName(), actualProduct.getName()); + assertEquals(expectedProduct.getFullName(), actualProduct.getFullName()); + assertEquals(expectedProduct.getDescription(), actualProduct.getDescription()); + + List expectedContacts = expectedProduct.getContacts(); + List actualContacts = actualProduct.getContacts(); + assertTrue( + "Expected contacts:" + Arrays.toString(expectedContacts.toArray()) + ", actual contacts:" + + Arrays.toString(actualContacts.toArray()), + expectedContacts.size() == actualContacts.size() && expectedContacts.containsAll(actualContacts) + && actualContacts.containsAll(expectedContacts)); + + List expectedTags = expectedProduct.getTags(); + List actualTags = actualProduct.getTags(); + assertTrue( + "Expected tags:" + Arrays.toString(expectedTags.toArray()) + ", actual tags:" + + Arrays.toString(actualTags.toArray()), + expectedTags.size() == actualTags.size() && expectedTags.containsAll(actualTags) + && actualTags.containsAll(expectedTags)); + + assertEquals(expectedProduct.getLifecycleState(), actualProduct.getLifecycleState()); + assertEquals(expectedProduct.getVersion(), actualProduct.getVersion()); + assertEquals(expectedProduct.isHighestVersion(), actualProduct.isHighestVersion()); + assertEquals(expectedProduct.getNormalizedName(), actualProduct.getNormalizedName()); + + compareCategories(expectedProduct, actualProduct); + assertEquals(expectedProduct.getLastUpdaterUserId(), actualProduct.getLastUpdaterUserId()); + if (operation != null) { + assertEquals(expectedProduct.getCreatorUserId(), actualProduct.getCreatorUserId()); + } + + Long lastUpdateDate = actualProduct.getLastUpdateDate(); + Long creationDate = actualProduct.getCreationDate(); + Map allVersions = actualProduct.getAllVersions(); + + if (operation != null) { + if (operation == ComponentOperationEnum.UPDATE_COMPONENT + || operation == ComponentOperationEnum.CHANGE_STATE_CHECKOUT + || operation == ComponentOperationEnum.CHANGE_STATE_CHECKIN + || operation == ComponentOperationEnum.CHANGE_STATE_UNDO_CHECKOUT) { + assertTrue("Last update date:" + lastUpdateDate + ", creation date: " + creationDate, + lastUpdateDate > 0 && creationDate > 0 && lastUpdateDate > creationDate); + } else { + assertTrue("Last update date:" + lastUpdateDate + ", creation date: " + creationDate, + lastUpdateDate > 0 && lastUpdateDate.equals(creationDate)); + } + } + + // Check UUIDs + // If just created, no way to test the UUIDs themselves + // If updated, we expect the UUIDs of actual to match the expected + String uniqueId = actualProduct.getUniqueId(); + if (operation == ComponentOperationEnum.CREATE_COMPONENT) { + UUID.fromString(uniqueId); + UUID.fromString(actualProduct.getUUID()); + UUID.fromString(actualProduct.getInvariantUUID()); + assertTrue(allVersions.size() == 1); + assertTrue(allVersions.get("0.1").equals(uniqueId)); + } else { + if (operation == ComponentOperationEnum.CHANGE_STATE_CHECKOUT) { + assertFalse(expectedProduct.getUniqueId().equals(uniqueId)); + // Assigning the updated uniqueId to expected so that it can be + // passed to further logic + expectedProduct.setUniqueId(uniqueId); + } else if (operation != null) { + assertTrue(expectedProduct.getUniqueId().equals(uniqueId)); + } + assertEquals(expectedProduct.getUUID(), actualProduct.getUUID()); + assertEquals(expectedProduct.getInvariantUUID(), actualProduct.getInvariantUUID()); + } + } + + private static void compareCategories(Product expectedProduct, Product actualProduct) { + List expectedCategories = expectedProduct.getCategories(); + List actualCategories = actualProduct.getCategories(); + if (expectedCategories != null && actualCategories != null) { + int expSize = expectedCategories.size(); + int actSize = actualCategories.size(); + + assertTrue("Expected size:" + expSize + ", actual size:" + actSize, expSize == actSize); + + for (CategoryDefinition actualDefinition : actualCategories) { + int lastIndexOfCat = expectedCategories.lastIndexOf(actualDefinition); + assertTrue("Actual category " + actualDefinition + " not found in expected.", lastIndexOfCat != -1); + CategoryDefinition expectedDefinition = expectedCategories.get(lastIndexOfCat); + List actualSubcategories = actualDefinition.getSubcategories(); + List expectedSubcategories = expectedDefinition.getSubcategories(); + for (SubCategoryDefinition actualSub : actualSubcategories) { + lastIndexOfCat = expectedSubcategories.lastIndexOf(actualSub); + assertTrue("Actual subcategory " + actualSub + " not found in expected.", lastIndexOfCat != -1); + SubCategoryDefinition expectedSub = expectedSubcategories.get(lastIndexOfCat); + List actualGroupings = actualSub.getGroupings(); + List expectedGroupings = expectedSub.getGroupings(); + for (GroupingDefinition actualGrouping : actualGroupings) { + lastIndexOfCat = expectedGroupings.lastIndexOf(actualGrouping); + assertTrue("Actual grouping " + actualSub + " not found in expected.", lastIndexOfCat != -1); + } + } + } + + for (CategoryDefinition expectedDefinition : expectedCategories) { + int lastIndexOfCat = actualCategories.lastIndexOf(expectedDefinition); + assertTrue("Expected category " + expectedDefinition + " not found in actual.", lastIndexOfCat != -1); + CategoryDefinition actualDefinition = actualCategories.get(lastIndexOfCat); + List actualSubcategories = actualDefinition.getSubcategories(); + List expectedSubcategories = expectedDefinition.getSubcategories(); + for (SubCategoryDefinition expectedSub : expectedSubcategories) { + lastIndexOfCat = actualSubcategories.lastIndexOf(expectedSub); + assertTrue("Expected subcategory " + expectedSub + " not found in actual.", lastIndexOfCat != -1); + SubCategoryDefinition actualSub = actualSubcategories.get(lastIndexOfCat); + List actualGroupings = actualSub.getGroupings(); + List expectedGroupings = expectedSub.getGroupings(); + for (GroupingDefinition expectedGrouping : expectedGroupings) { + lastIndexOfCat = actualGroupings.lastIndexOf(expectedGrouping); + assertTrue("Expected grouping " + expectedGrouping + " not found in actual.", + lastIndexOfCat != -1); + } + } + } + } + } + + public static void verifyProductsNotExistInUserFollowedPage(User user, Product... nonExpectedProducts) + throws Exception { + String component = "products"; + Boolean isExist; + Product nonExpectedProduct; + RestResponse getFollowedPage = ProductRestUtils.getFollowed(user.getUserId()); + JSONArray followedProductes = getListArrayFromRestResponse(getFollowedPage, component); + if (followedProductes != null) { // if any product exist in followed + // page + for (int i = 0; i < nonExpectedProducts.length; i++) { + nonExpectedProduct = nonExpectedProducts[i]; + isExist = false; + for (int k = 0; k < followedProductes.size(); k++) { + JSONObject jobject = (JSONObject) followedProductes.get(k); + if (jobject.get("uuid").toString().equals(nonExpectedProduct.getUUID())) { + isExist = true; + k = followedProductes.size(); + } + } + assertFalse(isExist); + } + } + + } + + public static void checkUserFollowedPage(User user, Product... expectedProducts) throws Exception { + String component = "products"; + Boolean isExist; + Product expectedProduct; + RestResponse getFollowedPage = ProductRestUtils.getFollowed(user.getUserId()); + JSONArray followedProductes = getListArrayFromRestResponse(getFollowedPage, component); + assertTrue("check if any followedProductes received ", followedProductes != null); + assertTrue("check if any expectedProducts and followedProductes are the same size", + expectedProducts.length == followedProductes.size()); + for (int i = 0; i < expectedProducts.length; i++) { + expectedProduct = expectedProducts[i]; + isExist = false; + for (int k = 0; k < followedProductes.size(); k++) { + JSONObject jobject = (JSONObject) followedProductes.get(k); + // if(jobject.get("uuid").toString().equals(expectedProduct.getUUID())) + if (jobject.get("uniqueId").toString().equals(expectedProduct.getUniqueId())) { + + String productString = jobject.toJSONString(); + Product actualProduct = ResponseParser.parseToObjectUsingMapper(productString, Product.class); + ProductValidationUtils.compareExpectedAndActualProducts(expectedProduct, actualProduct, null); + isExist = true; + k = followedProductes.size(); + } + } + assertTrue(isExist); + } + } + + private static JSONArray getListArrayFromRestResponse(RestResponse restResponse, String lst) { + String json = restResponse.getResponse(); + JSONObject jsonResp = (JSONObject) JSONValue.parse(json); + JSONArray resources = (JSONArray) jsonResp.get(lst); + return resources; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ResourceValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ResourceValidationUtils.java new file mode 100644 index 0000000000..07f2ef8188 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ResourceValidationUtils.java @@ -0,0 +1,358 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceRespJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.enums.RespJsonKeysEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; + +import com.google.gson.Gson; + +public class ResourceValidationUtils { + + public static void validateResourceReqVsResp(ResourceReqDetails resourceDetails, + ResourceRespJavaObject resourceRespJavaObject) { + + String expected; + + expected = resourceDetails.getDescription(); + assertEquals("resource description - ", expected, resourceRespJavaObject.getDescription()); + + expected = resourceDetails.getVendorName(); + assertEquals("resource vendorName - ", expected, resourceRespJavaObject.getVendorName()); + + expected = resourceDetails.getVendorRelease(); + assertEquals("resource vendorReleaseName - ", expected, resourceRespJavaObject.getVendorRelease()); + + expected = resourceDetails.getContactId(); + assertEquals("resource contactId - ", expected, resourceRespJavaObject.getContactId()); + + } + + public static void validateResourceReqVsResp(ResourceReqDetails resourceDetails, Resource resourceRespJavaObject) { + + String expected; + + expected = resourceDetails.getDescription(); + assertEquals("resource description - ", expected, resourceRespJavaObject.getDescription()); + + expected = resourceDetails.getVendorName(); + assertEquals("resource vendorName - ", expected, resourceRespJavaObject.getVendorName()); + + expected = resourceDetails.getVendorRelease(); + assertEquals("resource vendorReleaseName - ", expected, resourceRespJavaObject.getVendorRelease()); + + expected = resourceDetails.getContactId(); + assertEquals("resource contactId - ", expected, resourceRespJavaObject.getContactId()); + + // Validating deduplication of tags + List expectedTags = resourceDetails.getTags(); + if (expectedTags != null) { + Set hs = new LinkedHashSet<>(expectedTags); + expectedTags.clear(); + expectedTags.addAll(hs); + List receivedTags = resourceRespJavaObject.getTags(); + assertEquals("resource tags - ", expectedTags, receivedTags); + } + + } + + public static void validateModelObjects(Resource expected, Resource actual) throws Exception { + + compareElements(expected.getUniqueId(), actual.getUniqueId()); + compareElements(expected.getName(), actual.getName()); + compareElements(expected.getVersion(), actual.getVersion()); + compareElements(expected.getCreatorUserId(), actual.getCreatorUserId()); + compareElements(expected.getCreatorFullName(), actual.getCreatorFullName()); + compareElements(expected.getLastUpdaterUserId(), actual.getLastUpdaterUserId()); + compareElements(expected.getLastUpdaterFullName(), actual.getLastUpdaterFullName()); + compareElements(expected.getCreatorFullName(), actual.getCreatorFullName()); + compareElements(expected.getCreationDate(), actual.getCreationDate()); + compareElements(expected.getLastUpdateDate(), actual.getLastUpdateDate()); + compareElements(expected.getDescription(), actual.getDescription()); + compareElements(expected.getIcon(), actual.getIcon()); + compareElements(expected.getLastUpdateDate(), actual.getLastUpdateDate()); + // TODO compare tags + compareElements(expected.getCategories(), actual.getCategories()); + compareElements(expected.getLifecycleState(), actual.getLifecycleState()); + compareElements(expected.getVendorName(), actual.getVendorName()); + compareElements(expected.getVendorRelease(), actual.getVendorRelease()); + compareElements(expected.getContactId(), actual.getContactId()); + compareElements(expected.getUUID(), actual.getUUID()); + compareElements(expected.getVersion(), actual.getVersion()); + + } + + public static void validateResp(RestResponse restResponse, ResourceRespJavaObject resourceRespJavaObject) + throws Exception { + + Gson gson = new Gson(); + String response = restResponse.getResponse(); + + validateResp(response, resourceRespJavaObject, gson); + + } + + public static void validateResp(String response, ResourceRespJavaObject resourceRespJavaObject, Gson gson) { + + Map map = new HashMap(); + map = (Map) gson.fromJson(response, map.getClass()); + + // De-duplicating the tags list for comparison + List tags = resourceRespJavaObject.getTags(); + if (tags != null) { + Set hs = new LinkedHashSet<>(tags); + tags = new ArrayList(hs); + resourceRespJavaObject.setTags(tags); + tags = new ArrayList(hs); + resourceRespJavaObject.setTags(tags); + } + + validateField(map, RespJsonKeysEnum.RESOURCE_NAME.getRespJsonKeyName(), resourceRespJavaObject.getName()); + validateField(map, RespJsonKeysEnum.RESOURCE_DESC.getRespJsonKeyName(), + resourceRespJavaObject.getDescription()); + // validateField(map, RespJsonKeysEnum.CATEGORIES.getRespJsonKeyName(), + // resourceRespJavaObject.getCategories()); + validateField(map, RespJsonKeysEnum.VENDOR_NAME.getRespJsonKeyName(), resourceRespJavaObject.getVendorName()); + validateField(map, RespJsonKeysEnum.VENDOR_RELEASE.getRespJsonKeyName(), + resourceRespJavaObject.getVendorRelease()); + validateField(map, RespJsonKeysEnum.CONTACT_ID.getRespJsonKeyName(), resourceRespJavaObject.getContactId()); + validateField(map, RespJsonKeysEnum.ICON.getRespJsonKeyName(), resourceRespJavaObject.getIcon()); + validateField(map, RespJsonKeysEnum.IS_ABSTRACT.getRespJsonKeyName(), + Boolean.valueOf(resourceRespJavaObject.getAbstractt())); + validateField(map, RespJsonKeysEnum.HIGHEST_VERSION.getRespJsonKeyName(), + Boolean.valueOf(resourceRespJavaObject.getIsHighestVersion())); + validateField(map, RespJsonKeysEnum.UNIQUE_ID.getRespJsonKeyName(), resourceRespJavaObject.getUniqueId()); + validateField(map, RespJsonKeysEnum.RESOURCE_VERSION.getRespJsonKeyName(), resourceRespJavaObject.getVersion()); + validateField(map, RespJsonKeysEnum.LIFE_CYCLE_STATE.getRespJsonKeyName(), + resourceRespJavaObject.getLifecycleState()); + validateField(map, RespJsonKeysEnum.TAGS.getRespJsonKeyName(), tags); + validateField(map, RespJsonKeysEnum.CREATOR_ATT_UID.getRespJsonKeyName(), + resourceRespJavaObject.getCreatorUserId()); + validateField(map, RespJsonKeysEnum.CREATOR_FULL_NAME.getRespJsonKeyName(), + resourceRespJavaObject.getCreatorFullName()); + validateField(map, RespJsonKeysEnum.LAST_UPDATER_ATT_UID.getRespJsonKeyName(), + resourceRespJavaObject.getLastUpdaterUserId()); + validateField(map, RespJsonKeysEnum.LAST_UPDATER_FULL_NAME.getRespJsonKeyName(), + resourceRespJavaObject.getLastUpdaterFullName()); + validateField(map, RespJsonKeysEnum.COST.getRespJsonKeyName(), resourceRespJavaObject.getCost()); + validateField(map, RespJsonKeysEnum.LICENSE_TYPE.getRespJsonKeyName(), resourceRespJavaObject.getLicenseType()); + validateField(map, RespJsonKeysEnum.RESOURCE_TYPE.getRespJsonKeyName(), + resourceRespJavaObject.getResourceType().toString()); + if (resourceRespJavaObject.getResourceType().equals("VF")) { + validateField(map, RespJsonKeysEnum.DERIVED_FROM.getRespJsonKeyName(), null); + } else { + validateField(map, RespJsonKeysEnum.DERIVED_FROM.getRespJsonKeyName(), + resourceRespJavaObject.getDerivedFrom()); + } + + validateCategories(resourceRespJavaObject, map); + + String uuid = ResponseParser.getValueFromJsonResponse(response, RespJsonKeysEnum.UUID.getRespJsonKeyName()); + assertTrue("UUID is empty", uuid != null && !uuid.isEmpty()); + } + + private static void validateCategories(ResourceRespJavaObject resourceRespJavaObject, Map map) { + assertTrue(RespJsonKeysEnum.CATEGORIES.getRespJsonKeyName() + " is missing", + map.containsKey(RespJsonKeysEnum.CATEGORIES.getRespJsonKeyName())); + Object foundValue = map.get(RespJsonKeysEnum.CATEGORIES.getRespJsonKeyName()); + List> foundList = (List>) foundValue; + List excpectedList = resourceRespJavaObject.getCategories(); + + assertTrue(foundList.size() == excpectedList.size()); + for (int i = 0; i < foundList.size(); i++) { + CategoryDefinition expCat = excpectedList.get(i); + Map foun = foundList.get(i); + assertTrue("expected " + expCat.getName() + " not equal to actual " + foundValue, + foun.get("name").equals(expCat.getName())); + } + } + + public static void validateField(Map map, String jsonField, Object expectedValue) { + if (expectedValue == null) { + assertTrue(jsonField + " is expected to be null", !map.containsKey(jsonField)); + } else { + assertTrue(jsonField + " is missing", map.containsKey(jsonField)); + Object foundValue = map.get(jsonField); + compareElements(expectedValue, foundValue); + } + } + + public static void compareElements(Object expectedValue, Object foundValue) { + if (expectedValue instanceof String) { + assertTrue(foundValue instanceof String); + assertTrue("expected " + expectedValue + " not equal to actual " + foundValue, + foundValue.equals(expectedValue)); + } + /* + * else if( expectedValue instanceof Number){ assertTrue(foundValue + * instanceof Number); assertTrue(foundValue == expectedValue); } + */ + else if (expectedValue instanceof Boolean) { + assertTrue(foundValue instanceof Boolean); + assertTrue(foundValue == expectedValue); + } else if (expectedValue instanceof Map) { + assertTrue(foundValue instanceof Map); + Map foundMap = (Map) foundValue; + Map excpectedMap = (Map) expectedValue; + assertTrue(foundMap.size() == excpectedMap.size()); + Iterator foundkeyItr = foundMap.keySet().iterator(); + while (foundkeyItr.hasNext()) { + String foundKey = foundkeyItr.next(); + assertTrue(excpectedMap.containsKey(foundKey)); + compareElements(excpectedMap.get(foundKey), foundMap.get(foundKey)); + } + + } else if (expectedValue instanceof List) { + assertTrue(foundValue instanceof List); + List foundList = (List) foundValue; + List excpectedList = (List) expectedValue; + assertTrue(foundList.size() == excpectedList.size()); + for (int i = 0; i < foundList.size(); i++) { + compareElements(excpectedList.get(i), foundList.get(i)); + } + + } else { + assertTrue(foundValue.equals(expectedValue)); + } + } + + public static boolean validateUuidAfterChangingStatus(String oldUuid, String newUuid) { + return oldUuid.equals(newUuid); + + } + + public static void validateRespArt(RestResponse restResponse, ResourceRespJavaObject resourceRespJavaObject, + String interfaze) throws Exception { + + Gson gson = new Gson(); + String response = restResponse.getResponse(); + + Map map = new HashMap(); + map = (Map) gson.fromJson(response, map.getClass()); + + Resource resource = gson.fromJson(response, Resource.class); + + Map artifacts = resource.getArtifacts(); + Map interfaces = null; + + if (interfaze != null) { + interfaces = resource.getInterfaces(); + Map operation = interfaces.get(interfaze).getOperationsMap(); + // operation.get("configure").getUniqueId(); + } + + validateField(map, RespJsonKeysEnum.RESOURCE_NAME.getRespJsonKeyName(), resourceRespJavaObject.getName()); + validateField(map, RespJsonKeysEnum.RESOURCE_DESC.getRespJsonKeyName(), + resourceRespJavaObject.getDescription()); + // validateField(map, RespJsonKeysEnum.CATEGORIES.getRespJsonKeyName(), + // resourceRespJavaObject.getCategories()); + validateField(map, RespJsonKeysEnum.DERIVED_FROM.getRespJsonKeyName(), resourceRespJavaObject.getDerivedFrom()); + validateField(map, RespJsonKeysEnum.VENDOR_NAME.getRespJsonKeyName(), resourceRespJavaObject.getVendorName()); + validateField(map, RespJsonKeysEnum.VENDOR_RELEASE.getRespJsonKeyName(), + resourceRespJavaObject.getVendorRelease()); + validateField(map, RespJsonKeysEnum.CONTACT_ID.getRespJsonKeyName(), resourceRespJavaObject.getContactId()); + validateField(map, RespJsonKeysEnum.ICON.getRespJsonKeyName(), resourceRespJavaObject.getIcon()); + validateField(map, RespJsonKeysEnum.IS_ABSTRACT.getRespJsonKeyName(), + Boolean.valueOf(resourceRespJavaObject.getAbstractt())); + validateField(map, RespJsonKeysEnum.HIGHEST_VERSION.getRespJsonKeyName(), + Boolean.valueOf(resourceRespJavaObject.getIsHighestVersion())); + validateField(map, RespJsonKeysEnum.UNIQUE_ID.getRespJsonKeyName(), resourceRespJavaObject.getUniqueId()); + validateField(map, RespJsonKeysEnum.RESOURCE_VERSION.getRespJsonKeyName(), resourceRespJavaObject.getVersion()); + validateField(map, RespJsonKeysEnum.LIFE_CYCLE_STATE.getRespJsonKeyName(), + resourceRespJavaObject.getLifecycleState()); + validateField(map, RespJsonKeysEnum.TAGS.getRespJsonKeyName(), resourceRespJavaObject.getTags()); + validateField(map, RespJsonKeysEnum.CREATOR_ATT_UID.getRespJsonKeyName(), + resourceRespJavaObject.getCreatorUserId()); + validateField(map, RespJsonKeysEnum.CREATOR_FULL_NAME.getRespJsonKeyName(), + resourceRespJavaObject.getCreatorFullName()); + validateField(map, RespJsonKeysEnum.LAST_UPDATER_ATT_UID.getRespJsonKeyName(), + resourceRespJavaObject.getLastUpdaterUserId()); + validateField(map, RespJsonKeysEnum.LAST_UPDATER_FULL_NAME.getRespJsonKeyName(), + resourceRespJavaObject.getLastUpdaterFullName()); + + // validate number of artifacts + if (resourceRespJavaObject.getArtifacts() != null) { + + // assertEquals("check number of artifacts", + // resourceRespJavaObject.getArtifacts().size(), artifacts.size()); + int iterNum = -1; + ArrayList myArtifacats = new ArrayList(); + Iterator it = artifacts.entrySet().iterator(); + while (it.hasNext()) { + iterNum++; + Map.Entry pair = (Map.Entry) it.next(); + // System.out.println(pair.getKey() + " = " + pair.getValue()); + ArtifactDefinition myArtifact = artifacts.get(pair.getKey()); + myArtifacats.add(myArtifact.getEsId()); + it.remove(); // avoids a ConcurrentModificationException + } + // assertTrue("check service contains + // artifacts",myArtifacats.containsAll(resourceRespJavaObject.getArtifacts())); + } + + // validate number of interfaces: + + if (interfaze != null) { + assertEquals("check number of interfaces", resourceRespJavaObject.getInterfaces().size(), + interfaces.size()); + } + + } + + public static boolean validateResourceIsAbstartct(List resourceList, Boolean bool) { + if (resourceList != null && resourceList.size() > 0) { + for (Resource resource : resourceList) { + if (resource.isAbstract().equals(bool)) + continue; + else + return false; + } + } else + return false; + return true; + } + + public static void validateResourceVersion(Resource resource, String expectedVersion) { + if (resource != null && !resource.equals("")) { + assertTrue("expected resource version is: " + expectedVersion + ", but actual is: " + resource.getVersion(), + resource.getVersion().equals(expectedVersion)); + } + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ServiceValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ServiceValidationUtils.java new file mode 100644 index 0000000000..a7c7b7d34e --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/ServiceValidationUtils.java @@ -0,0 +1,130 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertEquals; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; + +public class ServiceValidationUtils { + + public static void validateServiceResponseMetaData(ServiceReqDetails serviceDetails, Service service, User user, + LifecycleStateEnum lifecycleState) { + validateServiceResponseMetaData(serviceDetails, service, user, user, lifecycleState); + } + + public static void validateServiceResponseMetaData(ServiceReqDetails expectedService, Service service, + User creatorUser, User updaterUser, LifecycleStateEnum lifeCycleState) { + List expectedTags = expectedService.getTags(); + expectedTags.add(expectedService.getName()); + List receivedTags = service.getTags(); + if (expectedTags != null) { + Set hs = new LinkedHashSet<>(expectedTags); + expectedTags.clear(); + expectedTags.addAll(hs); + } + + assertEquals("Check service name on response after create service", expectedService.getName(), + service.getName()); + // check size of list + assertEquals("Check only 1 category returned on response after create service", 1, + expectedService.getCategories().size()); + assertEquals("Check service name on response after create service", expectedService.getName(), + service.getName()); + assertEquals("Check categories on response after create service", + expectedService.getCategories().get(0).getName(), service.getCategories().get(0).getName()); + assertEquals("Check tag list on response after create service", expectedTags, receivedTags); + assertEquals("Check description on response after create service", expectedService.getDescription(), + service.getDescription()); + // assertEquals("Check vendor name on response after create service", + // expectedService.getVendorName(), service.getVendorName()); + // assertEquals("Check vendor release on response after create service", + // expectedService.getVendorRelease(), service.getVendorRelease()); + assertEquals("Check attContant name on response after create service", + expectedService.getContactId().toLowerCase(), service.getContactId()); + assertEquals("Check icon name on response after create service", expectedService.getIcon(), service.getIcon()); + assertEquals("Check LastUpdaterUserId after create service", updaterUser.getUserId(), + service.getLastUpdaterUserId()); + assertEquals("Check LastUpdaterName after create service", + updaterUser.getFirstName() + " " + updaterUser.getLastName(), service.getLastUpdaterFullName()); + assertEquals("Check CreatorUserId after create service", creatorUser.getUserId(), service.getCreatorUserId()); + assertEquals("Check CreatorName after create service", + creatorUser.getFirstName() + " " + creatorUser.getLastName(), service.getCreatorFullName()); + assertEquals("Check version after create service", expectedService.getVersion(), service.getVersion()); + // assertEquals("Check UniqueId after create service", SERVICE_PREFIX + + // serviceDetails.getServiceName().toLowerCase()+"." + + // serviceBaseVersion, service.getUniqueId()); + assertFalse("Check uuid after create service", service.getUUID().isEmpty()); + + // assertTrue("check creation date after create service", + // service.getCreationDate() != null); + // assertTrue("check update date after create service", + // service.getLastUpdateDate() != null); + + if (lifeCycleState != null) + assertEquals("Check LifecycleState after create service", lifeCycleState, service.getLifecycleState()); + else + assertEquals("Check LifecycleState after create service", LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, + service.getLifecycleState()); + } + + public static ExpectedResourceAuditJavaObject constructFieldsForAuditValidation(ServiceReqDetails serviceReqDetails, + String serviceVersion, User sdncUserDetails) { + + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); + + expectedResourceAuditJavaObject.setAction("Create"); + expectedResourceAuditJavaObject.setModifierUid(sdncUserDetails.getUserId()); + String userFirstLastName = sdncUserDetails.getFirstName() + " " + sdncUserDetails.getLastName(); + expectedResourceAuditJavaObject.setModifierName(userFirstLastName); + expectedResourceAuditJavaObject.setStatus("200"); + expectedResourceAuditJavaObject.setDesc("OK"); + expectedResourceAuditJavaObject.setResourceName(serviceReqDetails.getName()); + expectedResourceAuditJavaObject.setResourceType("Service"); + expectedResourceAuditJavaObject.setPrevVersion(String.valueOf(Float.parseFloat(serviceVersion) - 0.1f)); + expectedResourceAuditJavaObject.setCurrVersion(serviceVersion); + expectedResourceAuditJavaObject.setPrevState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setCurrState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + expectedResourceAuditJavaObject.setComment(null); + + return expectedResourceAuditJavaObject; + + } + + public static void validateDistrubtionStatusValue(RestResponse response, + DistributionStatusEnum expectedDistributionValue) throws Exception { + String actualDistributionValue = ResponseParser.getValueFromJsonResponse(response.getResponse(), + "distributionStatus"); + assertEquals(expectedDistributionValue.name(), actualDistributionValue); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/UserValidationUtils.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/UserValidationUtils.java new file mode 100644 index 0000000000..1fa20c19fd --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/utils/validation/UserValidationUtils.java @@ -0,0 +1,279 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utils.validation; + +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.assertEquals; + +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.openecomp.sdc.be.dao.utils.UserStatusEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.users.AddUserAuditMessageInfo; +import org.openecomp.sdc.ci.tests.users.UserAuditJavaObject; +import org.openecomp.sdc.ci.tests.utils.DbUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class UserValidationUtils { + public static void compareExpectedAndActualUsers(User expected, User actual) { + + String actualFirstName = actual.getFirstName(); + String expectedFirstName = expected.getFirstName(); + assertEquals("check user first name - ", expectedFirstName, actualFirstName); + + String actualLastName = actual.getLastName(); + String expectedLastName = expected.getLastName(); + assertEquals("check user last name - ", expectedLastName, actualLastName); + + String actualUserId = actual.getUserId(); + String expectedUserId = expected.getUserId(); + assertEquals("check user userId - ", expectedUserId, actualUserId); + + String actualEmail = actual.getEmail(); + String expectedEmail = expected.getEmail(); + assertEquals("check user email - ", expectedEmail, actualEmail); + + Long actualLastLoginTime = actual.getLastLoginTime(); + Long expectedLastLoginTime = expected.getLastLoginTime(); + assertEquals("check user last login time - ", expectedLastLoginTime, actualLastLoginTime); + + String actualRole = actual.getRole(); + if (expected.getRole() == null) { + String expectedRole = UserRoleEnum.DESIGNER.name(); + assertEquals("check user role - ", expectedRole, actualRole); + } else { + String expectedRole = expected.getRole(); + assertEquals("check user role - ", expectedRole, actualRole); + } + + UserStatusEnum actualStatus = expected.getStatus(); + UserStatusEnum expectedStatus = expected.getStatus(); + assertEquals("check user status - ", expectedStatus, actualStatus); + } + + public static void validateDeleteUserAuditMessage(User sdncUserDetails, User sdncModifierDetails, + String responseCode, String responseMessage, AddUserAuditMessageInfo addUserAuditMessageInfo) { + String action = "DeleteUser"; + validateUserAuditMessage(sdncUserDetails, sdncModifierDetails, responseCode, responseMessage, + addUserAuditMessageInfo, action); + + } + + private static void validateUserAuditMessage(User sdncUserDetails, User sdncModifierDetails, String responseCode, + String responseMessage, AddUserAuditMessageInfo addUserAuditMessageInfo, String expectedAction) { + + assertEquals("check audit action - ", expectedAction, addUserAuditMessageInfo.getACTION()); + + // String expectedModifierFirstLastName = + // sdncModifierDetails.getFirstName() + " " + + // sdncModifierDetails.getLastName(); + // assertEquals("check audit modifier name - ", + // expectedModifierFirstLastName, + // addUserAuditMessageInfo.getMODIFIER_NAME()); + String fullName = sdncModifierDetails.getFullName(); + if (sdncModifierDetails.getFullName().equals(" ")) { + fullName = ""; + } + String expectedModifierId = fullName + "(" + sdncModifierDetails.getUserId() + ")"; + assertEquals("check audit modifier uid - ", expectedModifierId, addUserAuditMessageInfo.getMODIFIER()); + + String expectedUserFirstLastName = sdncUserDetails.getFirstName() + " " + sdncUserDetails.getLastName(); + if (expectedUserFirstLastName.equals("null null")) { + expectedUserFirstLastName = ""; + } + + String email = (sdncUserDetails.getEmail() == null) ? "" : sdncUserDetails.getEmail(); + String role = (sdncUserDetails.getRole() == null) ? "DESIGNER" : sdncUserDetails.getRole(); + + String formatedUser = String.format("%s,%s,%s,%s", sdncUserDetails.getUserId(), expectedUserFirstLastName, + email, role); + + // + // String expectedUserFirstLastName = sdncUserDetails.getFirstName() + " + // " + sdncUserDetails.getLastName(); + // if (expectedUserFirstLastName.equals("null null")) { + // expectedUserFirstLastName = ""; + // } + // + // String expectedUserFirstLastName = ""; + // expectedUserFirstLastName += sdncUserDetails.getFirstName() == null ? + // "" : sdncUserDetails.getFirstName(); + // String lastName = sdncUserDetails.getLastName() == null ? "" : + // sdncUserDetails.getLastName(); + // if (expectedUserFirstLastName.isEmpty()) { + // expectedUserFirstLastName = lastName; + // } else { + // expectedUserFirstLastName += " " + lastName; + // } + + assertEquals("check audit user name - ", formatedUser, addUserAuditMessageInfo.getUSER()); + + // String expectedUserUid = sdncUserDetails.getUserId(); + // assertEquals("check audit user uid - ", expectedUserUid, + // addUserAuditMessageInfo.getUSER_UID()); + // + // String expectedUserEmail = sdncUserDetails.getEmail() == null ? "" : + // sdncUserDetails.getEmail(); + // //TODO: esofer check with Andrey. Audit return "" but in user we have + // null + // assertEquals("check audit user email - ", expectedUserEmail, + // addUserAuditMessageInfo.getUSER_EMAIL()); + // + // String expectedUserRole = sdncUserDetails.getRole(); + // if (expectedUserRole ==null){ + // expectedUserRole = "DESIGNER"; + // assertEquals("check audit user role - ", expectedUserRole, + // addUserAuditMessageInfo.getUSER_ROLE()); + // }else{ + // assertEquals("check audit user role - ", expectedUserRole, + // addUserAuditMessageInfo.getUSER_ROLE()); + // } + + String expectedUserResponseCode = responseCode; + assertEquals("check audit user response code - ", expectedUserResponseCode, + addUserAuditMessageInfo.getSTATUS()); + + String expectedUserResponseMessage = responseMessage; + assertEquals("check audit user response message - ", expectedUserResponseMessage, + addUserAuditMessageInfo.getDESC()); + + } + + public static void validateDataAgainstAuditDB_access(User sdncUserDetails, UserAuditJavaObject auditJavaObject, + RestResponse restResponse, ErrorInfo errorInfo, List variables) { + + validateAuditDataAgainstAuditDbInAccess(sdncUserDetails, auditJavaObject, restResponse, errorInfo, variables); + + } + + public static void validateAuditDataAgainstAuditDbInAccess(User sdncUserDetails, + UserAuditJavaObject auditJavaObject, RestResponse restResponse, ErrorInfo errorInfo, + List variables) { + + String expected; + + expected = "Access"; + assertEquals("ACTION- ", expected, auditJavaObject.getACTION()); + + if (sdncUserDetails.getFirstName() != StringUtils.EMPTY && sdncUserDetails.getLastName() != StringUtils.EMPTY) { + expected = sdncUserDetails.getFirstName() + " " + sdncUserDetails.getLastName(); + } else { + expected = StringUtils.EMPTY; + } + String formatedUser = String.format("%s(%s)", expected, sdncUserDetails.getUserId()); + assertTrue( + "check audit user: expected start with - " + formatedUser + " ,actual - " + auditJavaObject.getUSER(), + auditJavaObject.getUSER().startsWith(formatedUser)); + + expected = restResponse.getErrorCode().toString(); + assertEquals("check audit user status code - ", expected, auditJavaObject.getSTATUS()); + + if (restResponse.getErrorCode() == 200 || restResponse.getErrorCode() == 201) { + expected = errorInfo.getMessage(); + } else { + expected = AuditValidationUtils.buildAuditDescription(errorInfo, variables); + } + + assertEquals("check audit user desc - ", expected, auditJavaObject.getDESC()); + + // expected = sdncUserDetails.getUserId(); + // assertEquals(expected, auditJavaObject.getUSER()); + + } + + public static void validateUserDetailsOnResponse(User sdncUserDetails, String userDetailsOnResponse) { + + String actualFirstName = Utils.getJsonObjectValueByKey(userDetailsOnResponse, "firstName"); + String expectedFirstName = sdncUserDetails.getFirstName(); + assertEquals("check user first name - ", expectedFirstName, actualFirstName); + + String actualLastName = Utils.getJsonObjectValueByKey(userDetailsOnResponse, "lastName"); + String expectedLastName = sdncUserDetails.getLastName(); + assertEquals("check user last name - ", expectedLastName, actualLastName); + + String actualUserId = Utils.getJsonObjectValueByKey(userDetailsOnResponse, "userId"); + String expectedUserId = sdncUserDetails.getUserId(); + assertEquals("check user userId - ", expectedUserId, actualUserId); + + String actualEmail = Utils.getJsonObjectValueByKey(userDetailsOnResponse, "email"); + String expectedEmail = sdncUserDetails.getEmail(); + assertEquals("check user email - ", expectedEmail, actualEmail); + + String actualRole = Utils.getJsonObjectValueByKey(userDetailsOnResponse, "role"); + if (sdncUserDetails.getRole() == null) { + String expectedRole = UserRoleEnum.DESIGNER.name(); + assertEquals("check user role - ", expectedRole, actualRole); + } else { + String expectedRole = sdncUserDetails.getRole(); + assertEquals("check user role - ", expectedRole, actualRole); + } + + String actualStatus = Utils.getJsonObjectValueByKey(userDetailsOnResponse, "status"); + String expectedStatus = sdncUserDetails.getStatus().name(); + assertEquals("check user status - ", expectedStatus, actualStatus); + + } + + public static AddUserAuditMessageInfo getAddUserAuditMessage(String action) throws Exception { + + Gson gson = new Gson(); + String index = "auditingevents*"; + String type = "useradminevent"; + String pattern = "/_search?q=ACTION:\"" + action + "\""; + String auditingMessage = DbUtils.retrieveAuditMessagesByPattern(pattern); + // String auditingMessage = retrieveAuditMessageByIndexType(index, type, + // pattern); + JsonElement jElement = new JsonParser().parse(auditingMessage); + JsonObject jObject = jElement.getAsJsonObject(); + JsonObject hitsObject = (JsonObject) jObject.get("hits"); + JsonArray hitsArray = (JsonArray) hitsObject.get("hits"); + // for (int i = 0; i < hitsArray.size();){ + if (hitsArray != null) { + JsonObject jHitObject = (JsonObject) hitsArray.get(0); + JsonObject jSourceObject = (JsonObject) jHitObject.get("_source"); + AddUserAuditMessageInfo addUserAuditMessageInfo = new AddUserAuditMessageInfo(); + addUserAuditMessageInfo = gson.fromJson(jSourceObject, AddUserAuditMessageInfo.class); + return addUserAuditMessageInfo; + } + return null; + + } + + public static void validateAddUserAuditMessage(User sdncUserDetails, User sdncModifierDetails, String responseCode, + String responseMessage, AddUserAuditMessageInfo addUserAuditMessageInfo) { + + String action = "AddUser"; + validateUserAuditMessage(sdncUserDetails, sdncModifierDetails, responseCode, responseMessage, + addUserAuditMessageInfo, action); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/webSealAccess/NeoJavaObject.java b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/webSealAccess/NeoJavaObject.java new file mode 100644 index 0000000000..0c19627bda --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/ci/tests/webSealAccess/NeoJavaObject.java @@ -0,0 +1,111 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.webSealAccess; + +public class NeoJavaObject { + + String userId; + String firstName; + String lastName; + String email; + String role; + String label; + String elementType; + + public NeoJavaObject(String userId, String firstName, String lastName, String email, String role, String label, + String elementType) { + super(); + this.userId = userId; + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.role = role; + this.label = label; + this.elementType = elementType; + } + + public NeoJavaObject() { + super(); + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getElementType() { + return elementType; + } + + public void setElementType(String elementType) { + this.elementType = elementType; + } + + @Override + public String toString() { + return "QueryUserNeo4jInfo [userId=" + userId + ", firstName=" + firstName + ", lastName=" + lastName + + ", email=" + email + ", role=" + role + ", label=" + label + ", elementType=" + elementType + "]"; + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/AssetLifeCycle.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/AssetLifeCycle.java new file mode 100644 index 0000000000..5ac70bf285 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/AssetLifeCycle.java @@ -0,0 +1,1146 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import static java.util.Arrays.asList; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.json.simple.parser.JSONParser; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceDetailedAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceExternalReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.SearchCriteriaEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.AssetRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtilsExternalAPI; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; +import com.google.gson.Gson; + +import fj.data.Either; + +public class AssetLifeCycle extends ComponentBaseTest { + + private static Logger log = LoggerFactory.getLogger(CRUDExternalAPI.class.getName()); + protected static final String UPLOAD_ARTIFACT_PAYLOAD = "UHVUVFktVXNlci1LZXktRmlsZS0yOiBzc2gtcnNhDQpFbmNyeXB0aW9uOiBhZXMyNTYtY2JjDQpDb21tZW5wOA0K"; + protected static final String UPLOAD_ARTIFACT_NAME = "TLV_prv.ppk"; + + protected Config config = Config.instance(); + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json"; + protected static User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + protected Gson gson = new Gson(); + protected JSONParser jsonParser = new JSONParser(); + + + protected String serviceVersion; + protected ResourceReqDetails resourceDetails; + protected User sdncUserDetails; + protected ServiceReqDetails serviceDetails; + + public static final int STATUS_CODE_SUCCESS = 200; + public static final int STATUS_CODE_CREATED = 201; + public static final int STATUS_CODE_DELETE = 204; + public static final int STATUS_CODE_NOT_FOUND = 404; + public static final int STATUS_CODE_SUCCESS_NO_CONTENT = 204; + public static final int STATUS_CODE_SUCCESS_DELETE = 204; + public static final int STATUS_CODE_INVALID_CONTENT = 400; + public static final int STATUS_CODE_MISSING_DATA = 400; + public static final int STATUS_CODE_MISSING_INFORMATION = 403; + public static final int STATUS_CODE_RESTRICTED_ACCESS = 403; + public static final int STATUS_CODE_ALREADY_EXISTS = 409; + public static final int STATUS_CODE_RESTRICTED_OPERATION = 409; + public static final int STATUS_CODE_COMPONENT_NAME_EXCEEDS_LIMIT = 400; + public static final int STATUS_CODE_MISSING_COMPONENT_NAME = 400; + public static final int STATUS_CODE_UNSUPPORTED_ERROR = 400; + public static final int STATUS_CODE_IMPORT_SUCCESS = 201; + public static final int STATUS_CODE_UPDATE_SUCCESS = 200; + public static final int RESTRICTED_OPERATION = 409; + public static final int STATUS_CODE_GET_SUCCESS = 200; + public static final int COMPONENT_IN_CHECKOUT_STATE = 403; + public static final int COMPONENT_ALREADY_CHECKED_IN = 409; + public static final int COMPONENT_NOT_READY_FOR_CERTIFICATION = 403; + public static final int COMPONENT_SENT_FOR_CERTIFICATION = 403; + public static final int COMPONENT_IN_CERT_IN_PROGRESS_STATE = 403; + public static final int COMPONENT_ALREADY_CERTIFIED = 403; + + + + @Rule + public static TestName name = new TestName(); + + public AssetLifeCycle() { + super(name, AssetLifeCycle.class.getName()); + + } + + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test + public void createResourceCheckInThenCheckOut() throws Exception { + User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ResourceExternalReqDetails defaultResource = ElementFactory.getDefaultResourceByType("ci", ResourceCategoryEnum.TEMPLATE_MONITORING_TEMPLATE, defaultUser.getUserId(), ResourceTypeEnum.VF.toString()); + + RestResponse restResponse = ResourceRestUtilsExternalAPI.createResource(defaultResource, defaultUser); + defaultResource.setVersion(String.format("%.1f",0.1)); + ResourceAssetStructure parsedCreatedResponse = gson.fromJson(restResponse.getResponse(), ResourceAssetStructure.class); + + restResponse = LifecycleRestUtils.checkInResource(parsedCreatedResponse.getUuid(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)STATUS_CODE_CREATED, "Fail to check in."); + + Component resourceDetails = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, defaultResource.getName(), defaultResource.getVersion()); + Assert.assertEquals(resourceDetails.getLifecycleState().toString(), LifeCycleStatesEnum.CHECKIN.getComponentState().toString(), "Life cycle state not changed."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, parsedCreatedResponse.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKIN, AssetTypeEnum.RESOURCES); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + restResponse = LifecycleRestUtils.checkOutResource(parsedCreatedResponse.getUuid(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)STATUS_CODE_CREATED, "Fail to check out."); + + resourceDetails = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, defaultResource.getName(), String.format("%.1f", Double.parseDouble(defaultResource.getVersion()) + 0.1)); + Assert.assertEquals(resourceDetails.getLifecycleState().toString(), LifeCycleStatesEnum.CHECKOUT.getComponentState().toString(), "Life cycle state not changed."); + + // auditing verification + body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, parsedCreatedResponse.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKOUT, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setCurrVersion("0.2"); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test + public void createServiceCheckInThenCheckOut() throws Exception { + User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + + Component resourceDetails = null; + Either createdComponent = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + resourceDetails = createdComponent.left().value(); + + RestResponse restResponse = LifecycleRestUtils.checkInService(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)STATUS_CODE_CREATED, "Fail to check in."); + + resourceDetails = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceDetails.getName(), resourceDetails.getVersion()); + Assert.assertEquals(resourceDetails.getLifecycleState().toString(), LifeCycleStatesEnum.CHECKIN.getComponentState().toString(), "Life cycle state not changed."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKIN, AssetTypeEnum.SERVICES); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + restResponse = LifecycleRestUtils.checkOutService(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)STATUS_CODE_CREATED, "Fail to check out."); + + resourceDetails = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceDetails.getName(), String.format("%.1f", Double.parseDouble(resourceDetails.getVersion()) + 0.1)); + Assert.assertEquals(resourceDetails.getLifecycleState().toString(), LifeCycleStatesEnum.CHECKOUT.getComponentState().toString(), "Life cycle state not changed."); + + // auditing verification + body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_CURR_STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKOUT, AssetTypeEnum.SERVICES); + expectedResourceAuditJavaObject.setCurrVersion("0.2"); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + @DataProvider(name="invalidAssetUUID") + public static Object[][] dataProviderInvalidAssetUUID() { + return new Object[][] { + {AssetTypeEnum.SERVICES, LifeCycleStatesEnum.CHECKIN}, + {AssetTypeEnum.RESOURCES, LifeCycleStatesEnum.CHECKIN}, + + {AssetTypeEnum.SERVICES, LifeCycleStatesEnum.CHECKOUT}, + {AssetTypeEnum.RESOURCES, LifeCycleStatesEnum.CHECKOUT}, + + {AssetTypeEnum.SERVICES, LifeCycleStatesEnum.CERTIFICATIONREQUEST}, + {AssetTypeEnum.RESOURCES, LifeCycleStatesEnum.CERTIFICATIONREQUEST}, + + {AssetTypeEnum.SERVICES, LifeCycleStatesEnum.STARTCERTIFICATION}, + {AssetTypeEnum.RESOURCES, LifeCycleStatesEnum.STARTCERTIFICATION}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidAssetUUID") + public void invalidAssetUUID(AssetTypeEnum assetTypeEnum, LifeCycleStatesEnum lifeCycleStatesEnum) throws Exception { + User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + String assetUUID = "InvalidAssetUUID"; + ErrorInfo errorInfo = null; + + RestResponse restResponse = null; + if(assetTypeEnum.equals(AssetTypeEnum.SERVICES)) { + + if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CHECKIN)) { + restResponse = LifecycleRestUtils.checkInService(assetUUID, defaultUser); + } else if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CHECKOUT)) { + restResponse = LifecycleRestUtils.checkOutService(assetUUID, defaultUser); + } else if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CERTIFICATIONREQUEST)) { + restResponse = LifecycleRestUtils.certificationRequestService(assetUUID, defaultUser); + } else if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.STARTCERTIFICATION)) { + restResponse = LifecycleRestUtils.startTestingService(assetUUID, defaultUser); + } + + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.SERVICE_NOT_FOUND.name()); + } else { + + if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CHECKIN)) { + restResponse = LifecycleRestUtils.checkInResource(assetUUID, defaultUser); + } else if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CHECKOUT)) { + restResponse = LifecycleRestUtils.checkOutResource(assetUUID, defaultUser); + } else if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CERTIFICATIONREQUEST)) { + restResponse = LifecycleRestUtils.certificationRequestResource(assetUUID, defaultUser); + } else if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.STARTCERTIFICATION)) { + restResponse = LifecycleRestUtils.startTestingResource(assetUUID, defaultUser); + } + + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESOURCE_NOT_FOUND.name()); + + } + Assert.assertEquals(restResponse.getErrorCode(), (Integer)STATUS_CODE_NOT_FOUND, "Asset found."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", assetTypeEnum.getValue().toLowerCase(), assetUUID, lifeCycleStatesEnum.getState())); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultInvalidChangeAssetLifeCycleExternalAPI(assetUUID, defaultUser, lifeCycleStatesEnum, assetTypeEnum); + + List variables = asList(assetUUID); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + @DataProvider(name="invalidUserCheckinForCheckedOutService") + public static Object[][] dataProviderInvalidUserCheckinForCheckedOutService() { + return new Object[][] { + {ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + // TODO: remove comment after talk with renana if it is defect or not +// {ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)}, + {ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR)}, + {ElementFactory.getDefaultUser(UserRoleEnum.OPS)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1)}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidUserCheckinForCheckedOutService") + public void invalidUserCheckinForCheckedOutService(User defaultUser) throws Exception { + Component resourceDetails = null; + Either createdComponent = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + resourceDetails = createdComponent.left().value(); + + RestResponse restResponse = LifecycleRestUtils.checkInService(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)RESTRICTED_OPERATION, "Expected for restricted operation."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKIN, AssetTypeEnum.SERVICES); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setStatus("409"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(""); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + @DataProvider(name="invalidUserCheckinForCheckedInService") + public static Object[][] dataProviderInvalidUserCheckinForCheckedInService() { + return new Object[][] { + {ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + // TODO: remove comment after talk with renana if it is defect or not +// {ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)}, + {ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR)}, + {ElementFactory.getDefaultUser(UserRoleEnum.OPS)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1)}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidUserCheckinForCheckedInService") + public void invalidUserCheckinForCheckedInService(User defaultUser) throws Exception { + Component resourceDetails = null; + Either createdComponent = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + resourceDetails = createdComponent.left().value(); + resourceDetails = AtomicOperationUtils.changeComponentState(resourceDetails, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + RestResponse restResponse = LifecycleRestUtils.checkInService(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)RESTRICTED_OPERATION, "Expected for restricted operation."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKIN, AssetTypeEnum.SERVICES); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setStatus("409"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(""); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + @DataProvider(name="invalidUserCheckoutForCheckedOutService") + public static Object[][] dataProviderInvalidUserCheckoutForCheckedOutService() { + return new Object[][] { + {ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + // TODO: remove comment after talk with renana if it is defect or not +// {ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)}, + {ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR)}, + {ElementFactory.getDefaultUser(UserRoleEnum.OPS)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1)}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidUserCheckoutForCheckedOutService") + public void invalidUserCheckoutForCheckedOutService(User defaultUser) throws Exception { + Component resourceDetails = null; + Either createdComponent = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + resourceDetails = createdComponent.left().value(); + + RestResponse restResponse = LifecycleRestUtils.checkOutService(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)RESTRICTED_OPERATION, "Expected for restricted operation."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKOUT, AssetTypeEnum.SERVICES); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setStatus("409"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(""); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + @DataProvider(name="invalidUserCheckoutForCheckedInService") + public static Object[][] dataProviderInvalidUserCheckoutForCheckedInService() { + return new Object[][] { + {ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + // TODO: remove comment after talk with renana if it is defect or not +// {ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)}, + {ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR)}, + {ElementFactory.getDefaultUser(UserRoleEnum.OPS)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1)}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidUserCheckoutForCheckedInService") + public void invalidUserCheckoutForCheckedInService(User defaultUser) throws Exception { + Component resourceDetails = null; + Either createdComponent = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + resourceDetails = createdComponent.left().value(); + resourceDetails = AtomicOperationUtils.changeComponentState(resourceDetails, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + RestResponse restResponse = LifecycleRestUtils.checkOutService(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)RESTRICTED_OPERATION, "Expected for restricted operation."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKOUT, AssetTypeEnum.SERVICES); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setStatus("409"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(""); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + @DataProvider(name="invalidUserCheckinForCheckedOutResource") + public static Object[][] dataProviderInvalidUserCheckinForCheckedOutResource() { + return new Object[][] { + {ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + // TODO: remove comment after talk with renana if it is defect or not +// {ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)}, + {ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR)}, + {ElementFactory.getDefaultUser(UserRoleEnum.OPS)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1)}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidUserCheckinForCheckedOutResource") + public void invalidUserCheckinForCheckedOutResource(User defaultUser) throws Exception { + Component resourceDetails = null; + Either createdComponent = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + resourceDetails = createdComponent.left().value(); + + RestResponse restResponse = LifecycleRestUtils.checkInResource(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)RESTRICTED_OPERATION, "Expected for restricted operation."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKIN, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setStatus("409"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(""); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + @DataProvider(name="invalidUserCheckinForCheckedInResource") + public static Object[][] dataProviderInvalidUserCheckinForCheckedInResource() { + return new Object[][] { + {ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + // TODO: remove comment after talk with renana if it is defect or not +// {ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)}, + {ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR)}, + {ElementFactory.getDefaultUser(UserRoleEnum.OPS)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1)}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidUserCheckinForCheckedInResource") + public void invalidUserCheckinForCheckedInResource(User defaultUser) throws Exception { + Component resourceDetails = null; + Either createdComponent = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + resourceDetails = createdComponent.left().value(); + resourceDetails = AtomicOperationUtils.changeComponentState(resourceDetails, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + RestResponse restResponse = LifecycleRestUtils.checkInResource(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)RESTRICTED_OPERATION, "Expected for restricted operation."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKIN, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setStatus("409"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(""); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + @DataProvider(name="invalidUserCheckoutForCheckedOutResource") + public static Object[][] dataProviderInvalidUserCheckoutForCheckedOutResource() { + return new Object[][] { + {ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + // TODO: remove comment after talk with renana if it is defect or not +// {ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)}, + {ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR)}, + {ElementFactory.getDefaultUser(UserRoleEnum.OPS)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1)}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidUserCheckoutForCheckedOutResource") + public void invalidUserCheckoutForCheckedOutResource(User defaultUser) throws Exception { + Component resourceDetails = null; + Either createdComponent = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + resourceDetails = createdComponent.left().value(); + + RestResponse restResponse = LifecycleRestUtils.checkOutResource(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)RESTRICTED_OPERATION, "Expected for restricted operation."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKOUT, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setStatus("409"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(""); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + @DataProvider(name="invalidUserCheckoutForCheckedInResource") + public static Object[][] dataProviderInvalidUserCheckoutForCheckedInResource() { + return new Object[][] { + {ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + // TODO: remove comment after talk with renana if it is defect or not +// {ElementFactory.getDefaultUser(UserRoleEnum.ADMIN)}, + {ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR)}, + {ElementFactory.getDefaultUser(UserRoleEnum.OPS)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_STRATEGIST1)}, + {ElementFactory.getDefaultUser(UserRoleEnum.PRODUCT_MANAGER1)}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidUserCheckoutForCheckedInResource") + public void invalidUserCheckoutForCheckedInResource(User defaultUser) throws Exception { + Component resourceDetails = null; + Either createdComponent = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + resourceDetails = createdComponent.left().value(); + resourceDetails = AtomicOperationUtils.changeComponentState(resourceDetails, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + RestResponse restResponse = LifecycleRestUtils.checkOutResource(resourceDetails.getUUID(), defaultUser); + Assert.assertEquals(restResponse.getErrorCode(), (Integer)RESTRICTED_OPERATION, "Expected for restricted operation."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CHECKOUT, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setStatus("409"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(""); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + + @DataProvider(name="invalidStatesForService") + public static Object[][] dataProviderInvalidStatesForService() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKIN, LifeCycleStatesEnum.CHECKIN, COMPONENT_ALREADY_CHECKED_IN, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, "409", ActionStatus.COMPONENT_ALREADY_CHECKED_IN, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), null}, + {LifeCycleStatesEnum.CHECKIN, LifeCycleStatesEnum.STARTCERTIFICATION, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + {LifeCycleStatesEnum.CHECKIN, LifeCycleStatesEnum.CERTIFY, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + + {LifeCycleStatesEnum.CHECKOUT, LifeCycleStatesEnum.CHECKOUT, COMPONENT_IN_CHECKOUT_STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, "403", ActionStatus.COMPONENT_IN_CHECKOUT_STATE, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), null}, + {LifeCycleStatesEnum.CHECKOUT, LifeCycleStatesEnum.STARTCERTIFICATION, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + {LifeCycleStatesEnum.CHECKOUT, LifeCycleStatesEnum.CERTIFY, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, LifeCycleStatesEnum.CERTIFICATIONREQUEST, COMPONENT_SENT_FOR_CERTIFICATION, LifecycleStateEnum.READY_FOR_CERTIFICATION, LifecycleStateEnum.READY_FOR_CERTIFICATION, "403", ActionStatus.COMPONENT_SENT_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), null}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, LifeCycleStatesEnum.CERTIFY, RESTRICTED_OPERATION, LifecycleStateEnum.READY_FOR_CERTIFICATION, LifecycleStateEnum.READY_FOR_CERTIFICATION, "409", ActionStatus.RESTRICTED_OPERATION, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), null}, + + {LifeCycleStatesEnum.STARTCERTIFICATION, LifeCycleStatesEnum.CHECKIN, COMPONENT_IN_CERT_IN_PROGRESS_STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, "403", ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.STARTCERTIFICATION, LifeCycleStatesEnum.CHECKOUT, COMPONENT_IN_CERT_IN_PROGRESS_STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, "403", ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.STARTCERTIFICATION, LifeCycleStatesEnum.CERTIFICATIONREQUEST, COMPONENT_IN_CERT_IN_PROGRESS_STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, "403", ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.STARTCERTIFICATION, LifeCycleStatesEnum.STARTCERTIFICATION, COMPONENT_IN_CERT_IN_PROGRESS_STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, "403", ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + + {LifeCycleStatesEnum.CERTIFY, LifeCycleStatesEnum.CHECKIN, COMPONENT_ALREADY_CERTIFIED, LifecycleStateEnum.CERTIFIED, LifecycleStateEnum.CERTIFIED, "403", ActionStatus.COMPONENT_ALREADY_CERTIFIED, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.CERTIFY, LifeCycleStatesEnum.CERTIFICATIONREQUEST, COMPONENT_ALREADY_CERTIFIED, LifecycleStateEnum.CERTIFIED, LifecycleStateEnum.CERTIFIED, "403", ActionStatus.COMPONENT_ALREADY_CERTIFIED, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.CERTIFY, LifeCycleStatesEnum.STARTCERTIFICATION, COMPONENT_ALREADY_CERTIFIED, LifecycleStateEnum.CERTIFIED, LifecycleStateEnum.CERTIFIED, "403", ActionStatus.COMPONENT_ALREADY_CERTIFIED, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + {LifeCycleStatesEnum.CERTIFY, LifeCycleStatesEnum.CERTIFY, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.CERTIFIED, LifecycleStateEnum.CERTIFIED, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidStatesForService") + public void invalidStatesForService(LifeCycleStatesEnum initState, LifeCycleStatesEnum targetState, int errorCode, + LifecycleStateEnum preState, LifecycleStateEnum currState, String status, + ActionStatus actionStatus, User user, User operationUser) throws Exception { + + if(initState.equals(LifeCycleStatesEnum.STARTCERTIFICATION) && targetState.equals(LifeCycleStatesEnum.CHECKIN)){ + throw new SkipException("Open bug DE270217"); + } + + getExtendTest().log(Status.INFO, String.format("initState: %s, targetState: %s, errorCode: %s," + + " preState: %s, currState: %s, status: %s, actionStatus: %s, user: %s, operationUser: %s", initState, targetState, errorCode, preState, + currState, status, actionStatus, user, operationUser)); + + + Either createdComponent = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + Component resourceDetails = createdComponent.left().value(); + + resourceDetails = AtomicOperationUtils.changeComponentState(resourceDetails, UserRoleEnum.DESIGNER, initState, true).getLeft(); + + RestResponse restResponse = null; + + if(targetState.equals(LifeCycleStatesEnum.CHECKOUT)) { + restResponse = LifecycleRestUtils.checkOutService(resourceDetails.getUUID(), user); + } else if(targetState.equals(LifeCycleStatesEnum.CHECKIN)) { + restResponse = LifecycleRestUtils.checkInService(resourceDetails.getUUID(), user); + } else if(targetState.equals(LifeCycleStatesEnum.CERTIFICATIONREQUEST)) { + restResponse = LifecycleRestUtils.certificationRequestService(resourceDetails.getUUID(), user); + } else if(targetState.equals(LifeCycleStatesEnum.STARTCERTIFICATION)) { + restResponse = LifecycleRestUtils.startTestingService(resourceDetails.getUUID(), user); + } else if(targetState.equals(LifeCycleStatesEnum.CERTIFY)) { + restResponse = LifecycleRestUtils.certifyService(resourceDetails.getUUID(), user); + } + + Assert.assertEquals(restResponse.getErrorCode(), (Integer)errorCode, "Expected that response code will be equal."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, user, targetState, AssetTypeEnum.SERVICES); + if(initState.equals(LifeCycleStatesEnum.CERTIFY)) { + expectedResourceAuditJavaObject.setCurrVersion("1.0"); + expectedResourceAuditJavaObject.setPrevVersion("1.0"); + } + expectedResourceAuditJavaObject.setPrevState(preState.toString()); + expectedResourceAuditJavaObject.setCurrState(currState.toString()); + expectedResourceAuditJavaObject.setStatus(status); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(actionStatus.name()); + List variables = null; + if(ActionStatus.RESTRICTED_OPERATION.equals(actionStatus)) { + variables = asList(""); + } else if(ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION.equals(actionStatus)) { + variables = asList(resourceDetails.getName(), AssetTypeEnum.SERVICES.getCorrespondingComponent().toLowerCase()); + } else { + if(operationUser == null) { + variables = asList(resourceDetails.getName(), AssetTypeEnum.SERVICES.getCorrespondingComponent().toLowerCase(), user.getFirstName(), user.getLastName(), user.getUserId()); + } else { + variables = asList(resourceDetails.getName(), AssetTypeEnum.SERVICES.getCorrespondingComponent().toLowerCase(), operationUser.getFirstName(), operationUser.getLastName(), operationUser.getUserId()); + } + + } + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + + + + + + + + + + + + + + @DataProvider(name="invalidStatesForResource") + public static Object[][] dataProviderInvalidStatesForResource() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKIN, LifeCycleStatesEnum.CHECKIN, COMPONENT_ALREADY_CHECKED_IN, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, "409", ActionStatus.COMPONENT_ALREADY_CHECKED_IN, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), null}, + {LifeCycleStatesEnum.CHECKIN, LifeCycleStatesEnum.STARTCERTIFICATION, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + {LifeCycleStatesEnum.CHECKIN, LifeCycleStatesEnum.CERTIFY, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, LifecycleStateEnum.NOT_CERTIFIED_CHECKIN, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + + {LifeCycleStatesEnum.CHECKOUT, LifeCycleStatesEnum.CHECKOUT, COMPONENT_IN_CHECKOUT_STATE, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, "403", ActionStatus.COMPONENT_IN_CHECKOUT_STATE, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), null}, + {LifeCycleStatesEnum.CHECKOUT, LifeCycleStatesEnum.STARTCERTIFICATION, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + {LifeCycleStatesEnum.CHECKOUT, LifeCycleStatesEnum.CERTIFY, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, LifeCycleStatesEnum.CERTIFICATIONREQUEST, COMPONENT_SENT_FOR_CERTIFICATION, LifecycleStateEnum.READY_FOR_CERTIFICATION, LifecycleStateEnum.READY_FOR_CERTIFICATION, "403", ActionStatus.COMPONENT_SENT_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), null}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, LifeCycleStatesEnum.CERTIFY, RESTRICTED_OPERATION, LifecycleStateEnum.READY_FOR_CERTIFICATION, LifecycleStateEnum.READY_FOR_CERTIFICATION, "409", ActionStatus.RESTRICTED_OPERATION, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), null}, + + {LifeCycleStatesEnum.STARTCERTIFICATION, LifeCycleStatesEnum.CHECKIN, COMPONENT_IN_CERT_IN_PROGRESS_STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, "403", ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.STARTCERTIFICATION, LifeCycleStatesEnum.CHECKOUT, COMPONENT_IN_CERT_IN_PROGRESS_STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, "403", ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.STARTCERTIFICATION, LifeCycleStatesEnum.CERTIFICATIONREQUEST, COMPONENT_IN_CERT_IN_PROGRESS_STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, "403", ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.STARTCERTIFICATION, LifeCycleStatesEnum.STARTCERTIFICATION, COMPONENT_IN_CERT_IN_PROGRESS_STATE, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, LifecycleStateEnum.CERTIFICATION_IN_PROGRESS, "403", ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + + {LifeCycleStatesEnum.CERTIFY, LifeCycleStatesEnum.CHECKIN, COMPONENT_ALREADY_CERTIFIED, LifecycleStateEnum.CERTIFIED, LifecycleStateEnum.CERTIFIED, "403", ActionStatus.COMPONENT_ALREADY_CERTIFIED, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.CERTIFY, LifeCycleStatesEnum.CERTIFICATIONREQUEST, COMPONENT_ALREADY_CERTIFIED, LifecycleStateEnum.CERTIFIED, LifecycleStateEnum.CERTIFIED, "403", ActionStatus.COMPONENT_ALREADY_CERTIFIED, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)}, + {LifeCycleStatesEnum.CERTIFY, LifeCycleStatesEnum.STARTCERTIFICATION, COMPONENT_ALREADY_CERTIFIED, LifecycleStateEnum.CERTIFIED, LifecycleStateEnum.CERTIFIED, "403", ActionStatus.COMPONENT_ALREADY_CERTIFIED, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + {LifeCycleStatesEnum.CERTIFY, LifeCycleStatesEnum.CERTIFY, COMPONENT_NOT_READY_FOR_CERTIFICATION, LifecycleStateEnum.CERTIFIED, LifecycleStateEnum.CERTIFIED, "403", ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), null}, + }; + } + + // US849997 - Story [BE]: External API for asset lifecycle - checkout + @Test(dataProvider="invalidStatesForResource") + public void invalidStatesForResource(LifeCycleStatesEnum initState, LifeCycleStatesEnum targetState, int errorCode, + LifecycleStateEnum preState, LifecycleStateEnum currState, String status, + ActionStatus actionStatus, User user, User operationUser) throws Exception { + getExtendTest().log(Status.INFO, String.format("initState: %s, targetState: %s, errorCode: %s," + + " preState: %s, currState: %s, status: %s, actionStatus: %s, user: %s, operationUser: %s", initState, targetState, errorCode, preState, + currState, status, actionStatus, user, operationUser)); + + if(initState.equals(LifeCycleStatesEnum.STARTCERTIFICATION) && targetState.equals(LifeCycleStatesEnum.CHECKIN)){ + throw new SkipException("Open bug DE270217"); + } + + Either createdComponent = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + Component resourceDetails = createdComponent.left().value(); + + resourceDetails = AtomicOperationUtils.changeComponentState(resourceDetails, UserRoleEnum.DESIGNER, initState, true).getLeft(); + + RestResponse restResponse = null; + + if(targetState.equals(LifeCycleStatesEnum.CHECKOUT)) { + restResponse = LifecycleRestUtils.checkOutResource(resourceDetails.getUUID(), user); + } else if(targetState.equals(LifeCycleStatesEnum.CHECKIN)) { + restResponse = LifecycleRestUtils.checkInResource(resourceDetails.getUUID(), user); + } else if(targetState.equals(LifeCycleStatesEnum.CERTIFICATIONREQUEST)) { + restResponse = LifecycleRestUtils.certificationRequestResource(resourceDetails.getUUID(), user); + } else if(targetState.equals(LifeCycleStatesEnum.STARTCERTIFICATION)) { + restResponse = LifecycleRestUtils.startTestingResource(resourceDetails.getUUID(), user); + } else if(targetState.equals(LifeCycleStatesEnum.CERTIFY)) { + restResponse = LifecycleRestUtils.certifyResource(resourceDetails.getUUID(), user); + } + + Assert.assertEquals(restResponse.getErrorCode(), (Integer)errorCode, "Expected that response code will be equal."); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, user, targetState, AssetTypeEnum.RESOURCES); + if(initState.equals(LifeCycleStatesEnum.CERTIFY)) { + expectedResourceAuditJavaObject.setCurrVersion("1.0"); + expectedResourceAuditJavaObject.setPrevVersion("1.0"); + } + expectedResourceAuditJavaObject.setPrevState(preState.toString()); + expectedResourceAuditJavaObject.setCurrState(currState.toString()); + expectedResourceAuditJavaObject.setStatus(status); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(actionStatus.name()); + List variables = null; + if(ActionStatus.RESTRICTED_OPERATION.equals(actionStatus)) { + variables = asList(""); + } else if(ActionStatus.COMPONENT_NOT_READY_FOR_CERTIFICATION.equals(actionStatus)) { + variables = asList(resourceDetails.getName(), AssetTypeEnum.RESOURCES.getCorrespondingComponent().toLowerCase()); + } else { + if(operationUser == null) { + variables = asList(resourceDetails.getName(), AssetTypeEnum.RESOURCES.getCorrespondingComponent().toLowerCase(), user.getFirstName(), user.getLastName(), user.getUserId()); + } else { + variables = asList(resourceDetails.getName(), AssetTypeEnum.RESOURCES.getCorrespondingComponent().toLowerCase(), operationUser.getFirstName(), operationUser.getLastName(), operationUser.getUserId()); + } + + } + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // US824692 - Story [BE]: External API for asset lifecycle - submit for test / start testing + @Test + public void BasicFlowForResourceSubmitForTestingStartTesting() throws Exception { + Either createdComponent = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + Component resourceDetails = createdComponent.left().value(); + RestResponse restResponse = LifecycleRestUtils.checkInResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Certification request + restResponse = LifecycleRestUtils.certificationRequestResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), resourceDetails.getUUID(), LifeCycleStatesEnum.CERTIFICATIONREQUEST.getState())); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CERTIFICATIONREQUEST, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.READY_FOR_CERTIFICATION.toString()); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + // Start testing + restResponse = LifecycleRestUtils.startTestingResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)); + + // Auditing verification + body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), resourceDetails.getUUID(), LifeCycleStatesEnum.STARTCERTIFICATION.getState())); + expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.READY_FOR_CERTIFICATION.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.toString()); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + // US824692 - Story [BE]: External API for asset lifecycle - submit for test / start testing + @Test + public void BasicFlowForServiceSubmitForTestingStartTesting() throws Exception { + Either createdComponent = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + Component resourceDetails = createdComponent.left().value(); + RestResponse restResponse = LifecycleRestUtils.checkInService(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Certification request + restResponse = LifecycleRestUtils.certificationRequestService(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.SERVICES.getValue().toLowerCase(), resourceDetails.getUUID(), LifeCycleStatesEnum.CERTIFICATIONREQUEST.getState())); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CERTIFICATIONREQUEST, AssetTypeEnum.SERVICES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.READY_FOR_CERTIFICATION.toString()); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + // Start testing + restResponse = LifecycleRestUtils.startTestingService(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)); + + // Auditing verification + body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.SERVICES.getValue().toLowerCase(), resourceDetails.getUUID(), LifeCycleStatesEnum.STARTCERTIFICATION.getState())); + expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION, AssetTypeEnum.SERVICES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.READY_FOR_CERTIFICATION.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.toString()); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + // US824692 - Story [BE]: External API for asset lifecycle - submit for test / start testing + @Test + public void specialCaseInvalidFlowForVfcmtSubmitForTesting() throws Exception { + Either createdComponent = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFCMT, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + Component resourceDetails = createdComponent.left().value(); + RestResponse restResponse = LifecycleRestUtils.checkInResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Certification request + restResponse = LifecycleRestUtils.certificationRequestResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), resourceDetails.getUUID(), LifeCycleStatesEnum.CERTIFICATIONREQUEST.getState())); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, defaultUser, LifeCycleStatesEnum.CERTIFICATIONREQUEST, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setStatus("400"); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESOURCE_VFCMT_LIFECYCLE_STATE_NOT_VALID.name()); + List variables = asList(LifeCycleStatesEnum.CERTIFICATIONREQUEST.getState()); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + // US824692 - Story [BE]: External API for asset lifecycle - submit for test / start testing + @Test + public void specialCaseInvalidFlowForVfcmtStartTesting() throws Exception { + Either createdComponent = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFCMT, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + Component resourceDetails = createdComponent.left().value(); + RestResponse restResponse = LifecycleRestUtils.checkInResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Certification request + restResponse = LifecycleRestUtils.startTestingResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)); + + // Auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), resourceDetails.getUUID(), LifeCycleStatesEnum.STARTCERTIFICATION.getState())); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.STARTCERTIFICATION, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setStatus("400"); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESOURCE_VFCMT_LIFECYCLE_STATE_NOT_VALID.name()); + List variables = asList(LifeCycleStatesEnum.STARTCERTIFICATION.getState()); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + + // US824692 - Story [BE]: External API for asset lifecycle - submit for test / start testing + @Test + public void BasicFlowForResourceCertify() throws Exception { + Either createdComponent = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, UserRoleEnum.DESIGNER, true); + Component resourceDetails = createdComponent.left().value(); + RestResponse restResponse = LifecycleRestUtils.checkInResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Certification request + restResponse = LifecycleRestUtils.certificationRequestResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Start testing + restResponse = LifecycleRestUtils.startTestingResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)); + + // Certify + restResponse = LifecycleRestUtils.certifyResource(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)); + + // Auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), resourceDetails.getUUID(), LifeCycleStatesEnum.CERTIFY.getState())); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.toString()); + expectedResourceAuditJavaObject.setCurrVersion("1.0"); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + } + + // US824692 - Story [BE]: External API for asset lifecycle - submit for test / start testing + @Test + public void BasicFlowForServiceCertify() throws Exception { + Either createdComponent = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true); + Component resourceDetails = createdComponent.left().value(); + RestResponse restResponse = LifecycleRestUtils.checkInService(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Certification request + restResponse = LifecycleRestUtils.certificationRequestService(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + + // Start testing + restResponse = LifecycleRestUtils.startTestingService(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)); + + // Certify + restResponse = LifecycleRestUtils.certifyService(resourceDetails.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER)); + + // Auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.SERVICES.getValue().toLowerCase(), resourceDetails.getUUID(), LifeCycleStatesEnum.CERTIFY.getState())); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.TESTER), LifeCycleStatesEnum.CERTIFY, AssetTypeEnum.SERVICES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.toString()); + expectedResourceAuditJavaObject.setCurrVersion("1.0"); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + } + + + + + + + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + @Test + public void theFlow() throws Exception { + User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ResourceExternalReqDetails defaultResource = ElementFactory.getDefaultResourceByType("ci", ResourceCategoryEnum.TEMPLATE_MONITORING_TEMPLATE, defaultUser.getUserId(), ResourceTypeEnum.VFCMT.toString()); + + // 1. Create VFCMT. + RestResponse restResponse = ResourceRestUtilsExternalAPI.createResource(defaultResource, defaultUser); + BaseRestUtils.checkCreateResponse(restResponse); + ResourceAssetStructure parsedCreatedResponse = gson.fromJson(restResponse.getResponse(), ResourceAssetStructure.class); + + // 2. Using search external API with resourceType=VFCMT to retrieve VFCMT. + restResponse = ResourceRestUtils.getResourceListFilterByCriteria(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), AssetTypeEnum.RESOURCES.getValue(), SearchCriteriaEnum.RESOURCE_TYPE.getValue(), ResourceTypeEnum.VFCMT.toString()); + BaseRestUtils.checkSuccess(restResponse); + ResourceAssetStructure dataOutOfSearchResponseForResourceName = ResponseParser.getDataOutOfSearchExternalAPIResponseForResourceName(restResponse.getResponse(), parsedCreatedResponse.getName()); + Assert.assertEquals(parsedCreatedResponse.getUuid(), dataOutOfSearchResponseForResourceName.getUuid(), "Created resourceUUID not equal to search retrive resourceUUID."); + + // 3. Use getSpecificMetadata external API to receive full information of the VFCMT. + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.RESOURCES, dataOutOfSearchResponseForResourceName.getUuid()); + BaseRestUtils.checkSuccess(assetResponse); + ResourceDetailedAssetStructure resourceAssetMetadata = AssetRestUtils.getResourceAssetMetadata(assetResponse); + Assert.assertEquals(resourceAssetMetadata.getUuid(), parsedCreatedResponse.getUuid(), "Created resourceUUID not equal to getSpecificMetadata resourceUUID."); + + // 4. Upload artifact via upload artifact external API. + Component initComponentVersion = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, parsedCreatedResponse.getName(), parsedCreatedResponse.getVersion()); + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", "OTHER", true, false); + RestResponse uploadArtifactRestResponse = ArtifactRestUtils.externalAPIUploadArtifactOfTheAsset(initComponentVersion, defaultUser, artifactReqDetails); + BaseRestUtils.checkSuccess(uploadArtifactRestResponse); + ArtifactDefinition responseArtifact = ArtifactRestUtils.getArtifactDataFromJson(uploadArtifactRestResponse.getResponse()); + initComponentVersion = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, parsedCreatedResponse.getName(), parsedCreatedResponse.getVersion()); + + // 5. Update artifact via external API. + CRUDExternalAPI crudExternalAPI = new CRUDExternalAPI(); + crudExternalAPI.updateArtifactOnAssetViaExternalAPI(initComponentVersion, ComponentTypeEnum.RESOURCE, LifeCycleStatesEnum.CHECKOUT, "OTHER"); + + + // 6. Use external API to checkin the VFCMT. + RestResponse checkInRestResponse = LifecycleRestUtils.checkInResource(initComponentVersion.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(checkInRestResponse); + parsedCreatedResponse = gson.fromJson(checkInRestResponse.getResponse(), ResourceAssetStructure.class); + Assert.assertEquals(parsedCreatedResponse.getVersion(), "0.1", "Expect that version will not change."); + Assert.assertEquals(parsedCreatedResponse.getUuid(), initComponentVersion.getUUID(), "Expect that UUID will not change."); + Assert.assertEquals(parsedCreatedResponse.getInvariantUUID(), initComponentVersion.getInvariantUUID(), "Expected that invariantUUID will not change."); + + // Auditing verification + AuditingActionEnum action = AuditingActionEnum.CHANGE_LIFECYCLE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, initComponentVersion.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), initComponentVersion.getUUID(), LifeCycleStatesEnum.CHECKIN.getState())); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(initComponentVersion, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKIN, AssetTypeEnum.RESOURCES); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + // 7. Then checkout the VFCMT via external API. + RestResponse checkOutRestResponse = LifecycleRestUtils.checkOutResource(initComponentVersion.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(checkOutRestResponse); + parsedCreatedResponse = gson.fromJson(checkOutRestResponse.getResponse(), ResourceAssetStructure.class); + Assert.assertEquals(parsedCreatedResponse.getVersion(), "0.2", "Expect that version will change to 0.2."); + Assert.assertEquals(parsedCreatedResponse.getUuid(), initComponentVersion.getUUID(), "Expect that UUID will not change."); + Assert.assertEquals(parsedCreatedResponse.getInvariantUUID(), initComponentVersion.getInvariantUUID(), "Expected that invariantUUID will not change."); + + // Auditing verification + body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, initComponentVersion.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), initComponentVersion.getUUID(), LifeCycleStatesEnum.CHECKOUT.getState())); + expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(initComponentVersion, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKOUT, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setCurrVersion("0.2"); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + // 8. The minor version must be incremented, the invariantUUID, and UUID must stay the same, the uniqueId should be changed, the artifacts from first version exists on the new version. + Component newComponentVersion = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, parsedCreatedResponse.getName(), String.format("%.1f", Double.parseDouble(parsedCreatedResponse.getVersion()))); + Assert.assertEquals(newComponentVersion.getInvariantUUID(), initComponentVersion.getInvariantUUID(), "Expected that invariantUUID will not change."); + Assert.assertEquals(newComponentVersion.getUUID(), initComponentVersion.getUUID(), "Expected that UUID will not change."); + Assert.assertNotEquals(newComponentVersion.getUniqueId(), initComponentVersion.getUniqueId(), "Expected that uniqueId will change."); + Assert.assertTrue(newComponentVersion.getDeploymentArtifacts().keySet().contains(responseArtifact.getArtifactLabel()), "Expected that artifact from first version exists on the new version."); + + // 9. The previous version remains untouched, the highest version flag on the first version is false, all information (metadata / artifacts) are the same on the first version. + initComponentVersion = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, parsedCreatedResponse.getName(), String.format("%.1f", Double.parseDouble("0.1"))); + Assert.assertEquals(initComponentVersion.isHighestVersion(), (Boolean)false, "Expected that highest version flag on first version is false."); + + // 10. Check in via external API. + checkInRestResponse = LifecycleRestUtils.checkInResource(initComponentVersion.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(checkInRestResponse); + parsedCreatedResponse = gson.fromJson(checkInRestResponse.getResponse(), ResourceAssetStructure.class); + Assert.assertEquals(parsedCreatedResponse.getVersion(), "0.2", "Expect that version will not change."); + Assert.assertEquals(parsedCreatedResponse.getUuid(), initComponentVersion.getUUID(), "Expect that UUID will not change."); + Assert.assertEquals(parsedCreatedResponse.getInvariantUUID(), initComponentVersion.getInvariantUUID(), "Expected that invariantUUID will not change."); + + // Auditing verification + body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, initComponentVersion.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), initComponentVersion.getUUID(), LifeCycleStatesEnum.CHECKIN.getState())); + expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(initComponentVersion, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKIN, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setCurrVersion("0.2"); + expectedResourceAuditJavaObject.setPrevVersion("0.2"); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + // 11. Certify via external API. + RestResponse certifyRestResponse = LifecycleRestUtils.certifyResource(initComponentVersion.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(certifyRestResponse); + parsedCreatedResponse = gson.fromJson(certifyRestResponse.getResponse(), ResourceAssetStructure.class); + Assert.assertEquals(parsedCreatedResponse.getVersion(), "1.0", "Expect that version will change to 1.0"); + Assert.assertEquals(parsedCreatedResponse.getUuid(), initComponentVersion.getUUID(), "Expect that UUID will not change."); + Assert.assertEquals(parsedCreatedResponse.getInvariantUUID(), initComponentVersion.getInvariantUUID(), "Expected that invariantUUID will not change."); + + // Auditing verification + body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, initComponentVersion.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), initComponentVersion.getUUID(), LifeCycleStatesEnum.CERTIFY.getState())); + expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(initComponentVersion, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CERTIFY, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.NOT_CERTIFIED_CHECKIN.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.CERTIFIED.toString()); + expectedResourceAuditJavaObject.setCurrVersion("1.0"); + expectedResourceAuditJavaObject.setPrevVersion("0.2"); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + // 12. Check out via external API. + checkOutRestResponse = LifecycleRestUtils.checkOutResource(initComponentVersion.getUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(checkOutRestResponse); + parsedCreatedResponse = gson.fromJson(checkOutRestResponse.getResponse(), ResourceAssetStructure.class); + Assert.assertEquals(parsedCreatedResponse.getVersion(), "1.1", "Expect that version will change to 1.1"); + Assert.assertNotEquals(parsedCreatedResponse.getUuid(), initComponentVersion.getUUID(), "Expect that UUID will change."); + Assert.assertEquals(parsedCreatedResponse.getInvariantUUID(), initComponentVersion.getInvariantUUID(), "Expected that invariantUUID will not change."); + + // Auditing verification + body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, initComponentVersion.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, String.format("/sdc/v1/catalog/%s/%s/lifecycleState/%s", AssetTypeEnum.RESOURCES.getValue().toLowerCase(), initComponentVersion.getUUID(), LifeCycleStatesEnum.CHECKOUT.getState())); + expectedResourceAuditJavaObject = ElementFactory.getDefaultChangeAssetLifeCycleExternalAPI(initComponentVersion, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), LifeCycleStatesEnum.CHECKOUT, AssetTypeEnum.RESOURCES); + expectedResourceAuditJavaObject.setPrevState(LifecycleStateEnum.CERTIFIED.toString()); + expectedResourceAuditJavaObject.setCurrState(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.toString()); + expectedResourceAuditJavaObject.setCurrVersion("1.1"); + expectedResourceAuditJavaObject.setPrevVersion("1.0"); + AuditValidationUtils.validateAuditExternalChangeAssetLifeCycle(expectedResourceAuditJavaObject, action.getName(), body); + + + } + + + + + + + + + + + + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/CRUDExternalAPI.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/CRUDExternalAPI.java new file mode 100644 index 0000000000..c3f9a723c2 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/CRUDExternalAPI.java @@ -0,0 +1,3528 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import static java.util.Arrays.asList; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.util.EntityUtils; +import org.codehaus.jackson.map.DeserializationConfig; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig.Feature; +import org.codehaus.jackson.map.annotate.JsonSerialize; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ArtifactUiDownloadData; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.DistributionNotificationStatusEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedExternalAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.AutomationUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.DistributionValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.config.EcompErrorName; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import fj.data.Either; + +public class CRUDExternalAPI extends ComponentBaseTest { + + private static Logger log = LoggerFactory.getLogger(CRUDExternalAPI.class.getName()); + protected static final String UPLOAD_ARTIFACT_PAYLOAD = "UHVUVFktVXNlci1LZXktRmlsZS0yOiBzc2gtcnNhDQpFbmNyeXB0aW9uOiBhZXMyNTYtY2JjDQpDb21tZW5wOA0K"; + protected static final String UPLOAD_ARTIFACT_NAME = "TLV_prv.ppk"; + + protected Config config = Config.instance(); + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json"; + + protected Gson gson = new Gson(); + protected JSONParser jsonParser = new JSONParser(); + + protected String serviceVersion; + protected ResourceReqDetails resourceDetails; + protected User sdncUserDetails; + protected ServiceReqDetails serviceDetails; + + @Rule + public static TestName name = new TestName(); + + public CRUDExternalAPI() { + super(name, CRUDExternalAPI.class.getName()); + } + + @DataProvider(name="uploadArtifactOnVfcVlCpViaExternalAPI" , parallel=true) + public static Object[][] dataProviderUploadArtifactOnVfcVlCpViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.CP}, + + {LifeCycleStatesEnum.CHECKIN, "YANG_XML", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "OTHER", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CHECKIN, "YANG_XML", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "OTHER", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKIN, "YANG_XML", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "OTHER", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.CP}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.CP} + }; + } + + // External API + // Upload artifact on VFC, VL, CP via external API - happy flow + @Test(dataProvider="uploadArtifactOnVfcVlCpViaExternalAPI") + public void uploadArtifactOnVfcVlCpViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s, resourceTypeEnum: %s", chosenLifeCycleState, artifactType, resourceTypeEnum)); + uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE, chosenLifeCycleState, artifactType, resourceTypeEnum); + } + + @DataProvider(name="uploadArtifactOnVFViaExternalAPI", parallel=true) + public static Object[][] dataProviderUploadArtifactOnVFViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "DCAE_JSON"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_POLICY"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_EVENT"}, + {LifeCycleStatesEnum.CHECKOUT, "APPC_CONFIG"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_DOC"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_TOSCA"}, + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE"}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_JSON"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_POLICY"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_EVENT"}, + {LifeCycleStatesEnum.CHECKIN, "APPC_CONFIG"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_DOC"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_TOSCA"}, + {LifeCycleStatesEnum.CHECKIN, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE"}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKIN, "OTHER"}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_JSON"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_POLICY"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_EVENT"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "APPC_CONFIG"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_DOC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_TOSCA"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER"} + }; + } + + // External API + // Upload artifact on VF via external API - happy flow + @Test(dataProvider="uploadArtifactOnVFViaExternalAPI") + public void uploadArtifactOnVFViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s", chosenLifeCycleState, artifactType)); + uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE, chosenLifeCycleState, artifactType, null); + } + + + @DataProvider(name="uploadArtifactOnServiceViaExternalAPI" , parallel=true) + public static Object[][] dataProviderUploadArtifactOnServiceViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {LifeCycleStatesEnum.CHECKIN, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER"} + }; + } + + + @Test(dataProvider="uploadArtifactOnServiceViaExternalAPI") + public void uploadArtifactOnServiceViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s", chosenLifeCycleState, artifactType)); + uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.SERVICE, chosenLifeCycleState, artifactType, null); + } + + + @DataProvider(name="uploadArtifactOnServiceViaExternalAPIIncludingDistribution", parallel=true) + public static Object[][] dataProviderUploadArtifactOnServiceViaExternalAPIIncludingDistribution() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML"}, + }; + } + + @Test(dataProvider="uploadArtifactOnServiceViaExternalAPIIncludingDistribution") + public void uploadArtifactOnServiceViaExternalAPIIncludingDistribution(LifeCycleStatesEnum chosenLifeCycleState, String artifactType) throws Exception { + if(true){ + throw new SkipException("Automated TC need repair."); + } + + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s", chosenLifeCycleState, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.SERVICE, chosenLifeCycleState, artifactType, null); + + component = AtomicOperationUtils.changeComponentState(component, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + if(config.getIsDistributionClientRunning()){ + List distributionStatusList = Arrays.asList(DistributionNotificationStatusEnum.DOWNLOAD_OK.toString(), DistributionNotificationStatusEnum.DEPLOY_OK.toString(), DistributionNotificationStatusEnum.NOTIFIED.toString()); + DistributionValidationUtils.validateDistributedArtifactsByAudit((Service)component, distributionStatusList); + } + } + + + // Happy flow - get chosen life cycle state, artifact type and asset type + // Create asset, upload artifact via external API + check audit & response code + // Download artifact via external API + check audit & response code + protected Component uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum componentTypeEnum, LifeCycleStatesEnum chosenLifeCycleState, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + Component component = null; + RestResponse restResponse; + int numberOfArtifact = 0; + + // get artifact data + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType, true, false); + + // create component/s & upload artifact via external api + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + component = getComponentWithResourceInstanceInTargetLifeCycleState(chosenLifeCycleState, resourceTypeEnum); + + restResponse = uploadArtifactOfRIIncludingValiditionOfAuditAndResponseCode(component, component.getComponentInstances().get(0), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, 200); + component =AtomicOperationUtils.getCompoenntObject(component, UserRoleEnum.DESIGNER); + + if((LifeCycleStatesEnum.CERTIFICATIONREQUEST == chosenLifeCycleState) && (!component.getComponentType().toString().equals(ComponentTypeEnum.RESOURCE.toString()))) { +// numberOfArtifact = component.getComponentInstances().get(0).getDeploymentArtifacts().size(); + numberOfArtifact = (component.getComponentInstances().get(0).getDeploymentArtifacts() == null ? 0 : component.getComponentInstances().get(0).getDeploymentArtifacts().size()); + } else { +// numberOfArtifact = component.getComponentInstances().get(0).getDeploymentArtifacts().size() + 1; + numberOfArtifact = (component.getComponentInstances().get(0).getDeploymentArtifacts() == null ? 0 : component.getComponentInstances().get(0).getDeploymentArtifacts().size()); + } + } else { + component = getComponentInTargetLifeCycleState(componentTypeEnum.toString(), UserRoleEnum.DESIGNER, chosenLifeCycleState, resourceTypeEnum); + + restResponse = uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, 200); + numberOfArtifact = component.getDeploymentArtifacts().size() + 1; + } + + + + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + component = getNewerVersionOfComponent(component, chosenLifeCycleState); + + // Get list of deployment artifact + download them via external API + Map deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + Assert.assertEquals(numberOfArtifact, deploymentArtifacts.keySet().size(), "Expected that number of deployment artifact will be increase by one."); + + // Download the uploaded artifact via external API + downloadResourceDeploymentArtifactExternalAPI(component, deploymentArtifacts.get(responseArtifact.getArtifactLabel()), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentTypeEnum); + + return component; + } + + // Upload artifact via external API + Check auditing for upload operation + Check response of external API + public RestResponse uploadArtifactOfRIIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, ComponentInstance componentInstance, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, Integer expectedResponseCode) throws Exception { + RestResponse restResponse = ArtifactRestUtils.externalAPIUploadArtifactOfComponentInstanceOnAsset(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, resourceDetails.getComponentInstances().get(0)); + + // Check response of external API + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + + // Check auditing for upload operation + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_UPLOAD_BY_API; + + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, componentInstance.getNormalizedName()); + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); + expectedExternalAudit.setRESOURCE_NAME(componentInstance.getNormalizedName()); + expectedExternalAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetTypeEnum.getValue() + "/" + resourceDetails.getUUID() + "/resourceInstances/" + componentInstance.getNormalizedName() + "/artifacts"); + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_UPLOAD_BY_API.getName(), body); + + return restResponse; + } + + + + + protected Component getComponentWithResourceInstanceInTargetLifeCycleState(LifeCycleStatesEnum lifeCycleStatesEnum, ResourceTypeEnum resourceTypeEnum) throws Exception { + Component component; + if(resourceTypeEnum == ResourceTypeEnum.VF) { + component = getComponentInTargetLifeCycleState(ComponentTypeEnum.SERVICE.toString(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, null); + + Component resourceInstanceDetails = getComponentInTargetLifeCycleState(ComponentTypeEnum.RESOURCE.getValue(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, null); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceInstanceDetails, component, UserRoleEnum.DESIGNER, true).left().value(); + + // Add artifact to service if asked for certifcationrequest - must be at least one artifact for the flow + if((LifeCycleStatesEnum.CERTIFICATIONREQUEST == lifeCycleStatesEnum) || (LifeCycleStatesEnum.STARTCERTIFICATION == lifeCycleStatesEnum)) { + } + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, component, UserRoleEnum.DESIGNER, true, true).left().value(); + component = AtomicOperationUtils.changeComponentState(component, UserRoleEnum.DESIGNER, lifeCycleStatesEnum, true).getLeft(); + } else { + component = getComponentInTargetLifeCycleState(ComponentTypeEnum.RESOURCE.toString(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, null); + Component resourceInstanceDetails = getComponentInTargetLifeCycleState(ComponentTypeEnum.RESOURCE.getValue(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, resourceTypeEnum); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceInstanceDetails, component, UserRoleEnum.DESIGNER, true).left().value(); + component = AtomicOperationUtils.changeComponentState(component, UserRoleEnum.DESIGNER, lifeCycleStatesEnum, true).getLeft(); + } + + + return component; + } + + + + + // Upload artifact via external API + Check auditing for upload operation + Check response of external API + protected RestResponse uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, Integer expectedResponseCode) throws Exception { + RestResponse restResponse = ArtifactRestUtils.externalAPIUploadArtifactOfTheAsset(resourceDetails, sdncModifierDetails, artifactReqDetails); + + // Check response of external API + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + + // Check auditing for upload operation + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_UPLOAD_BY_API; + + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_UPLOAD_BY_API.getName(), body); + + return restResponse; + } + + + + // Check Component version (increase by one if not in checkout) + // Input: component, componentLifeCycleState + // for any LifeCycleState != checkout + // find component of version +0.1 + // check that this version different for input version + // check that this component uniqueID different from input uniqueID + // Return: that version + protected Component getNewerVersionOfComponent(Component component, LifeCycleStatesEnum lifeCycleStatesEnum) throws Exception { + Component resourceDetails = null; + + if((!lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CHECKOUT)) && (!lifeCycleStatesEnum.equals(LifeCycleStatesEnum.STARTCERTIFICATION))) { + + + String resourceVersion = component.getVersion(); + String resourceUniqueID = component.getUniqueId(); + + if(component.getComponentType().equals(ComponentTypeEnum.SERVICE)) { + resourceDetails = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, component.getName(), String.format("%.1f", Double.parseDouble(component.getVersion()) + 0.1)); + } else { + resourceDetails = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, component.getName(), String.format("%.1f", Double.parseDouble(component.getVersion()) + 0.1)); + } + + String resourceNewVersion = resourceDetails.getVersion(); + String resourceNewUniqueID = resourceDetails.getUniqueId(); + + System.out.println(resourceNewVersion); + System.out.println("Service UUID: " + resourceDetails.getUUID()); + System.out.println("Service UniqueID: " + resourceDetails.getUniqueId()); + + // Checking that new version exist + different from old one by unique id + Assert.assertNotEquals(resourceVersion, resourceNewVersion, "Expected for diffrent resource version."); + Assert.assertNotEquals(resourceUniqueID, resourceNewUniqueID, "Expected that resource will have new unique ID."); + } else { + if(component.getComponentType().equals(ComponentTypeEnum.SERVICE)) { + resourceDetails = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, component.getName(), component.getVersion()); + } else { + resourceDetails = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, component.getName(), component.getVersion()); + } + } + return resourceDetails; + } + + + + + + // download deployment via external api + check response code for success (200) + get artifactReqDetails and verify payload + verify audit + protected RestResponse downloadResourceDeploymentArtifactExternalAPI(Component resourceDetails, ArtifactDefinition artifactDefinition, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, ComponentTypeEnum componentTypeEnum) throws Exception { + RestResponse restResponse; + + if(componentTypeEnum == ComponentTypeEnum.RESOURCE_INSTANCE) { + restResponse = ArtifactRestUtils.getComponentInstanceDeploymentArtifactExternalAPI(resourceDetails.getUUID(), resourceDetails.getComponentInstances().get(0).getNormalizedName(), artifactDefinition.getArtifactUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), resourceDetails.getComponentType().toString()); + } else { + restResponse = ArtifactRestUtils.getResourceDeploymentArtifactExternalAPI(resourceDetails.getUUID(), artifactDefinition.getArtifactUUID(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), resourceDetails.getComponentType().toString()); + } + + Integer responseCode = restResponse.getErrorCode(); + Integer expectedCode = 200; + Assert.assertEquals(responseCode,expectedCode, "Response code is not correct."); + + + // For known artifact/payload - verify payload of downloaded artfaict + if (artifactReqDetails != null) { + String response = restResponse.getResponse(); + String payloadData = artifactReqDetails.getPayload(); + String decodedPaypload = org.openecomp.sdc.ci.tests.utils.Decoder.decode(payloadData); + + Assert.assertEquals(response, decodedPaypload, "Response artifact payload not correct."); + } + + //TODO - including body - resourceDetails.getName() +// // Verify audit +// String auditAction = "DownloadArtifact"; +// +// Map body = new HashMap<>(); +// body.put(AuditingFieldsKeysEnum.AUDIT_STATUS, responseCode.toString()); +// body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); +// +// ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); +// expectedResourceAuditJavaObject.setAction(auditAction); +// expectedResourceAuditJavaObject.setResourceType(resourceDetails.getComponentType().getValue()); +// expectedResourceAuditJavaObject.setStatus("200"); +// expectedResourceAuditJavaObject.setDesc("OK"); +// expectedResourceAuditJavaObject.setCONSUMER_ID("ci"); +// +// if(componentTypeEnum == ComponentTypeEnum.RESOURCE_INSTANCE) { +// expectedResourceAuditJavaObject.setResourceName(resourceDetails.getComponentInstances().get(0).getName()); +// String resource_url = String.format("/sdc/v1/catalog/services/%s/resourceInstances/%s/artifacts/%s", resourceDetails.getUUID(), resourceDetails.getComponentInstances().get(0).getNormalizedName(), artifactDefinition.getArtifactUUID()); +// expectedResourceAuditJavaObject.setRESOURCE_URL(resource_url); +// +// AuditValidationUtils.validateAuditDownloadExternalAPI(expectedResourceAuditJavaObject, auditAction, null, false); +// } else { +// expectedResourceAuditJavaObject.setResourceName(resourceDetails.getName()); +// String resource_url = String.format("/sdc/v1/catalog/services/%s/artifacts/%s", resourceDetails.getUUID(), artifactDefinition.getArtifactUUID()); +// expectedResourceAuditJavaObject.setRESOURCE_URL(resource_url); +// } +// +// AuditValidationUtils.validateAuditDownloadExternalAPI(expectedResourceAuditJavaObject, auditAction, null, false); + + return restResponse; + + } + + // download deployment via external api + check response code for success (200) + verify audit + protected void downloadResourceDeploymentArtifactExternalAPI(Component resourceDetails, ArtifactDefinition artifactDefinition, User sdncModifierDetails) throws Exception { + downloadResourceDeploymentArtifactExternalAPI(resourceDetails, artifactDefinition, sdncModifierDetails, null, resourceDetails.getComponentType()); + } + + + + + + + + + + @DataProvider(name="uploadArtifactOnRIViaExternalAPI", parallel=true) + public static Object[][] dataProviderUploadArtifactOnRIViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT"}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL"}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP"}, + + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT"}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL"}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP"}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP"} + + }; + } + + + + + + @Test(dataProvider="uploadArtifactOnRIViaExternalAPI") + public void uploadArtifactOnRIViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s", chosenLifeCycleState, artifactType)); + uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE_INSTANCE, chosenLifeCycleState, artifactType, null); + } + + + + @DataProvider(name="uploadArtifactOnVfcVlCpRIViaExternalAPI", parallel=true) + public static Object[][] dataProviderUploadArtifactOnVfcVlCpRIViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.CP}, + + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.CP}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.CP} + + }; + } + + + + + + @Test(dataProvider="uploadArtifactOnVfcVlCpRIViaExternalAPI") + public void uploadArtifactOnVfcVlCpRIViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s", chosenLifeCycleState, artifactType)); + uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE_INSTANCE, chosenLifeCycleState, artifactType, resourceTypeEnum); + } + + + + + @DataProvider(name="uploadInvalidArtifactTypeExtensionLabelDescriptionCheckSumDuplicateLabelViaExternalAPI", parallel=true) + public static Object[][] dataProviderUploadInvalidArtifactTypeExtensionLabelDescriptionCheckSumDuplicateLabelViaExternalAPI() { + return new Object[][] { + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidTypeToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidTypeToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidTypeToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidTypeToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidTypeToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidTypeToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidTypeToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidTypeToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidTypeToLong"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidTypeEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidTypeEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidTypeEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidTypeEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidTypeEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidTypeEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidTypeEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidTypeEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidTypeEmpty"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidNameToLong"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidNameEmpty"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidLabelToLong"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidLabelEmpty"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidDescriptionToLong"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidDescriptionEmpty"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithSameLabel"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithSameLabel"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithSameLabel"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithSameLabel"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithSameLabel"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithSameLabel"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithSameLabel"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithSameLabel"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithSameLabel"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "uploadArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "uploadArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "uploadArtifactWithInvalidCheckSum"}, + }; + } + + + + + // InvalidArtifact + check audit & response code function + @Test(dataProvider="uploadInvalidArtifactTypeExtensionLabelDescriptionCheckSumDuplicateLabelViaExternalAPI") + public void uploadInvalidArtifactTypeExtensionLabelDescriptionCheckSumDuplicateLabelViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, + ComponentTypeEnum componentTypeEnum, String uploadArtifactTestType) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, componentTypeEnum: %s, uploadArtifactTestType: %s", chosenLifeCycleState, componentTypeEnum, uploadArtifactTestType)); + Component resourceDetails; + ComponentInstance componentResourceInstanceDetails = null; + ArtifactReqDetails artifactReqDetails; + + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + artifactReqDetails = ElementFactory.getArtifactByType("Abcd", ArtifactTypeEnum.DCAE_INVENTORY_DOC.toString(), true, false); + + resourceDetails = getComponentInTargetLifeCycleState(ComponentTypeEnum.SERVICE.toString(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, null); + resourceDetails = getComponentWithResourceInstanceInTargetLifeCycleState(chosenLifeCycleState, null); + componentResourceInstanceDetails = resourceDetails.getComponentInstances().get(0); + } else { + artifactReqDetails = ElementFactory.getArtifactByType("Abcd", ArtifactTypeEnum.OTHER.toString(), true, false); + + resourceDetails = getComponentInTargetLifeCycleState(componentTypeEnum.toString(), UserRoleEnum.DESIGNER, chosenLifeCycleState, null); + } + + + switch (uploadArtifactTestType) { + case "uploadArtifactWithInvalidTypeToLong": + uploadArtifactWithInvalidTypeToLong(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + case "uploadArtifactWithInvalidTypeEmpty": + uploadArtifactWithInvalidTypeEmpty(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + case "uploadArtifactWithInvalidCheckSum": + uploadArtifactWithInvalidCheckSum(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + case "uploadArtifactWithInvalidNameToLong": + uploadArtifactWithInvalidNameToLong(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + case "uploadArtifactWithInvalidNameEmpty": + uploadArtifactWithInvalidNameEmpty(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + case "uploadArtifactWithInvalidLabelToLong": + uploadArtifactWithInvalidLabelToLong(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + case "uploadArtifactWithInvalidLabelEmpty": + uploadArtifactWithInvalidLabelEmpty(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + case "uploadArtifactWithInvalidDescriptionToLong": + uploadArtifactWithInvalidDescriptionToLong(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + case "uploadArtifactWithInvalidDescriptionEmpty": + uploadArtifactWithInvalidDescriptionEmpty(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + case "uploadArtifactWithSameLabel": + default: + uploadArtifactWithSameLabel(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + break; + } + } + + // Upload artifact with invalid type via external API - to long type + protected void uploadArtifactWithInvalidTypeToLong(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + artifactReqDetails.setArtifactType("dsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfdsdsfdsfds"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name()); + List variables = asList(artifactReqDetails.getArtifactType()); + + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables, null, false); + } + + // Upload artifact with invalid type via external API - empty type + protected void uploadArtifactWithInvalidTypeEmpty(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + artifactReqDetails.setArtifactType(""); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_TYPE_NOT_SUPPORTED.name()); + List variables = asList(artifactReqDetails.getArtifactType()); + + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables, null, false); + } + + // Upload artifact with invalid checksum via external API + protected void uploadArtifactWithInvalidCheckSum(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_INVALID_MD5.name()); + List variables = asList(); + uploadArtifactWithInvalidCheckSumOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables); + } + + + // Upload artifact with valid type & invalid name via external API - name to long + protected void uploadArtifactWithInvalidNameToLong(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.EXCEEDS_LIMIT.name()); + List variables = asList("artifact name", "255"); + artifactReqDetails.setArtifactName("invalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidType"); + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables, null, false); + } + + + // Upload artifact with valid type & invalid name via external API - name is empty + protected void uploadArtifactWithInvalidNameEmpty(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_ARTIFACT_NAME.name()); + List variables = asList(); + + artifactReqDetails.setArtifactName(""); + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables, null, false); + } + + + // Upload artifact with valid type & invalid label via external API - label to long + protected void uploadArtifactWithInvalidLabelToLong(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.EXCEEDS_LIMIT.name()); + List variables = asList("artifact label", "255"); + artifactReqDetails.setArtifactLabel("invalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidType"); + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables, null, false); + } + + + // Upload artifact with valid type & invalid label via external API - label is empty + protected void uploadArtifactWithInvalidLabelEmpty(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + List variables = asList("artifact label"); + artifactReqDetails.setArtifactLabel(""); + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables, null, false); + } + + + // Upload artifact with invalid description via external API - to long description + protected void uploadArtifactWithInvalidDescriptionToLong(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.EXCEEDS_LIMIT.name()); + List variables = asList("artifact description", "256"); + artifactReqDetails.setDescription("invalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidType"); + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables, null, false); + } + + + // Upload artifact with invalid description via external API - empty description + protected void uploadArtifactWithInvalidDescriptionEmpty(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + List variables = asList("artifact description"); + artifactReqDetails.setDescription(""); + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables, null, false); + } + + + + + // Upload artifact with same label via external API + protected void uploadArtifactWithSameLabel(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + ComponentInstance componentResourceInstanceDetails) throws Exception { + + RestResponse restResponse = null; + if(componentResourceInstanceDetails != null) { + restResponse = ArtifactRestUtils.externalAPIUploadArtifactOfComponentInstanceOnAsset(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + } else { + restResponse = ArtifactRestUtils.externalAPIUploadArtifactOfTheAsset(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails); + + } + + ArtifactDefinition artifactDefinition = getArtifactDataFromJson(restResponse.getResponse()); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_EXIST.name()); + + List variables = asList(artifactDefinition.getArtifactDisplayName()); + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables, null, false); + } + + protected RestResponse uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + Integer expectedResponseCode, ComponentInstance componentResourceInstanceDetails, ErrorInfo errorInfo, List variables, LifeCycleStatesEnum lifeCycleStatesEnum, Boolean includeResourceNameInAudit) throws Exception { + RestResponse restResponse; + + if(componentResourceInstanceDetails != null) { + restResponse = ArtifactRestUtils.externalAPIUploadArtifactOfComponentInstanceOnAsset(resourceDetails, sdncModifierDetails, artifactReqDetails, componentResourceInstanceDetails); + } else { + restResponse = ArtifactRestUtils.externalAPIUploadArtifactOfTheAsset(resourceDetails, sdncModifierDetails, artifactReqDetails); + + } + + // validate response code + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + // Check auditing for upload operation + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_UPLOAD_BY_API; + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); +// ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); + + responseArtifact.setUpdaterFullName(""); + responseArtifact.setUserIdLastUpdater(sdncModifierDetails.getUserId()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditFailure(assetTypeEnum, action, responseArtifact, resourceDetails.getUUID(), errorInfo, variables); + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getName()); + expectedExternalAudit.setRESOURCE_TYPE(resourceDetails.getComponentType().getValue()); + expectedExternalAudit.setARTIFACT_DATA(null); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_STATUS, responseCode.toString()); + if(componentResourceInstanceDetails != null) { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getComponentInstances().get(0).getNormalizedName()); + expectedExternalAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetTypeEnum.getValue() + "/" + resourceDetails.getUUID() + "/resourceInstances/" + resourceDetails.getComponentInstances().get(0).getNormalizedName() + "/artifacts"); + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getComponentInstances().get(0).getNormalizedName()); + } else { + if(includeResourceNameInAudit) { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + } else { + if((lifeCycleStatesEnum == LifeCycleStatesEnum.CHECKIN) || (lifeCycleStatesEnum == LifeCycleStatesEnum.STARTCERTIFICATION)) { + expectedExternalAudit.setRESOURCE_NAME(""); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, ""); + } else { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + } + } + } + + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_UPLOAD_BY_API.getName(), body); + + return restResponse; + + } + + + + + + + protected RestResponse uploadArtifactWithInvalidCheckSumOfAssetIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, + Integer expectedResponseCode, ComponentInstance componentResourceInstanceDetails, ErrorInfo errorInfo, List variables) throws Exception { + RestResponse restResponse; + + if(componentResourceInstanceDetails != null) { + restResponse = ArtifactRestUtils.externalAPIUploadArtifactWithInvalidCheckSumOfComponentInstanceOnAsset(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentResourceInstanceDetails); + } else { + restResponse = ArtifactRestUtils.externalAPIUploadArtifactWithInvalidCheckSumOfTheAsset(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails); + + } + + // validate response code + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + // Check auditing for upload operation +// ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS.name()); +// = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.EXCEEDS_LIMIT.name()); +// List variables = asList("artifact name", "255"); + + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_UPLOAD_BY_API; + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); +// ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); + + responseArtifact.setUpdaterFullName(""); + responseArtifact.setUserIdLastUpdater(sdncModifierDetails.getUserId()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditFailure(assetTypeEnum, action, responseArtifact, resourceDetails.getUUID(), errorInfo, variables); + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getName()); + expectedExternalAudit.setRESOURCE_TYPE(resourceDetails.getComponentType().getValue()); + expectedExternalAudit.setARTIFACT_DATA(null); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_STATUS, responseCode.toString()); + if(componentResourceInstanceDetails != null) { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getComponentInstances().get(0).getNormalizedName()); + expectedExternalAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetTypeEnum.getValue() + "/" + resourceDetails.getUUID() + "/resourceInstances/" + resourceDetails.getComponentInstances().get(0).getNormalizedName() + "/artifacts"); + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getComponentInstances().get(0).getNormalizedName()); + } else { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + } + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_UPLOAD_BY_API.getName(), body); + + return restResponse; + + } + + + + + + + + + @DataProvider(name="uploadArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset", parallel=true) + public static Object[][] dataProviderUploadArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset() { + return new Object[][] { + {ComponentTypeEnum.RESOURCE, UserRoleEnum.DESIGNER2, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.DESIGNER2, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.DESIGNER2, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKOUT}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKOUT}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKOUT}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKOUT}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKOUT}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKIN}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKOUT}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKOUT}, + }; + } + + + // External API + // Upload artifact by diffrent user then creator of asset - Fail + @Test(dataProvider="uploadArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset") + public void uploadArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset(ComponentTypeEnum componentTypeEnum, UserRoleEnum userRoleEnum, LifeCycleStatesEnum lifeCycleStatesEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("componentTypeEnum: %s, userRoleEnum: %s, lifeCycleStatesEnum: %s", componentTypeEnum, userRoleEnum, lifeCycleStatesEnum)); + Component resourceDetails; + ComponentInstance componentResourceInstanceDetails = null; + ArtifactReqDetails artifactReqDetails; + + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + artifactReqDetails = ElementFactory.getArtifactByType("Abcd", ArtifactTypeEnum.DCAE_INVENTORY_DOC.toString(), true, false); + + resourceDetails = getComponentWithResourceInstanceInTargetLifeCycleState(lifeCycleStatesEnum, null); + componentResourceInstanceDetails = resourceDetails.getComponentInstances().get(0); + } else { + artifactReqDetails = ElementFactory.getArtifactByType("Abcd", ArtifactTypeEnum.OTHER.toString(), true, false); + + resourceDetails = getComponentInTargetLifeCycleState(componentTypeEnum.toString(), UserRoleEnum.DESIGNER, lifeCycleStatesEnum, null); + } + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(); + + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(userRoleEnum), + artifactReqDetails, 409, componentResourceInstanceDetails, errorInfo, variables, lifeCycleStatesEnum, true); + +// if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CHECKIN)) { +// performeClean(); +// } + } + + + + + + @DataProvider(name="uploadArtifactOnAssetWhichNotExist", parallel=true) + public static Object[][] dataProviderUploadArtifactOnAssetWhichNotExist() { + return new Object[][] { + {ComponentTypeEnum.SERVICE}, + {ComponentTypeEnum.RESOURCE}, + {ComponentTypeEnum.RESOURCE_INSTANCE}, + }; + } + + + // External API + // Upload artifact on VF via external API - happy flow + @Test(dataProvider="uploadArtifactOnAssetWhichNotExist") + public void uploadArtifactOnAssetWhichNotExist(ComponentTypeEnum componentTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("componentTypeEnum: %s", componentTypeEnum)); + Component resourceDetails; + ComponentInstance componentResourceInstanceDetails = null; + ArtifactReqDetails artifactReqDetails; + + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + artifactReqDetails = ElementFactory.getArtifactByType("Abcd", ArtifactTypeEnum.DCAE_INVENTORY_DOC.toString(), true, false); + + resourceDetails = getComponentWithResourceInstanceInTargetLifeCycleState(LifeCycleStatesEnum.CHECKIN, null); + componentResourceInstanceDetails = resourceDetails.getComponentInstances().get(0); + + resourceDetails.setUUID("12345"); + componentResourceInstanceDetails.setNormalizedName("12345"); + } else { + artifactReqDetails = ElementFactory.getArtifactByType("Abcd", "OTHER", true, false); + + resourceDetails = getComponentInTargetLifeCycleState(componentTypeEnum.toString(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, null); + + resourceDetails.setUUID("12345"); + } + + String componentTypeError = ActionStatus.RESOURCE_NOT_FOUND.name(); + if (ComponentTypeEnum.SERVICE == componentTypeEnum){ + componentTypeError = ActionStatus.SERVICE_NOT_FOUND.name(); + } + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(componentTypeError); + List variables = asList(resourceDetails.getUUID()); + + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 404, componentResourceInstanceDetails, errorInfo, variables, LifeCycleStatesEnum.CHECKIN, false); + +// performeClean(); + + } + + + @DataProvider(name="uploadArtifactOnAssetWhichInInvalidStateForUploading", parallel=true) + public static Object[][] dataProviderUploadArtifactOnAssetWhichInInvalidStateForUploading() { + return new Object[][] { + {ComponentTypeEnum.SERVICE}, + {ComponentTypeEnum.RESOURCE}, + {ComponentTypeEnum.RESOURCE_INSTANCE}, + }; + } + + + @Test(dataProvider="uploadArtifactOnAssetWhichInInvalidStateForUploading") + public void uploadArtifactOnAssetWhichInInvalidStateForUploading(ComponentTypeEnum componentTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("componentTypeEnum: %s", componentTypeEnum)); + Component resourceDetails; + ComponentInstance componentResourceInstanceDetails = null; + ArtifactReqDetails artifactReqDetails; + + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + artifactReqDetails = ElementFactory.getArtifactByType("Abcd", ArtifactTypeEnum.DCAE_INVENTORY_DOC.toString(), true, false); + + resourceDetails = getComponentWithResourceInstanceInTargetLifeCycleState(LifeCycleStatesEnum.STARTCERTIFICATION, null); + componentResourceInstanceDetails = resourceDetails.getComponentInstances().get(0); + } else { + artifactReqDetails = ElementFactory.getArtifactByType("Abcd", ArtifactTypeEnum.OTHER.toString(), true, false); + + resourceDetails = getComponentInTargetLifeCycleState(componentTypeEnum.toString(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.STARTCERTIFICATION, null); + } + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE.name()); + List variables = asList(resourceDetails.getName(), resourceDetails.getComponentType().toString().toLowerCase(), resourceDetails.getLastUpdaterFullName().split(" ")[0], + resourceDetails.getLastUpdaterFullName().split(" ")[1], resourceDetails.getLastUpdaterUserId()); + + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + artifactReqDetails, 403, componentResourceInstanceDetails, errorInfo, variables, LifeCycleStatesEnum.STARTCERTIFICATION, true); + } + + + //////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////// + // Update External API // + //////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////// + + @DataProvider(name="updateArtifactForServiceViaExternalAPI", parallel=true) + public static Object[][] dataProviderUpdateArtifactForServiceViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {LifeCycleStatesEnum.CHECKIN, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER"}, + {LifeCycleStatesEnum.CERTIFY, "YANG_XML"}, + {LifeCycleStatesEnum.CERTIFY, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CERTIFY, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CERTIFY, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CERTIFY, "OTHER"} + }; + } + + + + + // Update artifact for Service - Success + @Test(dataProvider="updateArtifactForServiceViaExternalAPI") + public void updateArtifactForServiceViaExternalAPI(LifeCycleStatesEnum lifeCycleStatesEnum, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("lifeCycleStatesEnum: %s, artifactType: %s", lifeCycleStatesEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.SERVICE, LifeCycleStatesEnum.CHECKOUT, artifactType, null); + updateArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.SERVICE, lifeCycleStatesEnum, artifactType); + + // for certify version check that previous version exist, and that it artifact can be download + checksum + if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CERTIFY)) { + // Download the uploaded artifact via external API + downloadResourceDeploymentArtifactExternalAPIAndComparePayLoadOfArtifactType(component, artifactType, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ComponentTypeEnum.SERVICE); + } + } + + @DataProvider(name="updateArtifactForVFViaExternalAPI", parallel=true) + public static Object[][] dataProviderUpdateArtifactForVFViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "DCAE_JSON"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_POLICY"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_EVENT"}, + {LifeCycleStatesEnum.CHECKOUT, "APPC_CONFIG"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_DOC"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_TOSCA"}, + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE"}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_JSON"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_POLICY"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_EVENT"}, + {LifeCycleStatesEnum.CHECKIN, "APPC_CONFIG"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_DOC"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_TOSCA"}, + {LifeCycleStatesEnum.CHECKIN, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE"}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKIN, "OTHER"}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_JSON"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_POLICY"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_EVENT"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "APPC_CONFIG"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_DOC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_TOSCA"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER"} + }; + } + + + // Update artifact for VF - Success + @Test(dataProvider="updateArtifactForVFViaExternalAPI") + public void updateArtifactForVFViaExternalAPI(LifeCycleStatesEnum lifeCycleStatesEnum, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("lifeCycleStatesEnum: %s, artifactType: %s", lifeCycleStatesEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE, LifeCycleStatesEnum.CHECKOUT, artifactType, null); + updateArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.RESOURCE, lifeCycleStatesEnum, artifactType); + + // for certify version check that previous version exist, and that it artifact can be download + checksum + if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CERTIFY)) { + // Download the uploaded artifact via external API + downloadResourceDeploymentArtifactExternalAPIAndComparePayLoadOfArtifactType(component, artifactType, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ComponentTypeEnum.RESOURCE); + } + } + + @DataProvider(name="updateArtifactForVfcVlCpViaExternalAPI", parallel=true) + public static Object[][] dataProviderUpdateArtifactForVfcVlCpViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.CP}, + + {LifeCycleStatesEnum.CHECKIN, "YANG_XML", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "OTHER", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CHECKIN, "YANG_XML", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "OTHER", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKIN, "YANG_XML", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "OTHER", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.CP}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.CP} + }; + } + + + // Update artifact for VFC/VL/CP - Success + @Test(dataProvider="updateArtifactForVfcVlCpViaExternalAPI") + public void updateArtifactForVfcVlCpViaExternalAPI(LifeCycleStatesEnum lifeCycleStatesEnum, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("lifeCycleStatesEnum: %s, artifactType: %s, resourceTypeEnum: %s", lifeCycleStatesEnum, artifactType, resourceTypeEnum)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE, LifeCycleStatesEnum.CHECKOUT, artifactType, resourceTypeEnum); + updateArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.RESOURCE, lifeCycleStatesEnum, artifactType); + + // for certify version check that previous version exist, and that it artifact can be download + checksum + if(lifeCycleStatesEnum.equals(LifeCycleStatesEnum.CERTIFY)) { + // Download the uploaded artifact via external API + downloadResourceDeploymentArtifactExternalAPIAndComparePayLoadOfArtifactType(component, artifactType, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ComponentTypeEnum.RESOURCE); + } + } + + @DataProvider(name="updateArtifactOfVfcVlCpForVfciVliCpiViaExternalAPI", parallel=true) + public static Object[][] dataProviderUpdateArtifactOfVfcVlCpForVfciVliCpiViaExternalAPI() { + return new Object[][] { + {ResourceTypeEnum.VFC}, + {ResourceTypeEnum.VL}, + {ResourceTypeEnum.CP} + }; + } + + + // Verify that it cannot update VFC/VL/CP artifact on VFCi/VLi/CPi - Failure flow + @Test(dataProvider="updateArtifactOfVfcVlCpForVfciVliCpiViaExternalAPI") + public void updateArtifactOfVfcVlCpForVfciVliCpiViaExternalAPI(ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("resourceTypeEnum: %s", resourceTypeEnum)); + + Component resourceInstanceDetails = getComponentInTargetLifeCycleState(ComponentTypeEnum.RESOURCE.getValue(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, resourceTypeEnum); + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", "SNMP_TRAP", true, false); + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceInstanceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, 200); + resourceInstanceDetails = AtomicOperationUtils.changeComponentState(resourceInstanceDetails, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + Component component = getComponentInTargetLifeCycleState(ComponentTypeEnum.RESOURCE.toString(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, null); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceInstanceDetails, component, UserRoleEnum.DESIGNER, true).left().value(); + component = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, component.getName(), component.getVersion()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_NOT_FOUND.name()); + Map deploymentArtifacts; + deploymentArtifacts = getDeploymentArtifactsOfAsset(component, ComponentTypeEnum.RESOURCE_INSTANCE); + String artifactUUID = null; + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci") && StringUtils.isNotEmpty(deploymentArtifacts.get(key).getArtifactUUID())) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + List variables = asList(artifactUUID); + updateArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.RESOURCE_INSTANCE, LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", errorInfo, variables, UserRoleEnum.DESIGNER, 404); + + } + + + + + + @DataProvider(name="updateArtifactOnRIViaExternalAPI", parallel=true) + public static Object[][] dataProviderUpdateArtifactOnRIViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", null}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", null}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VF} + + }; + } + + + + + + @Test(dataProvider="updateArtifactOnRIViaExternalAPI") + public void updateArtifactOnRIViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s", chosenLifeCycleState, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE_INSTANCE, LifeCycleStatesEnum.CHECKOUT, artifactType, resourceTypeEnum); + updateArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.RESOURCE_INSTANCE, chosenLifeCycleState, artifactType); + + // for certify version check that previous version exist, and that it artifact can be download + checksum + if(chosenLifeCycleState.equals(LifeCycleStatesEnum.CERTIFY)) { + // Download the uploaded artifact via external API + downloadResourceDeploymentArtifactExternalAPIAndComparePayLoadOfArtifactType(component, artifactType, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ComponentTypeEnum.RESOURCE_INSTANCE); + } + } + + + + + + + + @DataProvider(name="updateArtifactOnVfcVlCpRIViaExternalAPI", parallel=true) + public static Object[][] dataProviderUpdateArtifactOnVfcVlCpRIViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.CP}, + + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.CP}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.CP} + + }; + } + + + + + + @Test(dataProvider="updateArtifactOnVfcVlCpRIViaExternalAPI") + public void updateArtifactOnVfcVlCpRIViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s", chosenLifeCycleState, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE_INSTANCE, LifeCycleStatesEnum.CHECKOUT, artifactType, resourceTypeEnum); + updateArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.RESOURCE_INSTANCE, chosenLifeCycleState, artifactType); + + + // for certify version check that previous version exist, and that it artifact can be download + checksum + if(chosenLifeCycleState.equals(LifeCycleStatesEnum.CERTIFY)) { + // Download the uploaded artifact via external API + downloadResourceDeploymentArtifactExternalAPIAndComparePayLoadOfArtifactType(component, artifactType, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ComponentTypeEnum.RESOURCE_INSTANCE); + } + } + + + + + + + + + + + @DataProvider(name="updateArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset", parallel=true) + public static Object[][] dataProviderUpdateArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset() { + return new Object[][] { + {ComponentTypeEnum.RESOURCE, UserRoleEnum.DESIGNER2, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.DESIGNER2, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.DESIGNER2, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + }; + } + + + + // External API + // Update artifact by diffrent user then creator of asset - Fail + @Test(dataProvider="updateArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset") + public void updateArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset(ComponentTypeEnum componentTypeEnum, UserRoleEnum userRoleEnum, LifeCycleStatesEnum lifeCycleStatesEnum, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("componentTypeEnum: %s, userRoleEnum: %s, lifeCycleStatesEnum: %s, artifactType: %s", componentTypeEnum, userRoleEnum, lifeCycleStatesEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(componentTypeEnum, LifeCycleStatesEnum.CHECKIN, artifactType, null); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(); + updateArtifactOnAssetViaExternalAPI(component, componentTypeEnum, lifeCycleStatesEnum, artifactType, errorInfo, variables, userRoleEnum, 409); + } + + + @DataProvider(name="updateArtifactOnAssetWhichNotExist", parallel=true) + public static Object[][] dataProviderUpdateArtifactOnAssetWhichNotExist() { + return new Object[][] { + {ComponentTypeEnum.SERVICE, "OTHER", null}, + {ComponentTypeEnum.RESOURCE, "OTHER", null}, + {ComponentTypeEnum.RESOURCE_INSTANCE, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VF}, + }; + } + + + + // External API + // Upload artifact on VF via external API - happy flow + @Test(dataProvider="updateArtifactOnAssetWhichNotExist") + public void updateArtifactOnAssetWhichNotExist(ComponentTypeEnum componentTypeEnum, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("componentTypeEnum: %s, artifactType: %s", componentTypeEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(componentTypeEnum, LifeCycleStatesEnum.CHECKIN, artifactType, resourceTypeEnum); + + // get updated artifact data + Map deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + ArtifactReqDetails artifactReqDetails = getUpdatedArtifact(deploymentArtifacts, artifactType); + String artifactUUID = deploymentArtifacts.get(artifactReqDetails.getArtifactLabel()).getArtifactUUID(); + + // Invalid artifactUUID + String invalidArtifactUUID = "12341234-1234-1234-1234-123412341234"; + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_NOT_FOUND.name()); + List variables = asList(invalidArtifactUUID); + + if(componentTypeEnum.equals(ComponentTypeEnum.RESOURCE_INSTANCE)) { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 404, component.getComponentInstances().get(0), artifactReqDetails, invalidArtifactUUID, errorInfo, variables, null, true); + } else { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 404, null, artifactReqDetails, invalidArtifactUUID, errorInfo, variables, null, true); + + } + + // Invalid componentUUID +// errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESOURCE_NOT_FOUND.name()); +// variables = asList("null"); + + if(componentTypeEnum.equals(ComponentTypeEnum.RESOURCE_INSTANCE)) { + component.getComponentInstances().get(0).setNormalizedName("invalidNormalizedName"); + + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER.name()); + + variables = asList("invalidNormalizedName", ComponentTypeEnum.RESOURCE_INSTANCE.getValue().toLowerCase(), ComponentTypeEnum.SERVICE.getValue(), component.getName()); + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 404, component.getComponentInstances().get(0), artifactReqDetails, artifactUUID, errorInfo, variables, LifeCycleStatesEnum.CHECKIN, true); + } else { + component.setUUID("invalidComponentUUID"); + + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESOURCE_NOT_FOUND.name()); + variables = asList("null"); + + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 404, null, artifactReqDetails, artifactUUID, errorInfo, variables, LifeCycleStatesEnum.CHECKIN, false); + } + + performClean(); + } + + + @DataProvider(name="updateArtifactOnAssetWhichInInvalidStateForUploading", parallel=true) + public static Object[][] dataProviderUpdateProviderDeleteArtifactOnAssetWhichInInvalidStateForUploading() { + return new Object[][] { + {ComponentTypeEnum.SERVICE, "OTHER"}, + {ComponentTypeEnum.RESOURCE, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, "DCAE_INVENTORY_TOSCA"}, + }; + } + + + @Test(dataProvider="updateArtifactOnAssetWhichInInvalidStateForUploading") + public void updateArtifactOnAssetWhichInInvalidStateForUploading(ComponentTypeEnum componentTypeEnum, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("componentTypeEnum: %s, artifactType: %s", componentTypeEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(componentTypeEnum, LifeCycleStatesEnum.CHECKIN, artifactType, null); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE.name()); + List variables = asList(component.getName(), component.getComponentType().toString().toLowerCase(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER).getFirstName(), + ElementFactory.getDefaultUser(UserRoleEnum.TESTER).getLastName(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER).getUserId()); + updateArtifactOnAssetViaExternalAPI(component, componentTypeEnum, LifeCycleStatesEnum.STARTCERTIFICATION, artifactType, errorInfo, variables, UserRoleEnum.DESIGNER, 403); + + } + + + + + + @DataProvider(name="updateInvalidArtifactTypeExtensionLabelDescriptionCheckSumDuplicateLabelViaExternalAPI", parallel=true) + public static Object[][] dataProviderUpdateInvalidArtifactTypeExtensionLabelDescriptionCheckSumDuplicateLabelViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidCheckSum"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidCheckSum"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidNameToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidNameToLong"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidNameEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidNameEmpty"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidLabelToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidLabelToLong"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidLabelEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidLabelEmpty"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidDescriptionToLong"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidDescriptionToLong"}, + + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKOUT, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CHECKIN, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE, "updateArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.SERVICE, "updateArtifactWithInvalidDescriptionEmpty"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, ComponentTypeEnum.RESOURCE_INSTANCE, "updateArtifactWithInvalidDescriptionEmpty"}, + }; + } + + + + + // InvalidArtifact + check audit & response code function + @Test(dataProvider="updateInvalidArtifactTypeExtensionLabelDescriptionCheckSumDuplicateLabelViaExternalAPI") + public void updateInvalidArtifactTypeExtensionLabelDescriptionCheckSumDuplicateLabelViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, + ComponentTypeEnum componentTypeEnum, String uploadArtifactTestType) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, componentTypeEnum: %s, uploadArtifactTestType: %s", chosenLifeCycleState, componentTypeEnum, uploadArtifactTestType)); + Component component; + ComponentInstance componentInstance = null; + String artifactType; + + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + artifactType = ArtifactTypeEnum.DCAE_INVENTORY_DOC.toString(); + component = uploadArtifactOnAssetViaExternalAPI(componentTypeEnum, LifeCycleStatesEnum.CHECKIN, artifactType, null); + componentInstance = component.getComponentInstances().get(0); + } else { + artifactType = ArtifactTypeEnum.OTHER.toString(); + component = uploadArtifactOnAssetViaExternalAPI(componentTypeEnum, LifeCycleStatesEnum.CHECKIN, artifactType, null); + } + + component = AtomicOperationUtils.changeComponentState(component, UserRoleEnum.DESIGNER, chosenLifeCycleState, true).getLeft(); + + switch (uploadArtifactTestType) { + case "updateArtifactWithInvalidCheckSum": + updateArtifactWithInvalidCheckSum(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactType, componentInstance); + break; + case "updateArtifactWithInvalidNameToLong": + updateArtifactWithInvalidNameToLong(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactType, componentInstance); + break; + case "updateArtifactWithInvalidNameEmpty": + updateArtifactWithInvalidNameEmpty(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactType, componentInstance); + break; + case "updateArtifactWithInvalidLabelToLong": + updateArtifactWithInvalidLabelToLong(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactType, componentInstance); + break; + case "updateArtifactWithInvalidLabelEmpty": + updateArtifactWithInvalidLabelEmpty(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactType, componentInstance); + break; + case "updateArtifactWithInvalidDescriptionToLong": + updateArtifactWithInvalidDescriptionToLong(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactType, componentInstance); + break; + case "updateArtifactWithInvalidDescriptionEmpty": + default: + updateArtifactWithInvalidDescriptionEmpty(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactType, componentInstance); + break; + } + +/////////////////////////////////////////////////////////////////////////////// +// // TODO: there is defect when checking invalid type +//// // Upload artifact with invalid type via external API +//// // invalid type +//// String artifactType = artifactReqDetails.getArtifactType(); +//// artifactReqDetails.setArtifactType("invalidType"); +//// restResponse = uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, 400, componentResourceInstanceDetails); +//// // empty type +//// artifactReqDetails.setArtifactType(""); +//// restResponse = uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, 400, componentResourceInstanceDetails); +//// artifactReqDetails.setArtifactType(artifactType); +/////////////////////////////////////////////////////////////////////////////// + } + + // TODO + // Update artifact with invalid checksum via external API + protected void updateArtifactWithInvalidCheckSum(Component component, User sdncModifierDetails, String artifactType, + ComponentInstance componentInstance) throws Exception { + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_INVALID_MD5.name()); + List variables = asList(); +// uploadArtifactWithInvalidCheckSumOfAssetIncludingValiditionOfAuditAndResponseCode(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), +// artifactReqDetails, 400, componentResourceInstanceDetails, errorInfo, variables); + } + + + // Update artifact with valid type & invalid name via external API - name to long + protected void updateArtifactWithInvalidNameToLong(Component component, User sdncModifierDetails, String artifactType, + ComponentInstance componentInstance) throws Exception { + + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType, true, true); + String artifactUUID = null; + Map deploymentArtifacts; + if(componentInstance != null) { + deploymentArtifacts = component.getComponentInstances().get(0).getDeploymentArtifacts(); + } else { + deploymentArtifacts = component.getDeploymentArtifacts(); + } + + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.EXCEEDS_LIMIT.name()); + List variables = asList("artifact name", "255"); + artifactReqDetails.setArtifactName("invalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidType"); + + if(componentInstance != null) { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, component.getComponentInstances().get(0), artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + } else { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, null, artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + + } + } + + + // Update artifact with valid type & invalid name via external API - name is empty + protected void updateArtifactWithInvalidNameEmpty(Component component, User sdncModifierDetails, String artifactType, + ComponentInstance componentInstance) throws Exception { + + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType, true, true); + String artifactUUID = null; + Map deploymentArtifacts; + if(componentInstance != null) { + deploymentArtifacts = component.getComponentInstances().get(0).getDeploymentArtifacts(); + } else { + deploymentArtifacts = component.getDeploymentArtifacts(); + } + + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_ARTIFACT_NAME.name()); + List variables = asList(); + artifactReqDetails.setArtifactName(""); + + if(componentInstance != null) { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, component.getComponentInstances().get(0), artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + } else { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, null, artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + + } + } + + + // Update artifact with valid type & invalid label via external API - label to long + protected void updateArtifactWithInvalidLabelToLong(Component component, User sdncModifierDetails, String artifactType, + ComponentInstance componentInstance) throws Exception { + + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType, true, true); + String artifactUUID = null; + Map deploymentArtifacts; + if(componentInstance != null) { + deploymentArtifacts = component.getComponentInstances().get(0).getDeploymentArtifacts(); + } else { + deploymentArtifacts = component.getDeploymentArtifacts(); + } + + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED.name()); + List variables = asList(); + artifactReqDetails.setArtifactLabel("invalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidType"); + + if(componentInstance != null) { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, component.getComponentInstances().get(0), artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + } else { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, null, artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + + } + } + + + // Update artifact with valid type & invalid label via external API - label is empty + protected void updateArtifactWithInvalidLabelEmpty(Component component, User sdncModifierDetails, String artifactType, + ComponentInstance componentInstance) throws Exception { + + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType, true, true); + String artifactUUID = null; + Map deploymentArtifacts; + if(componentInstance != null) { + deploymentArtifacts = component.getComponentInstances().get(0).getDeploymentArtifacts(); + } else { + deploymentArtifacts = component.getDeploymentArtifacts(); + } + + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_DATA.name()); + List variables = asList("artifact label"); + artifactReqDetails.setArtifactLabel(""); + + if(componentInstance != null) { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, component.getComponentInstances().get(0), artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + } else { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, null, artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + + } + } + + + // Update artifact with invalid description via external API - to long description + protected void updateArtifactWithInvalidDescriptionToLong(Component component, User sdncModifierDetails, String artifactType, + ComponentInstance componentInstance) throws Exception { + + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType, true, true); + String artifactUUID = null; + Map deploymentArtifacts; + if(componentInstance != null) { + deploymentArtifacts = component.getComponentInstances().get(0).getDeploymentArtifacts(); + } else { + deploymentArtifacts = component.getDeploymentArtifacts(); + } + + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED.name()); + List variables = asList(); + artifactReqDetails.setDescription("invalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeinvalGGfdsiofhdsouhfoidshfoidshoifhsdoifhdsouihfdsofhiufdsghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidTypeghiufghodhfioudsgafodsgaiofudsghifudsiugfhiufawsouipfhgawseiupfsadiughdfsoiuhgfaighfpasdghfdsaqgfdsgdfgidType"); + + if(componentInstance != null) { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, component.getComponentInstances().get(0), artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + } else { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, null, artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + + } + } + + + // Update artifact with invalid description via external API - empty description + protected void updateArtifactWithInvalidDescriptionEmpty(Component component, User sdncModifierDetails, String artifactType, + ComponentInstance componentInstance) throws Exception { + + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType, true, true); + String artifactUUID = null; + Map deploymentArtifacts; + if(componentInstance != null) { + deploymentArtifacts = component.getComponentInstances().get(0).getDeploymentArtifacts(); + } else { + deploymentArtifacts = component.getDeploymentArtifacts(); + } + + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED.name()); + List variables = asList("artifact description"); + artifactReqDetails.setDescription(""); + + if(componentInstance != null) { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, component.getComponentInstances().get(0), artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + } else { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 400, null, artifactReqDetails, artifactUUID, errorInfo, variables, null, true); + + } + } + + + + + + + + + + // Unhappy flow - get chosen life cycle state, artifact type and asset type + // update artifact via external API + check audit & response code + // Download artifact via external API + check audit & response code + // Check artifact version, uuid & checksusm + protected Component updateArtifactOnAssetViaExternalAPI(Component component, ComponentTypeEnum componentTypeEnum, LifeCycleStatesEnum chosenLifeCycleState, String artifactType, ErrorInfo errorInfo, List variables, UserRoleEnum userRoleEnum, Integer expectedResponseCode) throws Exception { + String componentVersionBeforeUpdate = null; + + // get updated artifact data + component = AtomicOperationUtils.changeComponentState(component, UserRoleEnum.DESIGNER, chosenLifeCycleState, true).getLeft(); + componentVersionBeforeUpdate = component.getVersion(); + + Map deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + ArtifactReqDetails artifactReqDetails = getUpdatedArtifact(deploymentArtifacts, artifactType); + + String artifactName = artifactReqDetails.getArtifactLabel(); + String artifactUUID = deploymentArtifacts.get(artifactName).getArtifactUUID(); + String artifactVersionBeforeUpdate = deploymentArtifacts.get(artifactName).getArtifactVersion(); + int numberOfArtifact = deploymentArtifacts.size(); + + // create component/s & upload artifact via external api + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(userRoleEnum), + expectedResponseCode, component.getComponentInstances().get(0), artifactReqDetails, artifactUUID, errorInfo, variables, chosenLifeCycleState, true); + } else { + updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(userRoleEnum), + expectedResponseCode, null, artifactReqDetails, artifactUUID, errorInfo, variables, chosenLifeCycleState, true); + } + + if(component.getComponentType().equals(ComponentTypeEnum.SERVICE)) { + component = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, component.getName(), component.getVersion()); + } else { + component = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, component.getName(), component.getVersion()); + } + + // Get list of deployment artifact + download them via external API + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + deploymentArtifacts = component.getComponentInstances().get(0).getDeploymentArtifacts(); + } else { + deploymentArtifacts = component.getDeploymentArtifacts(); + } + Assert.assertEquals(numberOfArtifact, deploymentArtifacts.keySet().size(), "Expected that number of deployment artifact will be same as before."); + Assert.assertEquals(String.valueOf((Integer.parseInt(artifactVersionBeforeUpdate))), deploymentArtifacts.get(artifactName).getArtifactVersion(), "Expected that aftifact will not change."); + Assert.assertEquals(artifactUUID, deploymentArtifacts.get(artifactName).getArtifactUUID(), "Expected that aftifactUUID will not change."); + Assert.assertEquals(componentVersionBeforeUpdate, component.getVersion(), "Expected that check-out component will not change version number."); + + return component; + } + + protected RestResponse updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, User sdncModifierDetails, + Integer expectedResponseCode, ComponentInstance componentInstance, ArtifactReqDetails artifactReqDetails, String artifactUUID, ErrorInfo errorInfo, List variables, LifeCycleStatesEnum lifeCycleStatesEnum, Boolean resourceNameInAudit) throws Exception { + RestResponse restResponse; + + if(componentInstance != null) { + restResponse = ArtifactRestUtils.externalAPIUpdateArtifactOfComponentInstanceOnAsset(resourceDetails, sdncModifierDetails, artifactReqDetails, componentInstance, artifactUUID); + } else { + restResponse = ArtifactRestUtils.externalAPIUpdateArtifactOfTheAsset(resourceDetails, sdncModifierDetails, artifactReqDetails, artifactUUID); + + } + + // validate response code + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + //TODO + // Check auditing for upload operation + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_UPDATE_BY_API; + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); +// ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); + + responseArtifact.setUpdaterFullName(""); + responseArtifact.setUserIdLastUpdater(sdncModifierDetails.getUserId()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditFailure(assetTypeEnum, action, responseArtifact, resourceDetails.getUUID(), errorInfo, variables); + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getName()); + expectedExternalAudit.setRESOURCE_TYPE(resourceDetails.getComponentType().getValue()); + expectedExternalAudit.setARTIFACT_DATA(""); + expectedExternalAudit.setCURR_ARTIFACT_UUID(artifactUUID); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_STATUS, responseCode.toString()); + if(componentInstance != null) { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getComponentInstances().get(0).getNormalizedName()); + expectedExternalAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetTypeEnum.getValue() + "/" + resourceDetails.getUUID() + "/resourceInstances/" + resourceDetails.getComponentInstances().get(0).getNormalizedName() + "/artifacts/" + artifactUUID); + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getComponentInstances().get(0).getNormalizedName()); + } else { + expectedExternalAudit.setRESOURCE_URL(expectedExternalAudit.getRESOURCE_URL() + "/" + artifactUUID); + if((lifeCycleStatesEnum == LifeCycleStatesEnum.CHECKIN) || (lifeCycleStatesEnum == LifeCycleStatesEnum.STARTCERTIFICATION)) { + if(resourceNameInAudit) { + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + } else { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedExternalAudit.getRESOURCE_URL()); +// body.put(AuditingFieldsKeysEnum.AUDIT_CURR_ARTIFACT_UUID, artifactUUID); + expectedExternalAudit.setRESOURCE_NAME(""); + } + } else { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + } + } + + + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_UPDATE_BY_API.getName(), body); + return restResponse; + + } + + + // This function get component, user & if updatedPayload or not + // It will create default payload / updated payload of artifact + // And download artifact of component which starts with ci + protected RestResponse downloadResourceDeploymentArtifactExternalAPIAndComparePayLoadOfArtifactType(Component component, String artifactType, User sdncModifierDetails, ComponentTypeEnum componentTypeEnum) throws IOException, Exception { + // Download the uploaded artifact via external API + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("abcd", artifactType, true, false); + String artifactName = null; + for (String key : component.getDeploymentArtifacts().keySet()) { + if (key.startsWith("ci")) { + artifactName = key; + break; + } + } + return downloadResourceDeploymentArtifactExternalAPI(component, component.getDeploymentArtifacts().get(artifactName), sdncModifierDetails, artifactReqDetails, componentTypeEnum); + } + + // Get deployment artifact of asset + protected Map getDeploymentArtifactsOfAsset(Component component, ComponentTypeEnum componentTypeEnum) { + Map deploymentArtifacts = null; + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + for(ComponentInstance componentInstance: component.getComponentInstances()) { + if(componentInstance.getNormalizedName().startsWith("ci")) { + deploymentArtifacts = componentInstance.getDeploymentArtifacts(); + break; + } + } + } else { + deploymentArtifacts = component.getDeploymentArtifacts(); + } + return deploymentArtifacts; + } + + // get deploymentArtifact of asset and artifactType -> generate new artifact that can be updated on the asset + protected ArtifactReqDetails getUpdatedArtifact(Map deploymentArtifacts, String artifactType) throws IOException, Exception { + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType, true, true); + + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactReqDetails.setArtifactDisplayName(deploymentArtifacts.get(key).getArtifactDisplayName()); + artifactReqDetails.setArtifactName(deploymentArtifacts.get(key).getArtifactName()); + artifactReqDetails.setArtifactLabel(deploymentArtifacts.get(key).getArtifactLabel()); + break; + } + } + + return artifactReqDetails; + } + + // Happy flow - get chosen life cycle state, artifact type and asset type + // update artifact via external API + check audit & response code + // Download artifact via external API + check audit & response code + // Check artifact version, uuid & checksusm + protected Component updateArtifactOnAssetViaExternalAPI(Component component, ComponentTypeEnum componentTypeEnum, LifeCycleStatesEnum chosenLifeCycleState, String artifactType) throws Exception { + RestResponse restResponse = null; + int numberOfArtifact = 0; + String artifactVersionBeforeUpdate = null; + String artifactName = null; + String componentVersionBeforeUpdate = null; + + // get updated artifact data + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType, true, true); + String artifactUUID = null; + Map deploymentArtifacts; + deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactName = key; + artifactVersionBeforeUpdate = deploymentArtifacts.get(key).getArtifactVersion(); + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + artifactReqDetails.setArtifactDisplayName(deploymentArtifacts.get(key).getArtifactDisplayName()); + artifactReqDetails.setArtifactName(deploymentArtifacts.get(key).getArtifactName()); + artifactReqDetails.setArtifactLabel(deploymentArtifacts.get(key).getArtifactLabel()); + break; + } + } + + component = AtomicOperationUtils.changeComponentState(component, UserRoleEnum.DESIGNER, chosenLifeCycleState, true).getLeft(); + componentVersionBeforeUpdate = component.getVersion(); + deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + numberOfArtifact = deploymentArtifacts.size(); + + + // create component/s & upload artifact via external api + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + if((chosenLifeCycleState == LifeCycleStatesEnum.CERTIFICATIONREQUEST) && (!component.getComponentType().toString().equals(ComponentTypeEnum.RESOURCE.toString()))) { + numberOfArtifact = numberOfArtifact - 1; + } + restResponse = updateArtifactOfRIIncludingValiditionOfAuditAndResponseCode(component, component.getComponentInstances().get(0), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, artifactUUID, 200); + } else { + + restResponse = updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, artifactUUID, 200); + } + + + + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + component = getNewerVersionOfComponent(component, chosenLifeCycleState); + + // Get list of deployment artifact + download them via external API + deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + Assert.assertEquals(numberOfArtifact, deploymentArtifacts.keySet().size(), "Expected that number of deployment artifact will be same as before."); + Assert.assertEquals(String.valueOf((Integer.parseInt(artifactVersionBeforeUpdate) + 1)), deploymentArtifacts.get(artifactName).getArtifactVersion(), "Expected that aftifact version will increase by one."); + + if(chosenLifeCycleState == LifeCycleStatesEnum.CHECKOUT) { + Assert.assertEquals(componentVersionBeforeUpdate, component.getVersion(), "Expected that check-out component will not change version number."); + } else { + Assert.assertEquals(String.format("%.1f", (Double.parseDouble(componentVersionBeforeUpdate) + 0.1)), component.getVersion(), "Expected that non check-out component version will increase by 0.1."); + } + + // Download the uploaded artifact via external API + downloadResourceDeploymentArtifactExternalAPI(component, deploymentArtifacts.get(responseArtifact.getArtifactLabel()), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, componentTypeEnum); + + return component; + } + + + // Update artifact via external API + Check auditing for upload operation + Check response of external API + protected RestResponse updateArtifactOfRIIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, ComponentInstance componentInstance, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, String artifactUUID, Integer expectedResponseCode) throws Exception { + RestResponse restResponse = ArtifactRestUtils.externalAPIUpdateArtifactOfComponentInstanceOnAsset(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, resourceDetails.getComponentInstances().get(0), artifactUUID); + + // Check response of external API + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + + // Check auditing for upload operation + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_UPDATE_BY_API; + + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, componentInstance.getNormalizedName()); + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); +// expectedExternalAudit.setRESOURCE_URL(expectedExternalAudit.getRESOURCE_URL()+ "/" + artifactUUID); + expectedExternalAudit.setRESOURCE_NAME(componentInstance.getNormalizedName()); + expectedExternalAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetTypeEnum.getValue() + "/" + resourceDetails.getUUID() + "/resourceInstances/" + componentInstance.getNormalizedName() + "/artifacts/" + artifactUUID); + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_UPDATE_BY_API.getName(), body); + + return restResponse; + } + + + // Update artifact via external API + Check auditing for upload operation + Check response of external API + protected RestResponse updateArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, User sdncModifierDetails, ArtifactReqDetails artifactReqDetails, String artifactUUID, Integer expectedResponseCode) throws Exception { + RestResponse restResponse = ArtifactRestUtils.externalAPIUpdateArtifactOfTheAsset(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, artifactUUID); + + // Check response of external API + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + + // Check auditing for upload operation + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_UPDATE_BY_API; + + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); + expectedExternalAudit.setRESOURCE_URL(expectedExternalAudit.getRESOURCE_URL()+ "/" + artifactUUID); + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_UPDATE_BY_API.getName(), body); + + return restResponse; + } + + + + + //////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////// + // Delete External API // + //////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////// + @DataProvider(name="deleteArtifactForServiceViaExternalAPI", parallel=true) + public static Object[][] dataProviderDeleteArtifactForServiceViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {LifeCycleStatesEnum.CHECKIN, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER"}, + {LifeCycleStatesEnum.CERTIFY, "YANG_XML"}, + {LifeCycleStatesEnum.CERTIFY, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CERTIFY, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CERTIFY, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CERTIFY, "OTHER"} + }; + } + + + + + // Delete artifact for Service - Success + @Test(dataProvider="deleteArtifactForServiceViaExternalAPI") + public void deleteArtifactForServiceViaExternalAPI(LifeCycleStatesEnum lifeCycleStatesEnum, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("lifeCycleStatesEnum: %s, artifactType: %s", lifeCycleStatesEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.SERVICE, LifeCycleStatesEnum.CHECKOUT, artifactType, null); + deleteArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.SERVICE, lifeCycleStatesEnum); + } + + @DataProvider(name="deleteArtifactForVFViaExternalAPI", parallel=true) + public static Object[][] dataProviderDeleteArtifactForVFViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "DCAE_JSON"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_POLICY"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_EVENT"}, + {LifeCycleStatesEnum.CHECKOUT, "APPC_CONFIG"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_DOC"}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_TOSCA"}, + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE"}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_JSON"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_POLICY"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_EVENT"}, + {LifeCycleStatesEnum.CHECKIN, "APPC_CONFIG"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_DOC"}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_TOSCA"}, + {LifeCycleStatesEnum.CHECKIN, "YANG_XML"}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE"}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CHECKIN, "OTHER"}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_JSON"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_POLICY"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_EVENT"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "APPC_CONFIG"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_DOC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_TOSCA"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC"}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER"}, + }; + } + + + // Delete artifact for VF - Success + @Test(dataProvider="deleteArtifactForVFViaExternalAPI") + public void deleteArtifactForVFViaExternalAPI(LifeCycleStatesEnum lifeCycleStatesEnum, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("lifeCycleStatesEnum: %s, artifactType: %s", lifeCycleStatesEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE, LifeCycleStatesEnum.CHECKOUT, artifactType, null); + deleteArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.RESOURCE, lifeCycleStatesEnum); + } + + @DataProvider(name="deleteArtifactForVfcVlCpViaExternalAPI", parallel=true) + public static Object[][] dataProviderDeleteArtifactForVfcVlCpViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKOUT, "YANG_XML", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "VNF_CATALOG", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "VF_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "VENDOR_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "MODEL_QUERY_SPEC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "OTHER", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.CP}, + + {LifeCycleStatesEnum.CHECKIN, "YANG_XML", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "OTHER", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CHECKIN, "YANG_XML", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "OTHER", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKIN, "YANG_XML", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "VNF_CATALOG", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "VF_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "VENDOR_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "MODEL_QUERY_SPEC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "OTHER", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.CP}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "YANG_XML", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VNF_CATALOG", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VF_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "VENDOR_LICENSE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_INVENTORY_PROFILE", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "MODEL_QUERY_SPEC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "OTHER", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.CP} + }; + } + + + // Delete artifact for VFC, VL, CP - Success + @Test(dataProvider="deleteArtifactForVfcVlCpViaExternalAPI") + public void deleteArtifactForVfcVlCpViaExternalAPI(LifeCycleStatesEnum lifeCycleStatesEnum, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("lifeCycleStatesEnum: %s, artifactType: %s, resourceTypeEnum: %s", lifeCycleStatesEnum, artifactType, resourceTypeEnum)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE, LifeCycleStatesEnum.CHECKOUT, artifactType, resourceTypeEnum); + deleteArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.RESOURCE, lifeCycleStatesEnum); + } + + @DataProvider(name="deleteArtifactOnRIViaExternalAPI", parallel=true) + public static Object[][] dataProviderDeleteArtifactOnRIViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", null}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", null}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", null}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", null}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VF}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VF} + + }; + } + + + + + + @Test(dataProvider="deleteArtifactOnRIViaExternalAPI") + public void deleteArtifactOnRIViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s", chosenLifeCycleState, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE_INSTANCE, LifeCycleStatesEnum.CHECKOUT, artifactType, resourceTypeEnum); + deleteArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.RESOURCE_INSTANCE, chosenLifeCycleState); + } + + + @DataProvider(name="deleteArtifactOnVfcVlCpRIViaExternalAPI", parallel=true) + public static Object[][] dataProviderDeleteArtifactOnVfcVlCpRIViaExternalAPI() { + return new Object[][] { + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_JSON", ResourceTypeEnum.CP,}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_DOC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKOUT, "SNMP_TRAP", ResourceTypeEnum.CP}, + + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_JSON", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_DOC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CHECKIN, "SNMP_TRAP", ResourceTypeEnum.CP}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VFC}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VFC}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.VL}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.VL}, + + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_JSON", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_POLICY", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_DOC", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_BLUEPRINT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "DCAE_INVENTORY_EVENT", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_POLL", ResourceTypeEnum.CP}, + {LifeCycleStatesEnum.CERTIFICATIONREQUEST, "SNMP_TRAP", ResourceTypeEnum.CP} + + }; + } + + + + + + @Test(dataProvider="deleteArtifactOnVfcVlCpRIViaExternalAPI") + public void deleteArtifactOnVfcVlCpRIViaExternalAPI(LifeCycleStatesEnum chosenLifeCycleState, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("chosenLifeCycleState: %s, artifactType: %s", chosenLifeCycleState, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(ComponentTypeEnum.RESOURCE_INSTANCE, LifeCycleStatesEnum.CHECKOUT, artifactType, resourceTypeEnum); + deleteArtifactOnAssetViaExternalAPI(component, ComponentTypeEnum.RESOURCE_INSTANCE, chosenLifeCycleState); + } + + + @DataProvider(name="deleteArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset", parallel=true) + public static Object[][] dataProviderDeleteArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset() { + return new Object[][] { + {ComponentTypeEnum.RESOURCE, UserRoleEnum.DESIGNER2, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.DESIGNER2, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.DESIGNER2, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.TESTER, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.ADMIN, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.OPS, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, +// + {ComponentTypeEnum.RESOURCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.GOVERNOR, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_STRATEGIST1, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKIN, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKIN, "DCAE_INVENTORY_TOSCA"}, + {ComponentTypeEnum.RESOURCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.SERVICE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKOUT, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, UserRoleEnum.PRODUCT_MANAGER1, LifeCycleStatesEnum.CHECKOUT, "DCAE_INVENTORY_TOSCA"}, + }; + } + + + // External API + // Delete artifact by diffrent user then creator of asset - Fail + @Test(dataProvider="deleteArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset") + public void deleteArtifactOnVFViaExternalAPIByDiffrentUserThenCreatorOfAsset(ComponentTypeEnum componentTypeEnum, UserRoleEnum userRoleEnum, LifeCycleStatesEnum lifeCycleStatesEnum, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("componentTypeEnum: %s, userRoleEnum %s, lifeCycleStatesEnum %s, artifactType: %s", componentTypeEnum, userRoleEnum, lifeCycleStatesEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(componentTypeEnum, lifeCycleStatesEnum, artifactType, null); + Map deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + + String artifactUUID = null; + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESTRICTED_OPERATION.name()); + List variables = asList(); + + if(componentTypeEnum.equals(ComponentTypeEnum.RESOURCE_INSTANCE)) { + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(userRoleEnum), + 409, component.getComponentInstances().get(0), artifactUUID, errorInfo, variables, lifeCycleStatesEnum, true); + } else { + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(userRoleEnum), + 409, null, artifactUUID, errorInfo, variables, lifeCycleStatesEnum, true); + } + + //TODO +// downloadResourceDeploymentArtifactExternalAPI(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactUUID, componentTypeEnum); + } + + + @DataProvider(name="deleteArtifactOnAssetWhichNotExist", parallel=true) + public static Object[][] dataProviderDeleteArtifactOnAssetWhichNotExist() { + return new Object[][] { + {ComponentTypeEnum.SERVICE, "OTHER", null}, + {ComponentTypeEnum.RESOURCE, "OTHER", null}, + {ComponentTypeEnum.RESOURCE_INSTANCE, "DCAE_INVENTORY_TOSCA", ResourceTypeEnum.VF}, + }; + } + + + // External API + // Upload artifact on VF via external API - happy flow + @Test(dataProvider="deleteArtifactOnAssetWhichNotExist") + public void deleteArtifactOnAssetWhichNotExist(ComponentTypeEnum componentTypeEnum, String artifactType, ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("componentTypeEnum: %s, artifactType: %s", componentTypeEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(componentTypeEnum, LifeCycleStatesEnum.CHECKIN, artifactType, resourceTypeEnum); + + Map deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + + String artifactUUID = null; + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + + // Invalid artifactUUID + String invalidArtifactUUID = "12341234-1234-1234-1234-123412341234"; + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_NOT_FOUND.name()); + List variables = asList(invalidArtifactUUID); + + if(componentTypeEnum.equals(ComponentTypeEnum.RESOURCE_INSTANCE)) { + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 404, component.getComponentInstances().get(0), invalidArtifactUUID, errorInfo, variables, null, true); + } else { + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 404, null, invalidArtifactUUID, errorInfo, variables, null, true); + + } + + + // Invalid componentUUID + if(componentTypeEnum.equals(ComponentTypeEnum.RESOURCE_INSTANCE)) { + component.getComponentInstances().get(0).setNormalizedName("invalidNormalizedName"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER.name()); + variables = asList("invalidNormalizedName", ComponentTypeEnum.RESOURCE_INSTANCE.getValue().toLowerCase(), ComponentTypeEnum.SERVICE.getValue(), component.getName()); + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 404, component.getComponentInstances().get(0), artifactUUID, errorInfo, variables, LifeCycleStatesEnum.CHECKIN, true); + } else { + component.setUUID("invalidComponentUUID"); + if(componentTypeEnum.equals(ComponentTypeEnum.RESOURCE)) { + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESOURCE_NOT_FOUND.name()); + } else { + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.SERVICE_NOT_FOUND.name()); + } + variables = asList("invalidComponentUUID"); + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 404, null, artifactUUID, errorInfo, variables, LifeCycleStatesEnum.CHECKIN, false); + } + + +// performeClean(); + + } + + @DataProvider(name="deleteArtifactOnAssetWhichInInvalidStateForUploading", parallel=true) + public static Object[][] dataProviderDeleteArtifactOnAssetWhichInInvalidStateForUploading() { + return new Object[][] { + {ComponentTypeEnum.SERVICE, "OTHER"}, + {ComponentTypeEnum.RESOURCE, "OTHER"}, + {ComponentTypeEnum.RESOURCE_INSTANCE, "DCAE_INVENTORY_TOSCA"}, + }; + } + + + @Test(dataProvider="deleteArtifactOnAssetWhichInInvalidStateForUploading") + public void deleteArtifactOnAssetWhichInInvalidStateForUploading(ComponentTypeEnum componentTypeEnum, String artifactType) throws Exception { + getExtendTest().log(Status.INFO, String.format("componentTypeEnum: %s, artifactType: %s", componentTypeEnum, artifactType)); + Component component = uploadArtifactOnAssetViaExternalAPI(componentTypeEnum, LifeCycleStatesEnum.CHECKOUT, artifactType, null); + component = AtomicOperationUtils.changeComponentState(component, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.STARTCERTIFICATION, true).getLeft(); + + Map deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + String artifactUUID = null; + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + + + // Invalid artifactUUID + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE.name()); + List variables = asList(component.getName(), component.getComponentType().toString().toLowerCase(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER).getFirstName(), + ElementFactory.getDefaultUser(UserRoleEnum.TESTER).getLastName(), ElementFactory.getDefaultUser(UserRoleEnum.TESTER).getUserId()); + + if(componentTypeEnum.equals(ComponentTypeEnum.RESOURCE_INSTANCE)) { + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 403, component.getComponentInstances().get(0), artifactUUID, errorInfo, variables, null, true); + } else { + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 403, null, artifactUUID, errorInfo, variables, null, true); + + } + + } + + + @DataProvider(name="deleteArtifactOfVfcVlCpForVfciVliCpiViaExternalAPI", parallel=true) + public static Object[][] dataProviderDeleteArtifactOfVfcVlCpForVfciVliCpiViaExternalAPI() { + return new Object[][] { + {ResourceTypeEnum.VFC}, + {ResourceTypeEnum.VL}, + {ResourceTypeEnum.CP} + }; + } + + + // Verify that it cannot delete VFC/VL/CP artifact on VFCi/VLi/CPi - Failure flow + @Test(dataProvider="deleteArtifactOfVfcVlCpForVfciVliCpiViaExternalAPI") + public void deleteArtifactOfVfcVlCpForVfciVliCpiViaExternalAPI(ResourceTypeEnum resourceTypeEnum) throws Exception { + getExtendTest().log(Status.INFO, String.format("resourceTypeEnum: %s", resourceTypeEnum)); + + Component resourceInstanceDetails = getComponentInTargetLifeCycleState(ComponentTypeEnum.RESOURCE.getValue(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, resourceTypeEnum); + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", "SNMP_TRAP", true, false); + uploadArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(resourceInstanceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactReqDetails, 200); + resourceInstanceDetails = AtomicOperationUtils.changeComponentState(resourceInstanceDetails, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + Component component = getComponentInTargetLifeCycleState(ComponentTypeEnum.RESOURCE.toString(), UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, null); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceInstanceDetails, component, UserRoleEnum.DESIGNER, true).left().value(); + component = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, component.getName(), component.getVersion()); + + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.ARTIFACT_NOT_FOUND.name()); + Map deploymentArtifacts; + deploymentArtifacts = getDeploymentArtifactsOfAsset(component, ComponentTypeEnum.RESOURCE_INSTANCE); + String artifactUUID = null; + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci")) { + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + break; + } + } + List variables = asList(artifactUUID); + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), + 404, component.getComponentInstances().get(0), artifactUUID, errorInfo, variables, null, true); + } + + protected RestResponse deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, User sdncModifierDetails, + Integer expectedResponseCode, ComponentInstance componentInstance, String artifactUUID, ErrorInfo errorInfo, List variables, LifeCycleStatesEnum lifeCycleStatesEnum, Boolean resourceNameInAudit) throws Exception { + RestResponse restResponse; + + if(componentInstance != null) { + restResponse = ArtifactRestUtils.externalAPIDeleteArtifactOfComponentInstanceOnAsset(resourceDetails, sdncModifierDetails, componentInstance, artifactUUID); + } else { + restResponse = ArtifactRestUtils.externalAPIDeleteArtifactOfTheAsset(resourceDetails, sdncModifierDetails, artifactUUID); + + } + + // validate response code + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + // Check auditing for upload operation + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_DELETE_BY_API; + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); +// ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); + + responseArtifact.setUpdaterFullName(""); + responseArtifact.setUserIdLastUpdater(sdncModifierDetails.getUserId()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditFailure(assetTypeEnum, action, responseArtifact, resourceDetails.getUUID(), errorInfo, variables); + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getName()); + expectedExternalAudit.setRESOURCE_TYPE(resourceDetails.getComponentType().getValue()); + expectedExternalAudit.setARTIFACT_DATA(null); + expectedExternalAudit.setCURR_ARTIFACT_UUID(artifactUUID); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_STATUS, responseCode.toString()); + if(componentInstance != null) { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getComponentInstances().get(0).getNormalizedName()); + expectedExternalAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetTypeEnum.getValue() + "/" + resourceDetails.getUUID() + "/resourceInstances/" + resourceDetails.getComponentInstances().get(0).getNormalizedName() + "/artifacts/" + artifactUUID); + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getComponentInstances().get(0).getNormalizedName()); + } else { + expectedExternalAudit.setRESOURCE_URL(expectedExternalAudit.getRESOURCE_URL() + "/" + artifactUUID); + if((errorInfo.getMessageId().equals(ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.RESOURCE_NOT_FOUND.name()).getMessageId())) || + errorInfo.getMessageId().equals(ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE.name()).getMessageId()) || + (lifeCycleStatesEnum == LifeCycleStatesEnum.STARTCERTIFICATION)) { + if(resourceNameInAudit) { + expectedExternalAudit.setRESOURCE_NAME(resourceDetails.getName()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + } else { + expectedExternalAudit.setRESOURCE_NAME(""); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedExternalAudit.getRESOURCE_URL()); + } + } else { + if(resourceNameInAudit) { + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + } else { + expectedExternalAudit.setRESOURCE_NAME(""); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedExternalAudit.getRESOURCE_URL()); + } + } + } + +// getExtendTest().log(LogStatus.INFO, "Audit Action: " + AuditingActionEnum.ARTIFACT_DELETE_BY_API.getName()); +// body.forEach((k,v)->getExtendTest().log(LogStatus.INFO,"key : " + k + " value : " + v)); + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_DELETE_BY_API.getName(), body); + + return restResponse; + + } + + + // Happy flow - get chosen life cycle state, artifact type and asset type + // delete artifact via external API + check audit & response code + protected Component deleteArtifactOnAssetViaExternalAPI(Component component, ComponentTypeEnum componentTypeEnum, LifeCycleStatesEnum chosenLifeCycleState) throws Exception { + String artifactName = null; + component = AtomicOperationUtils.changeComponentState(component, UserRoleEnum.DESIGNER, chosenLifeCycleState, true).getLeft(); + + // get updated artifact data + String artifactUUID = null; + int moduleTypeArtifact = 0; + Map deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + + for (String key : deploymentArtifacts.keySet()) { + if (key.startsWith("ci") && StringUtils.isNotEmpty(deploymentArtifacts.get(key).getArtifactUUID())) { + artifactName = key; + artifactUUID = deploymentArtifacts.get(key).getArtifactUUID(); + + if (deploymentArtifacts.get(key).getArtifactType().equals(ArtifactTypeEnum.VF_MODULES_METADATA)){ + moduleTypeArtifact = 1; + } + break; + } + } + + + String componentVersionBeforeDelete = component.getVersion(); + int numberOfArtifact = deploymentArtifacts.size(); + + + + // create component/s & upload artifact via external api + if(ComponentTypeEnum.RESOURCE_INSTANCE == componentTypeEnum) { + deleteArtifactOfRIIncludingValiditionOfAuditAndResponseCode(component, component.getComponentInstances().get(0), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactUUID, 200); + } else { + deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactUUID, 200); + } + + component = getNewerVersionOfComponent(component, chosenLifeCycleState); + + // Get list of deployment artifact + download them via external API + deploymentArtifacts = getDeploymentArtifactsOfAsset(component, componentTypeEnum); + if(deploymentArtifacts.get(artifactName) != null) { + Assert.assertTrue(false, "Expected that deleted artifact will not appear in deployment artifact list."); + } + if((LifeCycleStatesEnum.CERTIFICATIONREQUEST.equals(chosenLifeCycleState)) && (ComponentTypeEnum.RESOURCE_INSTANCE.equals(componentTypeEnum)) && (!component.getComponentType().toString().equals(ComponentTypeEnum.RESOURCE.toString()))) { + Assert.assertEquals(numberOfArtifact - 1 - moduleTypeArtifact, deploymentArtifacts.keySet().size(), "Expected that number of deployment artifact (one deleted and one vfmodule) will decrease by two."); + } else { + Assert.assertEquals(numberOfArtifact - 1, deploymentArtifacts.keySet().size(), "Expected that number of deployment artifact will decrease by one."); + } + + + if(chosenLifeCycleState == LifeCycleStatesEnum.CHECKOUT) { + Assert.assertEquals(componentVersionBeforeDelete, component.getVersion(), "Expected that check-out component will not change version number."); + } else { + Assert.assertEquals(String.format("%.1f", (Double.parseDouble(componentVersionBeforeDelete) + 0.1)), component.getVersion(), "Expected that non check-out component version will increase by 0.1."); + } + + downloadResourceDeploymentArtifactExternalAPI(component, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactUUID, componentTypeEnum); + + return component; + } + + // Delete artifact via external API + Check auditing for upload operation + Check response of external API + protected RestResponse deleteArtifactOfRIIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, ComponentInstance componentInstance, User sdncModifierDetails, String artifactUUID, Integer expectedResponseCode) throws Exception { + RestResponse restResponse = ArtifactRestUtils.externalAPIDeleteArtifactOfComponentInstanceOnAsset(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), resourceDetails.getComponentInstances().get(0), artifactUUID); + + // Check response of external API + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + + // Check auditing for upload operation + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_DELETE_BY_API; + + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, componentInstance.getNormalizedName()); + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); +// expectedExternalAudit.setRESOURCE_URL(expectedExternalAudit.getRESOURCE_URL()+ "/" + artifactUUID); + expectedExternalAudit.setRESOURCE_NAME(componentInstance.getNormalizedName()); + expectedExternalAudit.setRESOURCE_URL("/sdc/v1/catalog/" + assetTypeEnum.getValue() + "/" + resourceDetails.getUUID() + "/resourceInstances/" + componentInstance.getNormalizedName() + "/artifacts/" + artifactUUID); + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_DELETE_BY_API.getName(), body); + + return restResponse; + } + + + // Delete artifact via external API + Check auditing for upload operation + Check response of external API + protected RestResponse deleteArtifactOfAssetIncludingValiditionOfAuditAndResponseCode(Component resourceDetails, User sdncModifierDetails, String artifactUUID, Integer expectedResponseCode) throws Exception { + RestResponse restResponse = ArtifactRestUtils.externalAPIDeleteArtifactOfTheAsset(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), artifactUUID); + + // Check response of external API + Integer responseCode = restResponse.getErrorCode(); + Assert.assertEquals(responseCode, expectedResponseCode, "Response code is not correct."); + + + // Check auditing for upload operation + ArtifactDefinition responseArtifact = getArtifactDataFromJson(restResponse.getResponse()); + + AuditingActionEnum action = AuditingActionEnum.ARTIFACT_DELETE_BY_API; + + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); + + AssetTypeEnum assetTypeEnum = AssetTypeEnum.valueOf((resourceDetails.getComponentType().getValue() + "s").toUpperCase()); + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalArtifactAuditSuccess(assetTypeEnum, action, responseArtifact, resourceDetails); + expectedExternalAudit.setRESOURCE_URL(expectedExternalAudit.getRESOURCE_URL()+ "/" + artifactUUID); + AuditValidationUtils.validateExternalAudit(expectedExternalAudit, AuditingActionEnum.ARTIFACT_DELETE_BY_API.getName(), body); + + return restResponse; + } + + + + // download deployment via external api + check response code for success (200) + get artifactReqDetails and verify payload + verify audit + protected RestResponse downloadResourceDeploymentArtifactExternalAPI(Component resourceDetails, User sdncModifierDetails, String artifactUUID, ComponentTypeEnum componentTypeEnum) throws Exception { + RestResponse restResponse; + + if(componentTypeEnum == ComponentTypeEnum.RESOURCE_INSTANCE) { + restResponse = ArtifactRestUtils.getComponentInstanceDeploymentArtifactExternalAPI(resourceDetails.getUUID(), resourceDetails.getComponentInstances().get(0).getNormalizedName(), artifactUUID, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), resourceDetails.getComponentType().toString()); + } else { + restResponse = ArtifactRestUtils.getResourceDeploymentArtifactExternalAPI(resourceDetails.getUUID(), artifactUUID, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), resourceDetails.getComponentType().toString()); + } + + Integer responseCode = restResponse.getErrorCode(); + Integer expectedCode = 404; + Assert.assertEquals(responseCode,expectedCode, "Response code is not correct."); + + + //TODO - including body - resourceDetails.getName() +// // Verify audit +// String auditAction = "DownloadArtifact"; +// +// Map body = new HashMap<>(); +// body.put(AuditingFieldsKeysEnum.AUDIT_STATUS, responseCode.toString()); +// body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, resourceDetails.getName()); +// +// ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = new ExpectedResourceAuditJavaObject(); +// expectedResourceAuditJavaObject.setAction(auditAction); +// expectedResourceAuditJavaObject.setResourceType(resourceDetails.getComponentType().getValue()); +// expectedResourceAuditJavaObject.setStatus("200"); +// expectedResourceAuditJavaObject.setDesc("OK"); +// expectedResourceAuditJavaObject.setCONSUMER_ID("ci"); +// +// if(componentTypeEnum == ComponentTypeEnum.RESOURCE_INSTANCE) { +// expectedResourceAuditJavaObject.setResourceName(resourceDetails.getComponentInstances().get(0).getName()); +// String resource_url = String.format("/sdc/v1/catalog/services/%s/resourceInstances/%s/artifacts/%s", resourceDetails.getUUID(), resourceDetails.getComponentInstances().get(0).getNormalizedName(), artifactDefinition.getArtifactUUID()); +// expectedResourceAuditJavaObject.setRESOURCE_URL(resource_url); +// +// AuditValidationUtils.validateAuditDownloadExternalAPI(expectedResourceAuditJavaObject, auditAction, null, false); +// } else { +// expectedResourceAuditJavaObject.setResourceName(resourceDetails.getName()); +// String resource_url = String.format("/sdc/v1/catalog/services/%s/artifacts/%s", resourceDetails.getUUID(), artifactDefinition.getArtifactUUID()); +// expectedResourceAuditJavaObject.setRESOURCE_URL(resource_url); +// } +// +// AuditValidationUtils.validateAuditDownloadExternalAPI(expectedResourceAuditJavaObject, auditAction, null, false); + + return restResponse; + + } + + + + + public Component getComponentInTargetLifeCycleState(String componentType, UserRoleEnum creatorUser, LifeCycleStatesEnum targetLifeCycleState, ResourceTypeEnum resourceTypeEnum) throws Exception { + Component resourceDetails = null; + + if((componentType.toLowerCase().equals("vf")) || (componentType.toLowerCase().equals("resource"))){ + if(resourceTypeEnum==null) { + resourceTypeEnum = ResourceTypeEnum.VF; + } + Either createdResource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(resourceTypeEnum, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_INFRASTRUCTURE, creatorUser, true); + resourceDetails = createdResource.left().value(); + resourceDetails = AtomicOperationUtils.changeComponentState(resourceDetails, creatorUser, targetLifeCycleState, true).getLeft(); + } else { + Either createdResource = AtomicOperationUtils.createDefaultService(creatorUser, true); + resourceDetails = createdResource.left().value(); + // Add artifact to service if asked for certifcationrequest - must be at least one artifact for the flow + if((LifeCycleStatesEnum.CERTIFICATIONREQUEST == targetLifeCycleState) || (LifeCycleStatesEnum.STARTCERTIFICATION == targetLifeCycleState)) { + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, resourceDetails, UserRoleEnum.DESIGNER, true, true).left().value(); + } + resourceDetails = AtomicOperationUtils.changeComponentState(resourceDetails, creatorUser, targetLifeCycleState, true).getLeft(); + } + + return resourceDetails; + } + + + + + + protected String createUploadArtifactBodyJson() { + Map jsonBody = new HashMap(); + jsonBody.put("artifactName", UPLOAD_ARTIFACT_NAME); + jsonBody.put("artifactDisplayName", "configure"); + jsonBody.put("artifactType", "SHELL"); + jsonBody.put("mandatory", "false"); + jsonBody.put("description", "ff"); + jsonBody.put("payloadData", UPLOAD_ARTIFACT_PAYLOAD); + jsonBody.put("artifactLabel", "configure"); + return gson.toJson(jsonBody); + } + + protected ArtifactDefinition getArtifactDataFromJson(String content) { + JsonObject jsonElement = new JsonObject(); + ArtifactDefinition resourceInfo = null; + + try { + Gson gson = new Gson(); + jsonElement = gson.fromJson(content, jsonElement.getClass()); + JsonElement artifactGroupValue = jsonElement.get(Constants.ARTIFACT_GROUP_TYPE_FIELD); + if (artifactGroupValue != null && !artifactGroupValue.isJsonNull()) { + String groupValueUpper = artifactGroupValue.getAsString().toUpperCase(); + if (!ArtifactGroupTypeEnum.getAllTypes().contains(groupValueUpper)) { + StringBuilder sb = new StringBuilder(); + for (String value : ArtifactGroupTypeEnum.getAllTypes()) { + sb.append(value).append(", "); + } + log.debug("artifactGroupType is {}. valid values are: {}", groupValueUpper, sb.toString()); + return null; + } else { + jsonElement.remove(Constants.ARTIFACT_GROUP_TYPE_FIELD); + jsonElement.addProperty(Constants.ARTIFACT_GROUP_TYPE_FIELD, groupValueUpper); + } + } + String payload = null; + JsonElement artifactPayload = jsonElement.get(Constants.ARTIFACT_PAYLOAD_DATA); + if (artifactPayload != null && !artifactPayload.isJsonNull()) { + payload = artifactPayload.getAsString(); + } + jsonElement.remove(Constants.ARTIFACT_PAYLOAD_DATA); + String json = gson.toJson(jsonElement); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(Feature.FAIL_ON_EMPTY_BEANS, false); + mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); + + resourceInfo = mapper.readValue(json, ArtifactDefinition.class); + resourceInfo.setPayloadData(payload); + + } catch (Exception e) { + BeEcompErrorManager.getInstance().processEcompError(EcompErrorName.BeArtifactInformationInvalidError, "Artifact Upload / Update"); + BeEcompErrorManager.getInstance().logBeArtifactInformationInvalidError("Artifact Upload / Update"); + log.debug("Failed to convert the content {} to object.", content.substring(0, Math.min(50, content.length())), e); + } + + return resourceInfo; + } + + protected HttpGet createGetRequest(String url) { + HttpGet httpGet = new HttpGet(url); + httpGet.addHeader(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + httpGet.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + httpGet.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + return httpGet; + } + + protected String getArtifactUid(HttpResponse response) throws HttpResponseException, IOException, ParseException { + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + String artifactId = (String) responseMap.get("uniqueId"); + return artifactId; + } + + protected String getArtifactEsId(HttpResponse response) throws HttpResponseException, IOException, ParseException { + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + String esId = (String) responseMap.get("EsId"); + return esId; + } + + protected ArtifactDefinition addArtifactDataFromResponse(HttpResponse response, ArtifactDefinition artifact) throws HttpResponseException, IOException, ParseException { + //String responseString = new BasicResponseHandler().handleResponse(response); + HttpEntity entity = response.getEntity(); + String responseString = EntityUtils.toString(entity); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + artifact.setEsId((String)responseMap.get("esId")); + artifact.setUniqueId((String) responseMap.get("uniqueId")); + artifact.setArtifactGroupType(ArtifactGroupTypeEnum.findType((String) responseMap.get("artifactGroupType"))); + artifact.setTimeout(((Long) responseMap.get("timeout")).intValue()); + return artifact; + } + + protected String getLifecycleArtifactUid(CloseableHttpResponse response) throws HttpResponseException, IOException, ParseException { + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseMap = (JSONObject) jsonParser.parse(responseString); + responseMap = (JSONObject) responseMap.get("implementation"); + String artifactId = (String) responseMap.get("uniqueId"); + return artifactId; + } + + protected HttpDelete createDeleteArtifactRequest(String url) { + HttpDelete httpDelete = new HttpDelete(url); + httpDelete.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + httpDelete.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + return httpDelete; + } + + protected HttpPost createPostAddArtifactRequeast(String jsonBody, String url, boolean addMd5Header) throws UnsupportedEncodingException { + HttpPost httppost = new HttpPost(url); + httppost.addHeader(HttpHeaderEnum.CONTENT_TYPE.getValue(), contentTypeHeaderData); + httppost.addHeader(HttpHeaderEnum.ACCEPT.getValue(), acceptHeaderDate); + httppost.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + if (addMd5Header) { + httppost.addHeader(HttpHeaderEnum.Content_MD5.getValue(), GeneralUtility.calculateMD5ByString(jsonBody)); + } + StringEntity input = new StringEntity(jsonBody); + input.setContentType("application/json"); + httppost.setEntity(input); + log.debug("Executing request {}" , httppost.getRequestLine()); + return httppost; + } + + protected String createLoadArtifactBody() { + Map json = new HashMap(); + json.put("artifactName", "install_apache2.sh"); + json.put("artifactType", "SHELL"); + json.put("description", "ddd"); + json.put("payloadData", "UEsDBAoAAAAIAAeLb0bDQz"); + json.put("artifactLabel", "name123"); + + String jsonStr = gson.toJson(json); + return jsonStr; + } + + protected void checkDeleteResponse(RestResponse response) { + BaseRestUtils.checkStatusCode(response, "delete request failed", false, 204, 404); + } + + protected ArtifactUiDownloadData getArtifactUiDownloadData(String artifactUiDownloadDataStr) throws Exception { + + ObjectMapper mapper = new ObjectMapper(); + try { + ArtifactUiDownloadData artifactUiDownloadData = mapper.readValue(artifactUiDownloadDataStr, ArtifactUiDownloadData.class); + return artifactUiDownloadData; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/DeploymentValiditaion.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/DeploymentValiditaion.java new file mode 100644 index 0000000000..91a7b12a44 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/DeploymentValiditaion.java @@ -0,0 +1,428 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.io.FileUtils; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.PropertyReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.AssetRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.CatalogRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.common.util.ZipUtil; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import org.yaml.snakeyaml.Yaml; + +import com.aventstack.extentreports.Status; + + + + + + + +public class DeploymentValiditaion extends ComponentBaseTest{ + + + + + @Rule + public static TestName name = new TestName(); + + public DeploymentValiditaion() { + super(name, DeploymentValiditaion.class.getName()); + } + + protected final static String categoryFilterKey = "category"; + protected final static String subCategoryFilterKey = "subCategory"; + protected String attVersionStr ; + + + public static List listf(String directoryName) { + File directory = new File(directoryName); + + List resultList = new ArrayList(); + + // get all the files from a directory + File[] fList = directory.listFiles(); + resultList.addAll(Arrays.asList(fList)); + for (File file : fList) { + if (file.isFile()) { + System.out.println(file.getAbsolutePath()); + } else if (file.isDirectory()) { + resultList.addAll(listf(file.getAbsolutePath())); + } + } + //System.out.println(fList); + return resultList; + } + @BeforeTest + public void beforeTest() throws Exception{ + RestResponse attVersion = CatalogRestUtils.getOsVersion(); + attVersionStr = ResponseParser.getVersionFromResponse(attVersion); + } + + + @Test + public void pasrseNormativies() throws Exception{ + + + String path = "//apps//asdc_kits//catalog-be-" + attVersionStr + "//import//tosca//normative-types"; + String path2 = "//apps//asdc_kits//catalog-be-" + attVersionStr + "//import//tosca//heat-types"; + +// String path = "C:\\Git_work\\Git_UGN\\d2-sdnc\\catalog-be\\src\\main\\resources\\import\\tosca\\normative-types"; +// String path2 = "C:\\Git_work\\Git_UGN\\d2-sdnc\\catalog-be\\src\\main\\resources\\import\\tosca\\heat-types"; + + + List yamlList1 = getYamlFilesList(path); + List nodeNamesFromYamlList1 = getNodeNamesFromYamlList(yamlList1); + List yamlList2 = getYamlFilesList(path2); + List nodeNamesFromYamlList2 = getNodeNamesFromYamlList(yamlList2); + + + List expectedList = new ArrayList(); + expectedList.addAll(nodeNamesFromYamlList1); + expectedList.addAll(nodeNamesFromYamlList2); + System.out.println("list of normatives from files:::::::::::"); + expectedList.forEach(System.out::println); + getExtendTest().log(Status.INFO, "list of normatives from files:"); + getExtendTest().log(Status.INFO,expectedList.toString()); + + + String[] filter = { categoryFilterKey + "=" + ResourceCategoryEnum.GENERIC_ABSTRACT.getCategory(), subCategoryFilterKey + "=" + ResourceCategoryEnum.GENERIC_ABSTRACT.getSubCategory() }; + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.RESOURCES); + Map resourceAssetList = AssetRestUtils.getResourceAssetMap(assetResponse); + Map resourceListFiltteredByWholeVersion = AssetRestUtils.getResourceListFiltteredByWholeVersion(resourceAssetList); + List resourceToscaNamesList = AssetRestUtils.getResourceObjectByNameAndVersionToscaNamesList(resourceListFiltteredByWholeVersion); + System.out.println("list of normatives from APIs:::::::::::"); + resourceToscaNamesList.forEach(System.out::println); + getExtendTest().log(Status.INFO, "list of normatives from APIs:"); + getExtendTest().log(Status.INFO, resourceToscaNamesList.toString()); + + boolean good = true; + List missingNormatives = new ArrayList<>(); + + for (int i = 0; i < expectedList.size(); i ++) { + if (!resourceToscaNamesList.contains(expectedList.get(i))) { + good = false; + missingNormatives.add(expectedList.get(i)); + + + } + } + + System.out.println("<<<<<<<<>>>>>"); + missingNormatives.forEach(System.out::println); + getExtendTest().log(Status.INFO, "MISSING NORMATIVES:"); + getExtendTest().log(Status.INFO, missingNormatives.toString()); + + assertTrue("missing normatives ", good); + + } + + + public List getNodeNamesFromYamlList(List yamlList) throws IOException { + List nodeNameList = new ArrayList(); + + for (File file : yamlList) { + String content = new String(Files.readAllBytes(Paths.get(file.getPath())), StandardCharsets.UTF_8); + Yaml yaml = new Yaml(); + Map load = (Map) yaml.load(content); + Map topology_template = (Map) load.get("node_types"); +// String string = topology_template.keySet().toString().replaceAll("tosca.nodes.", ""); + String string = topology_template.keySet().iterator().next().toString(); + System.out.println(string +" -----> " +file.getPath()); + nodeNameList.add(string); + } + return nodeNameList; + } + + + public List getYamlFilesList(String path) throws IOException { + List yamlList = new ArrayList(); + File dir = new File(path); + String[] extensions = new String[] { "yml" }; + System.out.println("Getting all .yml files in " + dir.getCanonicalPath() + + " including those in subdirectories"); + List files = (List) FileUtils.listFiles(dir, extensions, true); + for (File file : files) { + System.out.println("file: " + file.getCanonicalPath()); + yamlList.add(file); + } + return yamlList; + } + + + + + + + @Test (enabled=false) + public void testYaml() throws IOException{ + + System.out.println(""); + + File file = new File("\\\\Comp-1\\FileIO\\Stop.txt"); + + + //read file + + + Map readZip = null; + Path path = Paths.get("C:\\Users\\ys9693\\Documents\\csar\\attributesWithProporties\\attributesWithProporties.csar"); + byte[] data = Files.readAllBytes(path); + if (data != null && data.length > 0) { + readZip = ZipUtil.readZip(data); + + } + + byte[] artifactsBs = readZip.get("Definitions/VF_RI2_G6.yaml"); + String str = new String(artifactsBs, StandardCharsets.UTF_8); + + + + + Yaml yaml = new Yaml(); + Map load = (Map) yaml.load(str); + Map topology_template = (Map) load.get("topology_template"); + Map node_templates = (Map) topology_template.get("node_templates"); + + Set keySet = node_templates.keySet(); + } + + + + @Test + public void pasrseDataTypes() throws Exception{ + +// String path = "C:\\Git_work\\Git_UGN\\d2-sdnc\\catalog-be\\src\\main\\resources\\import\\tosca\\data-types\\dataTypes.yml"; + String path = "//apps//asdc_kits//catalog-be-" + attVersionStr + "//import//tosca//data-types//dataTypes.yml"; + + String content = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); + + + Yaml yaml = new Yaml(); + Map load = (Map) yaml.load(content); + List listOfDataTypes = new ArrayList(); + listOfDataTypes.addAll(load.keySet()); + System.out.println("<<<<<<<< List of Data Types >>>>>>>>>"); + listOfDataTypes.forEach(System.out::println); + getExtendTest().log(Status.INFO, "List of Data Types:"); + getExtendTest().log(Status.INFO, listOfDataTypes.toString()); + + Resource resource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + PropertyReqDetails defaultProperty = ElementFactory.getDefaultListProperty(); + +// SchemaDefinition schemaDefinition = new SchemaDefinition(); + + + + + defaultProperty.setPropertyDefaultValue(null); +// defaultProperty.setSchema(schemaDefinition); + + +// listOfDataTypes.remove("tosca.datatypes.Root"); + for (String dataType : listOfDataTypes) { +// if (dataType.equals("map") || dataType.equals("list")){ + defaultProperty.setPropertyType(dataType); + defaultProperty.setName(dataType); + System.out.println("Adding proporty with data type: ----> " + dataType); + getExtendTest().log(Status.INFO, "Adding proporty with data type: ----> " + dataType); + AtomicOperationUtils.addCustomPropertyToResource(defaultProperty, resource, UserRoleEnum.DESIGNER, true); +// } + } + + + listOfDataTypes.forEach(System.out::println); + + } + + + + + + + @Test + public void pasrseCategories() throws Exception{ + +// String path = "C:\\Git_work\\Git_UGN\\d2-sdnc\\catalog-be\\src\\main\\resources\\import\\tosca\\categories\\categoryTypes.yml"; + String path = "//apps//asdc_kits//catalog-be-" + attVersionStr + "//import//tosca//categories//categoryTypes.yml"; + + String content = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); + + List serviceCategories = new ArrayList(); + List resourceCategories = new ArrayList(); + + Yaml yaml = new Yaml(); + Map load = (Map) yaml.load(content); + Map services = (Map) load.get("services"); + Map resources = (Map) load.get("resources"); + + Map> resourcesListFromFile = new HashMap>() ; + + //retrieve subcategories + for ( String resourceCategoryName : resources.keySet()) { + Map subcategory = (Map) resources.get(resourceCategoryName).get("subcategories"); + + resourceCategories = new ArrayList(); + for (String subcategoryName : subcategory.keySet()) { + String name = (String) subcategory.get(subcategoryName).get("name"); +// resourceCategories.add(name.replaceAll("\\s","")); + resourceCategories.add(name); + + } + resourcesListFromFile.put(resources.get(resourceCategoryName).get("name").toString(), resourceCategories); + } + + System.out.println(resourcesListFromFile.toString()); + getExtendTest().log(Status.INFO, "Expected categories:"); + getExtendTest().log(Status.INFO, resourcesListFromFile.toString()); + + //retrieve service categories +// for ( String serviceCategoryName : services.keySet()) { +// String name = (String) services.get(serviceCategoryName).get("name"); +// serviceCategories.add(name); +// } +// serviceCategories.forEach(System.out::println); + + + //retrieve resource list from URL + + Map> categoriesMap = getCategories(); + List resourceSubCategories = categoriesMap.get(ComponentTypeEnum.RESOURCE_PARAM_NAME); + List subcategories; + for (CategoryDefinition categoryDefinition : resourceSubCategories) { + subcategories = categoryDefinition.getSubcategories(); + } +// subcategories.stream().collect(toMap(i -> i, i -> items.get(i))); + +// resourceSubCategories.stream().collect( +// Collectors.groupingBy(CategoryDefinition::getName, Collectors.groupingBy(SubCategoryDefinition::getName))); + +// resourceSubCategories.stream().filter(p->p.getSubcategories()).map(m->m.getName()).collect(Collectors.toList()).collect(Collectors.toMap(CategoryDefinition::getName,m)); + + + Map> resourceMapFromUrl = resourceSubCategories.stream().collect(Collectors.toMap( e -> e.getName() , e -> e.getSubcategories().stream().map(e1 -> e1.getName()).collect(Collectors.toList()))); + + getExtendTest().log(Status.INFO, "Actual categories:"); + getExtendTest().log(Status.INFO, resourceMapFromUrl.toString()); + + + assertTrue("missing categories ", resourceMapFromUrl.keySet().containsAll(resourcesListFromFile.keySet())); + + + + + + + } + + + public Map> getCategories() throws Exception { + + User defaultAdminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + Map> map = new HashMap>(); + + + RestResponse allResourceCategories = CategoryRestUtils.getAllCategories(defaultAdminUser, ComponentTypeEnum.RESOURCE_PARAM_NAME); + RestResponse allServiceCategories = CategoryRestUtils.getAllCategories(defaultAdminUser, ComponentTypeEnum.SERVICE_PARAM_NAME); + + List parsedResourceCategories = ResponseParser.parseCategories(allResourceCategories); + List parsedServiceCategories = ResponseParser.parseCategories(allServiceCategories); + + map.put(ComponentTypeEnum.RESOURCE_PARAM_NAME, parsedResourceCategories); + map.put(ComponentTypeEnum.SERVICE_PARAM_NAME, parsedServiceCategories); + + return map; + } + + + + @Test (enabled=false) + public void pasrseCategoriesClass2() throws IOException{ + + String path = "C:\\Git_work\\Git_UGN\\d2-sdnc\\catalog-be\\src\\main\\resources\\import\\tosca\\categories\\categoryTypes.yml"; + + FileReader reader = new FileReader(path); + Yaml yaml=new Yaml(); + + + Map map = (Map) yaml.load(reader); + + Collection values = (Collection) map.values(); + for (Map map2 : values) { + Collection values2 = map2.values(); + for (Object object : values2) { + + + } + } + + { + + } + List collect = values.stream().map(e -> e.get("name")).collect(Collectors.toList()); + +// resourcesArrayList.stream().filter(s -> s.getName().toLowerCase().startsWith("ci") && !s.getName().toLowerCase().equals("cindervolume")).map(e -> e.getUniqueId()).collect(Collectors.toList()).forEach((i) + + + + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetAssetServlet.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetAssetServlet.java new file mode 100644 index 0000000000..90dd3a47ae --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetAssetServlet.java @@ -0,0 +1,343 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import static org.testng.AssertJUnit.assertEquals; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.codehaus.jackson.map.ObjectMapper; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactUiDownloadData; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedExternalAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.cassandra.CassandraUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.AssetRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.gson.Gson; + +public class GetAssetServlet extends ComponentBaseTest { + + protected User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + protected User sdncAdminUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + protected ConsumerDataDefinition consumerDataDefinition; + + @Rule + public static TestName name = new TestName(); + + public GetAssetServlet() { + super(name, GetAssetServlet.class.getName()); + } + + Gson gson = new Gson(); + +// @BeforeMethod +// public void setup() throws Exception { +// +// AtomicOperationUtils.createDefaultConsumer(true); +// +// } + + @Test // (enabled = false) + public void getResourceAssetSuccess() throws Exception { + +// CassandraUtils.truncateAllKeyspaces(); + List expectedAssetNamesList = new ArrayList<>(); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); + resourceDetails.setName("ciResource1"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + expectedAssetNamesList.add(resource.getName()); + + resourceDetails.setName("ciResource2"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + expectedAssetNamesList.add(resource.getName()); + expectedAssetNamesList.add(resource.getName()); + + resourceDetails.setName("ciResource3"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, + ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + expectedAssetNamesList.add(resource.getName()); + + resourceDetails.setName("ciResource4"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + expectedAssetNamesList.add(resource.getName()); + + resourceDetails.setName("ciResource5"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + expectedAssetNamesList.add(resource.getName()); + + resourceDetails.setName("ciResource6"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.STARTCERTIFICATION, true).getLeft(); + expectedAssetNamesList.add(resource.getName()); + + resourceDetails.setName("ciResource7"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true).getLeft(); + expectedAssetNamesList.add(resource.getName()); + expectedAssetNamesList.add(resource.getName()); + + System.out.println("7 VF resources were created"); + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.RESOURCES); + BaseRestUtils.checkSuccess(assetResponse); + + List resourceAssetList = AssetRestUtils.getResourceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getResourceNamesList(resourceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + AssetRestUtils.checkComponentTypeInObjectList(resourceAssetList, ComponentTypeEnum.RESOURCE); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_ASSET_LIST); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_LIST.getName(), body); + + } + + @Test // (enabled = false) + public void getServiceAssetSuccess() throws Exception { + +// CassandraUtils.truncateAllKeyspaces(); + List expectedAssetNamesList = new ArrayList<>(); + ArtifactReqDetails artifactDetails = ElementFactory.getArtifactByType(ArtifactTypeEnum.OTHER, ArtifactTypeEnum.OTHER, true); + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + serviceDetails.setName("ciService1"); + RestResponse createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + Service service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService2"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + expectedAssetNamesList.add(service.getName()); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService3"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService4"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService5"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService6"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.STARTCERTIFICATION, true).getLeft(); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService7"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true).getLeft(); + expectedAssetNamesList.add(service.getName()); + expectedAssetNamesList.add(service.getName()); + + System.out.println("7 Services were created"); + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.SERVICES); + BaseRestUtils.checkSuccess(assetResponse); + + List serviceAssetList = AssetRestUtils.getServiceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getServiceNamesList(serviceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_ASSET_LIST); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_LIST.getName(), body); + + } + + @Test + public void getToscaModelSuccess() throws Exception { + + CloseableHttpClient httpclient = HttpClients.createDefault(); + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(); +// resourceDetails.setName("ciResource11"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncUserDetails); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + HttpResponse assetResponse = AssetRestUtils.getComponentToscaModel(AssetTypeEnum.RESOURCES, resource.getUUID()); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + String artId = resource.getToscaArtifacts().get("assettoscacsar").getEsId(); + String url = String.format(Urls.UI_DOWNLOAD_RESOURCE_ARTIFACT, config.getCatalogBeHost(), config.getCatalogBePort(), resource.getUniqueId(), artId); + HttpGet httpGet = createGetRequest(url); + HttpResponse response = httpclient.execute(httpGet); + InputStream inputStream = response.getEntity().getContent(); + ArtifactUiDownloadData artifactUiDownloadData = getArtifactUiDownloadData(IOUtils.toString(inputStream)); + assetResponse = AssetRestUtils.getComponentToscaModel(AssetTypeEnum.RESOURCES, resource.getUUID()); + inputStream = assetResponse.getEntity().getContent(); + int len = (int) assetResponse.getEntity().getContentLength(); + byte[] res = new byte[len]; + inputStream.read(res, 0, len); + byte[] fromUiDownload = artifactUiDownloadData.getBase64Contents().getBytes(); + assertEquals(Base64.encodeBase64(res), fromUiDownload); + String fileName = assetResponse.getFirstHeader(Constants.CONTENT_DISPOSITION_HEADER).getValue(); + assertEquals(fileName, new StringBuilder().append("attachment; filename=\"") + .append(artifactUiDownloadData.getArtifactName()).append("\"").toString()); + } + + private HttpGet createGetRequest(String url) { + HttpGet httpGet = new HttpGet(url); + httpGet.addHeader(HttpHeaderEnum.USER_ID.getValue(), sdncUserDetails.getUserId()); + return httpGet; + } + + private ArtifactUiDownloadData getArtifactUiDownloadData(String artifactUiDownloadDataStr) throws Exception { + + ObjectMapper mapper = new ObjectMapper(); + try { + ArtifactUiDownloadData artifactUiDownloadData = mapper.readValue(artifactUiDownloadDataStr, + ArtifactUiDownloadData.class); + return artifactUiDownloadData; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetCSARofVF.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetCSARofVF.java new file mode 100644 index 0000000000..6acc54b54c --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetCSARofVF.java @@ -0,0 +1,262 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import static org.testng.AssertJUnit.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.codehaus.jackson.map.ObjectMapper; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.datatypes.elements.ConsumerDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactUiDownloadData; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.api.Urls; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedExternalAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.cassandra.CassandraUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.AssetRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import static org.testng.AssertJUnit.assertTrue; + +import com.google.gson.Gson; + +import fj.data.Either; + +public class GetCSARofVF extends ComponentBaseTest { + +// protected User sdncUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); +// protected User sdncAdminUserDetails = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); +// protected ConsumerDataDefinition consumerDataDefinition; + + @Rule + public static TestName name = new TestName(); + + public GetCSARofVF() { + super(name, GetCSARofVF.class.getName()); + } + +// Gson gson = new Gson(); + + @BeforeMethod + public void setup() throws Exception { + +// AtomicOperationUtils.createDefaultConsumer(true); +// CassandraUtils.truncateAllKeyspaces(); + + + } + + @Test + public void getResourceToscaModelCheckOutState() throws Exception { + + + Resource resource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + +// HttpResponse componentToscaModel = AssetRestUtils.getComponentToscaModel(AssetTypeEnum.RESOURCES, resource.getUUID()); + File toscaModelCsarFile = AssetRestUtils.getToscaModelCsarFile(AssetTypeEnum.RESOURCES, resource.getUUID()); + + // validate tosca structure + validateCsarContent(resource, toscaModelCsarFile); + + // Validate audit message + validateAudit(resource); + + + + } + + + + @Test + public void getResourceToscaModelCheckInState() throws Exception { + + Resource resource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + + AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + +// HttpResponse componentToscaModel = AssetRestUtils.getComponentToscaModel(AssetTypeEnum.RESOURCES, resource.getUUID()); + File toscaModelCsarFile = AssetRestUtils.getToscaModelCsarFile(AssetTypeEnum.RESOURCES, resource.getUUID()); + + // validate tosca structure + validateCsarContent(resource, toscaModelCsarFile); + + // Validate audit message + validateAudit(resource); + + + + } + + @Test + public void getRsourceToscaModelCertifyState() throws Exception { + + Resource resource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + + AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + +// HttpResponse componentToscaModel = AssetRestUtils.getComponentToscaModel(AssetTypeEnum.RESOURCES, resource.getUUID()); + File toscaModelCsarFile = AssetRestUtils.getToscaModelCsarFile(AssetTypeEnum.RESOURCES, resource.getUUID()); + + // validate tosca structure + validateCsarContent(resource, toscaModelCsarFile); + + // Validate audit message + validateAudit(resource); + + + } + + + @Test + public void getServiceToscaModelCheckOutState() throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + +// HttpResponse componentToscaModel = AssetRestUtils.getComponentToscaModel(AssetTypeEnum.RESOURCES, resource.getUUID()); + File toscaModelCsarFile = AssetRestUtils.getToscaModelCsarFile(AssetTypeEnum.SERVICES, service.getUUID()); + + // validate tosca structure + validateCsarContent(service, toscaModelCsarFile); + + validateAudit(service); + + + + } + + @Test + public void getServiceToscaModelCheckInState() throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + + AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true); + +// HttpResponse componentToscaModel = AssetRestUtils.getComponentToscaModel(AssetTypeEnum.RESOURCES, resource.getUUID()); + File toscaModelCsarFile = AssetRestUtils.getToscaModelCsarFile(AssetTypeEnum.SERVICES, service.getUUID()); + + // validate tosca structure + validateCsarContent(service, toscaModelCsarFile); + + validateAudit(service); + + + } + + @Test + public void getServiceToscaModelCertifyState() throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.OTHER, service, UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + +// HttpResponse componentToscaModel = AssetRestUtils.getComponentToscaModel(AssetTypeEnum.RESOURCES, resource.getUUID()); + File toscaModelCsarFile = AssetRestUtils.getToscaModelCsarFile(AssetTypeEnum.SERVICES, service.getUUID()); + + // validate tosca structure + validateCsarContent(service, toscaModelCsarFile); + + validateAudit(service); + + } + + + + + + + public void validateCsarContent(Component resource, File toscaModelCsarFile) throws ZipException, IOException { + ZipFile zipFile = new ZipFile(toscaModelCsarFile); + Enumeration entries = zipFile.entries(); + while(entries.hasMoreElements()){ + ZipEntry nextElement = entries.nextElement(); + if (!(nextElement.getName().contains("Artifacts")||nextElement.getName().contains("csar.meta"))){ + assertTrue("missing file in csar template", (nextElement.getName().equals("TOSCA-Metadata/TOSCA.meta") || + nextElement.getName().equals("Definitions/"+ resource.getComponentType().getValue().toLowerCase()+"-"+ resource.getSystemName()+"-template.yml")) || + nextElement.getName().equals("Definitions/"+ resource.getComponentType().getValue().toLowerCase()+"-"+ resource.getSystemName()+"-template-interface.yml")); + } + } + } + + public void validateAudit(Component resource) throws Exception { + ExpectedExternalAudit expectedAudit = null; + if (resource.getComponentType().equals(ComponentTypeEnum.RESOURCE)){ + expectedAudit = ElementFactory.getDefaultExternalAuditObject(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_TOSCA_MODEL, ("/" + resource.getUUID() + "/toscaModel")); + } + else expectedAudit = ElementFactory.getDefaultExternalAuditObject(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_TOSCA_MODEL, ("/" + resource.getUUID() + "/toscaModel")); + expectedAudit.setRESOURCE_NAME(resource.getName()); + expectedAudit.setSERVICE_INSTANCE_ID(resource.getUUID()); + expectedAudit.setRESOURCE_TYPE(resource.getComponentType().getValue()); +// AuditValidationUtils.validateExternalAudit(expectedAudit, AuditingActionEnum.GET_TOSCA_MODEL.getName(), null); + + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, expectedAudit.getRESOURCE_NAME()); + AuditValidationUtils.validateExternalAudit(expectedAudit, AuditingActionEnum.GET_TOSCA_MODEL.getName(), body); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetFilteredAssetServlet.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetFilteredAssetServlet.java new file mode 100644 index 0000000000..008cdbb1a5 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetFilteredAssetServlet.java @@ -0,0 +1,712 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedExternalAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.AssetRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.LifecycleRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class GetFilteredAssetServlet extends ComponentBaseTest { + + private static Logger log = LoggerFactory.getLogger(GetAssetServlet.class.getName()); + protected final static String categoryFilterKey = "category"; + protected final static String subCategoryFilterKey = "subCategory"; + protected final static String distributionStatusFilterKey = "distributionStatus"; + protected final static String serviceKey = "service"; + protected final static String resourceKey = "resource"; + protected final static String resourceType = "resourceType"; + protected final static String validFilterParameters = "[" + resourceType + ", "+ subCategoryFilterKey + ", " + categoryFilterKey + "]"; + + @Rule + public static TestName name = new TestName(); + + public GetFilteredAssetServlet() { + super(name, GetFilteredAssetServlet.class.getName()); + } + +// @BeforeMethod +// public void setup() throws Exception { +// AtomicOperationUtils.createDefaultConsumer(true); +// } + + // RESOURCE + // Success + + @Test // (enabled = false) + public void getResourceAssetBySpecifiedCategory() throws Exception { + String[] filter = { categoryFilterKey + "=" + ResourceCategoryEnum.GENERIC_ABSTRACT.getCategory() }; + List expectedAssetNamesList = new ArrayList<>(); + + Resource resource1 = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.COMPUTE, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left().value(); + expectedAssetNamesList.add(resource1.getName()); + Resource resource2 = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.DATABASE, ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, UserRoleEnum.DESIGNER, true).left().value(); + expectedAssetNamesList.add(resource2.getName()); + Resource resource3 = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.COMPUTE, ResourceCategoryEnum.NETWORK_CONNECTIVITY_CON_POINT, UserRoleEnum.DESIGNER, true).left().value(); + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.RESOURCES, filter); + BaseRestUtils.checkSuccess(assetResponse); + + List resourceAssetList = AssetRestUtils.getResourceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getResourceNamesList(resourceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + + } + + // 2 resources has the same category and different subcategory + @Test // (enabled = false) + public void getResourceAssetBySpecifiedCategoryAndSubCategory() throws Exception { + String[] filter = { categoryFilterKey + "=" + ResourceCategoryEnum.GENERIC_ABSTRACT.getCategory(), subCategoryFilterKey + "=" + ResourceCategoryEnum.GENERIC_ABSTRACT.getSubCategory() }; + // String[] filter2 = {categoryFilterKey + "=" + + // ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS.getCategory(), + // subCategoryFilterKey + "=" + + // ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS.getSubCategory()}; + List expectedAssetNamesList = new ArrayList<>(); + + Resource resource1 = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.COMPUTE, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left().value(); + expectedAssetNamesList.add(resource1.getName()); + Resource resource2 = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.DATABASE, ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS, UserRoleEnum.DESIGNER, true).left().value(); + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.RESOURCES, filter); + BaseRestUtils.checkSuccess(assetResponse); + + List resourceAssetList = AssetRestUtils.getServiceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getServiceNamesList(resourceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetBySpecifiedSubCategoryAndCategory() throws Exception { + String[] filter = { subCategoryFilterKey + "=" + ResourceCategoryEnum.GENERIC_DATABASE.getSubCategory(), categoryFilterKey + "=" + ResourceCategoryEnum.GENERIC_DATABASE.getCategory(), }; + List expectedAssetNamesList = new ArrayList<>(); + + Resource resource1 = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.COMPUTE, ResourceCategoryEnum.GENERIC_ABSTRACT, UserRoleEnum.DESIGNER, true).left().value(); + Resource resource2 = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.DATABASE, ResourceCategoryEnum.GENERIC_DATABASE, UserRoleEnum.DESIGNER, true).left().value(); + expectedAssetNamesList.add(resource2.getName()); + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.RESOURCES, filter); + BaseRestUtils.checkSuccess(assetResponse); + + List resourceAssetList = AssetRestUtils.getServiceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getServiceNamesList(resourceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + // Failure + @Test // (enabled = false) + public void getResourceAssetCategoryNotExists() throws Exception { + String[] filter = { categoryFilterKey + "=" + "NotExistingCategory" }; + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.RESOURCES, filter); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name()); + + assertNotNull("check response object is not null after create resouce", assetResponse); + assertNotNull("check error code exists in response after create resource", assetResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), assetResponse.getErrorCode()); + + List variables = Arrays.asList(resourceKey, categoryFilterKey, "NotExistingCategory"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name(), variables, assetResponse.getResponse()); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + expectedAssetListAudit.setSTATUS(errorInfo.getCode().toString()); + expectedAssetListAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetSubCategoryNotExists() throws Exception { + String[] filter = { categoryFilterKey + "=" + ResourceCategoryEnum.GENERIC_ABSTRACT.getCategory(), subCategoryFilterKey + "=" + "NotExistingSubCategory" }; + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.RESOURCES, filter); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_SUB_CATEGORY_NOT_FOUND_FOR_CATEGORY.name()); + + assertNotNull("check response object is not null after create resouce", assetResponse); + assertNotNull("check error code exists in response after create resource", assetResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), assetResponse.getErrorCode()); + + List variables = Arrays.asList("Resource", "NotExistingSubCategory", ResourceCategoryEnum.GENERIC_ABSTRACT.getCategory()); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_SUB_CATEGORY_NOT_FOUND_FOR_CATEGORY.name(), variables, assetResponse.getResponse()); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + expectedAssetListAudit.setSTATUS(errorInfo.getCode().toString()); + expectedAssetListAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetCategoryNotExistsSubCategoryExists() throws Exception { + String[] filter = { subCategoryFilterKey + "=" + ResourceCategoryEnum.NETWORK_L2_3_GETEWAY.getSubCategory(), categoryFilterKey + "=" + "NotExistingCategory" }; + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.RESOURCES, filter); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name()); + + assertNotNull("check response object is not null after create resouce", assetResponse); + assertNotNull("check error code exists in response after create resource", assetResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), assetResponse.getErrorCode()); + + List variables = Arrays.asList(resourceKey, categoryFilterKey, "NotExistingCategory"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name(), variables, assetResponse.getResponse()); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + expectedAssetListAudit.setSTATUS(errorInfo.getCode().toString()); + expectedAssetListAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetInvalidFilterKey() throws Exception { + String[] filter = { subCategoryFilterKey + "1=" + ResourceCategoryEnum.NETWORK_L2_3_GETEWAY.getSubCategory(), categoryFilterKey + "=" + "NotExistingCategory" }; + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.RESOURCES, filter); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_FILTER_KEY.name()); + + assertNotNull("check response object is not null after create resouce", assetResponse); + assertNotNull("check error code exists in response after create resource", assetResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), assetResponse.getErrorCode()); + + List variables = Arrays.asList(subCategoryFilterKey + "1", validFilterParameters); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FILTER_KEY.name(), variables, assetResponse.getResponse()); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + expectedAssetListAudit.setSTATUS(errorInfo.getCode().toString()); + expectedAssetListAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + // --------------------------------------------------------------------------------------------------------- + // SERVICE + // Success + @Test // (enabled = false) + public void getServiceAssetBySpecifiedCategory() throws Exception { + String[] filter = { categoryFilterKey + "=" + ServiceCategoriesEnum.MOBILITY.getValue() }; + List expectedAssetNamesList = new ArrayList<>(); + + Service service1 = AtomicOperationUtils.createServiceByCategory(ServiceCategoriesEnum.MOBILITY, UserRoleEnum.DESIGNER, true).left().value(); + expectedAssetNamesList.add(service1.getName()); + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.SERVICES, filter); + BaseRestUtils.checkSuccess(assetResponse); + + List serviceAssetList = AssetRestUtils.getServiceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getServiceNamesList(serviceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getServiceAssetBySpecifiedCategoryAndDistributionStatus() throws Exception { + String[] filter = { categoryFilterKey + "=" + ServiceCategoriesEnum.MOBILITY.getValue(), distributionStatusFilterKey + "=" + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED }; + List expectedAssetNamesList = new ArrayList<>(); + ArtifactReqDetails artifactDetails = ElementFactory.getArtifactByType(ArtifactTypeEnum.OTHER, ArtifactTypeEnum.OTHER, true); + + Service service1 = AtomicOperationUtils.createServiceByCategory(ServiceCategoriesEnum.MOBILITY, UserRoleEnum.DESIGNER, true).left().value(); + expectedAssetNamesList.add(service1.getName()); + Service service2 = AtomicOperationUtils.createServiceByCategory(ServiceCategoriesEnum.MOBILITY, UserRoleEnum.DESIGNER, true).left().value(); + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service2.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service2 = (Service) AtomicOperationUtils.changeComponentState(service2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + expectedAssetNamesList.add(service2.getName()); + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.SERVICES, filter); + BaseRestUtils.checkSuccess(assetResponse); + + List serviceAssetList = AssetRestUtils.getServiceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getServiceNamesList(serviceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getServiceAssetByDistributionStatus() throws Exception { + String[] filter = { distributionStatusFilterKey + "=" + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED }; + List expectedAssetNamesList = new ArrayList<>(); + ArtifactReqDetails artifactDetails = ElementFactory.getArtifactByType(ArtifactTypeEnum.OTHER, ArtifactTypeEnum.OTHER, true); + + Service service1 = AtomicOperationUtils.createServiceByCategory(ServiceCategoriesEnum.MOBILITY, UserRoleEnum.DESIGNER, true).left().value(); + expectedAssetNamesList.add(service1.getName()); + Service service2 = AtomicOperationUtils.createServiceByCategory(ServiceCategoriesEnum.MOBILITY, UserRoleEnum.DESIGNER, true).left().value(); + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service2.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service2 = (Service) AtomicOperationUtils.changeComponentState(service2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + ServiceRestUtils.approveServiceDistribution(service2.getUniqueId(), UserRoleEnum.GOVERNOR.getUserId()); + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.SERVICES, filter); + BaseRestUtils.checkSuccess(assetResponse); + + List serviceAssetList = AssetRestUtils.getServiceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getServiceNamesList(serviceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + // Failure + @Test // (enabled = false) + public void getServiceAssetCategoryNotExists() throws Exception { + String[] filter = { categoryFilterKey + "=" + "NotExistingCategory" }; + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.SERVICES, filter); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name()); + + assertNotNull("check response object is not null after create resouce", assetResponse); + assertNotNull("check error code exists in response after create resource", assetResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), assetResponse.getErrorCode()); + + List variables = Arrays.asList(serviceKey, categoryFilterKey, "NotExistingCategory"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name(), variables, assetResponse.getResponse()); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + expectedAssetListAudit.setSTATUS(errorInfo.getCode().toString()); + expectedAssetListAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getServiceAssetInvalidDistributionStatus() throws Exception { + String[] filter = { distributionStatusFilterKey + "=" + "NotExistingDistributionStatus" }; + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.SERVICES, filter); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name()); + + assertNotNull("check response object is not null after create resouce", assetResponse); + assertNotNull("check error code exists in response after create resource", assetResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), assetResponse.getErrorCode()); + + List variables = Arrays.asList(serviceKey, distributionStatusFilterKey, "NotExistingDistributionStatus"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name(), variables, assetResponse.getResponse()); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + expectedAssetListAudit.setSTATUS(errorInfo.getCode().toString()); + expectedAssetListAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getServiceAssetCategoryExitsDistributionStatusInvalid() throws Exception { + String[] filter = { categoryFilterKey + "=" + ServiceCategoriesEnum.MOBILITY.getValue(), distributionStatusFilterKey + "=" + "NotExistingDistributionStatus" }; + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.SERVICES, filter); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name()); + + assertNotNull("check response object is not null after create resouce", assetResponse); + assertNotNull("check error code exists in response after create resource", assetResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), assetResponse.getErrorCode()); + + List variables = Arrays.asList(serviceKey, distributionStatusFilterKey, "NotExistingDistributionStatus"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name(), variables, assetResponse.getResponse()); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + expectedAssetListAudit.setSTATUS(errorInfo.getCode().toString()); + expectedAssetListAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getServiceAssetCategoryNotExistsDistributionStatus() throws Exception { + String[] filter = { distributionStatusFilterKey + "=" + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, categoryFilterKey + "=" + "NotExistingCategory" }; + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.SERVICES, filter); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name()); + + assertNotNull("check response object is not null after create resouce", assetResponse); + assertNotNull("check error code exists in response after create resource", assetResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), assetResponse.getErrorCode()); + + List variables = Arrays.asList(serviceKey, categoryFilterKey, "NotExistingCategory"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.COMPONENT_CATEGORY_NOT_FOUND.name(), variables, assetResponse.getResponse()); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + expectedAssetListAudit.setSTATUS(errorInfo.getCode().toString()); + expectedAssetListAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @Test // (enabled = false) + public void getServiceAssetInvalidFilterKey() throws Exception { + String[] filter = { distributionStatusFilterKey + "1=" + DistributionStatusEnum.DISTRIBUTION_NOT_APPROVED, categoryFilterKey + "=" + ServiceCategoriesEnum.MOBILITY.getValue() }; + + RestResponse assetResponse = AssetRestUtils.getComponentListByAssetType(true, AssetTypeEnum.SERVICES, filter); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_FILTER_KEY.name()); + + assertNotNull("check response object is not null after create resouce", assetResponse); + assertNotNull("check error code exists in response after create resource", assetResponse.getErrorCode()); + assertEquals("Check response code after create resource", errorInfo.getCode(), assetResponse.getErrorCode()); + + List variables = Arrays.asList(distributionStatusFilterKey + "1", "[" + categoryFilterKey + ", " + distributionStatusFilterKey + "]"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FILTER_KEY.name(), variables, assetResponse.getResponse()); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetListAudit(AssetTypeEnum.SERVICES, AuditingActionEnum.GET_FILTERED_ASSET_LIST); + expectedAssetListAudit.setRESOURCE_URL(AssetRestUtils.buildUrlWithFilter(expectedAssetListAudit.getRESOURCE_URL(), filter)); + expectedAssetListAudit.setSTATUS(errorInfo.getCode().toString()); + expectedAssetListAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + + } + + @Test + public void getFilteredResourceAssetCategoryNotFound() throws Exception { + + String query = "category=Application%20L3%2B"; + RestResponse assetResponse = AssetRestUtils.getFilteredComponentList(AssetTypeEnum.RESOURCES, query); + BaseRestUtils.checkErrorResponse(assetResponse, ActionStatus.COMPONENT_CATEGORY_NOT_FOUND, "resource", "category", "Application L3+"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getFilteredAssetListAuditCategoryNotFound(AssetTypeEnum.RESOURCES, "?" + query, "Application L3+"); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + + } + + @Test + public void getFilteredResourceAssetSuccess() throws Exception { + + List expectedAssetNamesList = new ArrayList<>(); + + ResourceReqDetails resourceDetails = ElementFactory.getDefaultResource(ResourceCategoryEnum.APPLICATION_L4_APP_SERVER); +// resourceDetails.setName("ciResource11"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + Resource resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + expectedAssetNamesList.add(resource.getName()); + + resourceDetails = ElementFactory.getDefaultResource(ResourceCategoryEnum.APPLICATION_L4_BORDER); +// resourceDetails.setName("ciResource22"); + resourceDetails.setResourceType(ResourceTypeEnum.VFC.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + + resourceDetails = ElementFactory.getDefaultResource(ResourceCategoryEnum.GENERIC_INFRASTRUCTURE); +// resourceDetails.setName("ciResource33"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + resourceDetails = ElementFactory.getDefaultResource(ResourceCategoryEnum.APPLICATION_L4_FIREWALL); +// resourceDetails.setName("ciResource44"); + resourceDetails.setResourceType(ResourceTypeEnum.VF.name()); + createResource = ResourceRestUtils.createResource(resourceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createResource); + resource = ResponseParser.parseToObjectUsingMapper(createResource.getResponse(), Resource.class); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + resource = (Resource) AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + expectedAssetNamesList.add(resource.getName()); + + log.debug("4 resources created"); + String query = "category=Application%20L4%2B"; + RestResponse assetResponse = AssetRestUtils.getFilteredComponentList(AssetTypeEnum.RESOURCES, query); + BaseRestUtils.checkSuccess(assetResponse); + + List resourceAssetList = AssetRestUtils.getResourceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getResourceNamesList(resourceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + +// Andrey L. This condition can not be checked in case resources list has two or ore different resource types +// AssetRestUtils.checkResourceTypeInObjectList(resourceAssetList, ResourceTypeEnum.VF); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultFilteredAssetListAudit(AssetTypeEnum.RESOURCES, "?" + query); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + + } + + @Test + public void getFilteredServiceAssetInformationalSuccess() throws Exception { + + List expectedAssetNamesList = new ArrayList<>(); + ArtifactReqDetails artifactDetails = ElementFactory.getArtifactByType(ArtifactTypeEnum.OTHER, ArtifactTypeEnum.OTHER, true); + artifactDetails.setArtifactGroupType(ArtifactGroupTypeEnum.INFORMATIONAL.getType()); + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + serviceDetails.setName("ciService111"); + RestResponse createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + Service service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + + serviceDetails.setName("ciService222"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + ServiceReqDetails certifyService = new ServiceReqDetails(service); + LifecycleRestUtils.changeDistributionStatus(certifyService, certifyService.getVersion(), ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR), null, DistributionStatusEnum.DISTRIBUTION_APPROVED); + AtomicOperationUtils.distributeService(service, false); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService333"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + certifyService = new ServiceReqDetails(service); + LifecycleRestUtils.changeDistributionStatus(certifyService, certifyService.getVersion(), ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR), null, DistributionStatusEnum.DISTRIBUTION_APPROVED); + AtomicOperationUtils.distributeService(service, false); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService444"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + serviceDetails.setName("ciService555"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + + String query = "distributionStatus=Distributed"; + RestResponse assetResponse = AssetRestUtils.getFilteredComponentList(AssetTypeEnum.SERVICES, query); + BaseRestUtils.checkSuccess(assetResponse); + + List resourceAssetList = AssetRestUtils.getServiceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getServiceNamesList(resourceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultFilteredAssetListAudit(AssetTypeEnum.SERVICES, "?" + query); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + + } + + @Test + public void getFilteredServiceAssetDeploymentSuccess() throws Exception { + + List expectedAssetNamesList = new ArrayList<>(); + ArtifactReqDetails artifactDetails = ElementFactory.getArtifactByType(ArtifactTypeEnum.OTHER, ArtifactTypeEnum.OTHER, true); + + ServiceReqDetails serviceDetails = ElementFactory.getDefaultService(); + serviceDetails.setName("ciService666"); + RestResponse createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + Service service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + + serviceDetails.setName("ciService777"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + RestResponse addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + ServiceReqDetails certifyService = new ServiceReqDetails(service); + LifecycleRestUtils.changeDistributionStatus(certifyService, certifyService.getVersion(), ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR), null, DistributionStatusEnum.DISTRIBUTION_APPROVED); + AtomicOperationUtils.distributeService(service, false); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService888"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + addInformationalArtifactToService = ArtifactRestUtils.addInformationalArtifactToService(artifactDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), service.getUniqueId()); + BaseRestUtils.checkSuccess(addInformationalArtifactToService); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + certifyService = new ServiceReqDetails(service); + LifecycleRestUtils.changeDistributionStatus(certifyService, certifyService.getVersion(), ElementFactory.getDefaultUser(UserRoleEnum.GOVERNOR), null, DistributionStatusEnum.DISTRIBUTION_APPROVED); + AtomicOperationUtils.distributeService(service, false); + expectedAssetNamesList.add(service.getName()); + + serviceDetails.setName("ciService999"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + serviceDetails.setName("ciService000"); + createService = ServiceRestUtils.createService(serviceDetails, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)); + BaseRestUtils.checkCreateResponse(createService); + service = ResponseParser.parseToObjectUsingMapper(createService.getResponse(), Service.class); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + + String query = "distributionStatus=Distributed"; + RestResponse assetResponse = AssetRestUtils.getFilteredComponentList(AssetTypeEnum.SERVICES, query); + BaseRestUtils.checkSuccess(assetResponse); + + List resourceAssetList = AssetRestUtils.getServiceAssetList(assetResponse); + List getActualAssetNamesList = AssetRestUtils.getServiceNamesList(resourceAssetList); + Utils.compareArrayLists(getActualAssetNamesList, expectedAssetNamesList, "Element"); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultFilteredAssetListAudit(AssetTypeEnum.SERVICES, "?" + query); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetSpecificAssetMetadataServlet.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetSpecificAssetMetadataServlet.java new file mode 100644 index 0000000000..2cb307cdb8 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/GetSpecificAssetMetadataServlet.java @@ -0,0 +1,447 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.ResourceDetailedAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ServiceDetailedAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedExternalAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.AssetRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class GetSpecificAssetMetadataServlet extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public GetSpecificAssetMetadataServlet() { + super(name, GetSpecificAssetMetadataServlet.class.getName()); + } + +// @BeforeMethod +// public void setup() throws Exception { +// AtomicOperationUtils.createDefaultConsumer(true); +// } + + // get specific asset metadata + + // Resource + @Test // (enabled = false) + public void getResourceAssetMetadataSuccess() throws Exception { + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.RESOURCES, resourceVF.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ResourceDetailedAssetStructure resourceAssetMetadata = AssetRestUtils.getResourceAssetMetadata(assetResponse); + AssetRestUtils.resourceMetadataValidatior(resourceAssetMetadata, resourceVF, AssetTypeEnum.RESOURCES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.RESOURCES, resourceVF); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetMetadataWithResourceInstancesSuccess() throws Exception { + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + Resource resource2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + resourceVF = ResponseParser.parseToObjectUsingMapper(ResourceRestUtils.getResource(resourceVF.getUniqueId()).getResponse(), Resource.class); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.RESOURCES, resourceVF.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ResourceDetailedAssetStructure resourceAssetMetadata = AssetRestUtils.getResourceAssetMetadata(assetResponse); + AssetRestUtils.resourceMetadataValidatior(resourceAssetMetadata, resourceVF, AssetTypeEnum.RESOURCES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory + .getDefaultAssetMetadataAudit(AssetTypeEnum.RESOURCES, resourceVF); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetMetadataWithNonCertifiedResourceInstancesSuccess() throws Exception { + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + Resource resource2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + Resource resource3 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource3 = (Resource) AtomicOperationUtils.changeComponentState(resource3, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource3, resourceVF, UserRoleEnum.DESIGNER, true); + + // certify resource2 and add to VF(VF with resource2 0.1, 1.0 and 1.1 + // versions) + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + resourceVF = ResponseParser.parseToObjectUsingMapper(ResourceRestUtils.getResource(resourceVF.getUniqueId()).getResponse(), Resource.class); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.RESOURCES, resourceVF.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ResourceDetailedAssetStructure resourceAssetMetadata = AssetRestUtils.getResourceAssetMetadata(assetResponse); + AssetRestUtils.resourceMetadataValidatior(resourceAssetMetadata, resourceVF, AssetTypeEnum.RESOURCES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.RESOURCES, resourceVF); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetMetadataWithResourceInstancesVfInSubmitForTestingSuccess() throws Exception { + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + Resource resource2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + Resource resource3 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource3 = (Resource) AtomicOperationUtils.changeComponentState(resource3, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource3, resourceVF, UserRoleEnum.DESIGNER, true); + + // certify resource2 and add to VF(VF with resource2 1.0, 2.0 and 3.0 + // versions) + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true).getLeft(); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.RESOURCES, resourceVF.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ResourceDetailedAssetStructure resourceAssetMetadata = AssetRestUtils.getResourceAssetMetadata(assetResponse); + AssetRestUtils.resourceMetadataValidatior(resourceAssetMetadata, resourceVF, AssetTypeEnum.RESOURCES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.RESOURCES, resourceVF); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetMetadataWithResourceInstancesVfInStartCertificationSuccess() throws Exception { + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + Resource resource2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + Resource resource3 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource3 = (Resource) AtomicOperationUtils.changeComponentState(resource3, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource3, resourceVF, UserRoleEnum.DESIGNER, true); + + // certify resource2 and add to VF(VF with resource2 1.0, 2.0 and 3.0 + // versions) + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.STARTCERTIFICATION, true).getLeft(); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.RESOURCES, resourceVF.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ResourceDetailedAssetStructure resourceAssetMetadata = AssetRestUtils.getResourceAssetMetadata(assetResponse); + AssetRestUtils.resourceMetadataValidatior(resourceAssetMetadata, resourceVF, AssetTypeEnum.RESOURCES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.RESOURCES, resourceVF); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetMetadataWithResourceInstancesCertifiedVFSuccess() throws Exception { + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + Resource resource2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + Resource resource3 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource3 = (Resource) AtomicOperationUtils.changeComponentState(resource3, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource3, resourceVF, UserRoleEnum.DESIGNER, true); + + // certify resource2 and add to VF(VF with resource2 1.0, 2.0 and 3.0 + // versions) + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.RESOURCES, resourceVF.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ResourceDetailedAssetStructure resourceAssetMetadata = AssetRestUtils.getResourceAssetMetadata(assetResponse); + AssetRestUtils.resourceMetadataValidatior(resourceAssetMetadata, resourceVF, AssetTypeEnum.RESOURCES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.RESOURCES, resourceVF); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + } + + @Test // (enabled = false) + public void getResourceAssetMetadataWithNonCertifiedResourceInstancesAndArtifactsSuccess() throws Exception { + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + Resource resource2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource2 = (Resource) AtomicOperationUtils.changeComponentState(resource2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + Resource resource3 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VFC, UserRoleEnum.DESIGNER, true).left().value(); + resource3 = (Resource) AtomicOperationUtils.changeComponentState(resource3, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource2, resourceVF, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resource3, resourceVF, UserRoleEnum.DESIGNER, true); + + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.VENDOR_LICENSE, resourceVF, UserRoleEnum.DESIGNER, true, true); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.APPC_CONFIG, resourceVF, UserRoleEnum.DESIGNER, true, true); + resourceVF = ResponseParser.parseToObjectUsingMapper(ResourceRestUtils.getResource(resourceVF.getUniqueId()).getResponse(), Resource.class); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.RESOURCES, resourceVF.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ResourceDetailedAssetStructure resourceAssetMetadata = AssetRestUtils.getResourceAssetMetadata(assetResponse); + AssetRestUtils.resourceMetadataValidatior(resourceAssetMetadata, resourceVF, AssetTypeEnum.RESOURCES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.RESOURCES, resourceVF); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + } + + // Import CSAR + + // Service + @Test // (enabled = false) + public void getServiceAssetMetadataSuccess() throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.SERVICES, service.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ServiceDetailedAssetStructure serviceAssetMetadata = AssetRestUtils.getServiceAssetMetadata(assetResponse); + AssetRestUtils.serviceMetadataValidatior(serviceAssetMetadata, service, AssetTypeEnum.SERVICES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.SERVICES, service); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + } + + @Test // (enabled = false) + public void getServiceAssetMetadataWithResourceInstancesSuccess() throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF, service, UserRoleEnum.DESIGNER, true); + service = ResponseParser.parseToObjectUsingMapper(ServiceRestUtils.getService(service.getUniqueId(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)).getResponse(),Service.class); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.SERVICES, service.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ServiceDetailedAssetStructure serviceAssetMetadata = AssetRestUtils.getServiceAssetMetadata(assetResponse); + AssetRestUtils.serviceMetadataValidatior(serviceAssetMetadata, service, AssetTypeEnum.SERVICES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.SERVICES, service); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + + } + + @Test // (enabled = false) + public void getServiceAssetMetadataWithNonCertifiedResourceInstancesWithArtifactsSuccess() throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.VENDOR_LICENSE, resourceVF, UserRoleEnum.DESIGNER, true, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + Resource resourceVF2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.APPC_CONFIG, resourceVF2, UserRoleEnum.DESIGNER, true, true); + resourceVF2 = (Resource) AtomicOperationUtils.changeComponentState(resourceVF2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKIN, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF, service, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF2, service, UserRoleEnum.DESIGNER, true); + resourceVF = (Resource) AtomicOperationUtils + .changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF, service, UserRoleEnum.DESIGNER, true); + + // service with 0.1, 0.1 and 1.0 RIs versions + service = ResponseParser.parseToObjectUsingMapper(ServiceRestUtils.getService(service.getUniqueId(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)).getResponse(), Service.class); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.SERVICES, service.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ServiceDetailedAssetStructure serviceAssetMetadata = AssetRestUtils.getServiceAssetMetadata(assetResponse); + AssetRestUtils.serviceMetadataValidatior(serviceAssetMetadata, service, AssetTypeEnum.SERVICES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.SERVICES, service); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + + } + + @Test // (enabled = false) + public void getServiceAssetMetadataWithCertifiedResourceInstancesAndArtifactsOnRIsAndServiceSuccess() + throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.VENDOR_LICENSE, resourceVF, UserRoleEnum.DESIGNER, true, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + Resource resourceVF2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.APPC_CONFIG, resourceVF2, UserRoleEnum.DESIGNER, true, true); + resourceVF2 = (Resource) AtomicOperationUtils.changeComponentState(resourceVF2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF, service, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF2, service, UserRoleEnum.DESIGNER, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.MODEL_INVENTORY_PROFILE, resourceVF, UserRoleEnum.DESIGNER, true, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF, service, UserRoleEnum.DESIGNER, true); + + // service with resourceVF 1.0(1 art), 2.0(2 art) versions and + // resourceVF2 1.0(1 art), service 1 artifact version + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.MODEL_INVENTORY_PROFILE, service, UserRoleEnum.DESIGNER, true, true); + service = ResponseParser.parseToObjectUsingMapper(ServiceRestUtils.getService(service.getUniqueId(), ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER)).getResponse(), Service.class); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.SERVICES, service.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ServiceDetailedAssetStructure serviceAssetMetadata = AssetRestUtils.getServiceAssetMetadata(assetResponse); + AssetRestUtils.serviceMetadataValidatior(serviceAssetMetadata, service, AssetTypeEnum.SERVICES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.SERVICES, service); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + + } + + @Test // (enabled = false) + public void getServiceAssetMetadataWithResourceInstancesServiceInSubmitForTestingSuccess() throws Exception { + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + + Resource resourceVF = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.VENDOR_LICENSE, resourceVF, UserRoleEnum.DESIGNER, true, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + Resource resourceVF2 = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.APPC_CONFIG, resourceVF2, UserRoleEnum.DESIGNER, true, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF2, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF, service, UserRoleEnum.DESIGNER, true); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF2, service, UserRoleEnum.DESIGNER, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CHECKOUT, true).getLeft(); + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.MODEL_INVENTORY_PROFILE, resourceVF, UserRoleEnum.DESIGNER, true, true); + resourceVF = (Resource) AtomicOperationUtils.changeComponentState(resourceVF, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + AtomicOperationUtils.addComponentInstanceToComponentContainer(resourceVF, service, UserRoleEnum.DESIGNER, true); + + // service with resourceVF 1.0(1 art), 2.0(2 art) versions and + // resourceVF2 1.0(1 art), service 1 artifact version + AtomicOperationUtils.uploadArtifactByType(ArtifactTypeEnum.MODEL_INVENTORY_PROFILE, service, UserRoleEnum.DESIGNER, true, true); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.SERVICES, service.getUUID()); + BaseRestUtils.checkSuccess(assetResponse); + + ServiceDetailedAssetStructure serviceAssetMetadata = AssetRestUtils.getServiceAssetMetadata(assetResponse); + AssetRestUtils.serviceMetadataValidatior(serviceAssetMetadata, service, AssetTypeEnum.SERVICES); + + // Validate audit message + ExpectedExternalAudit expectedAssetListAudit = ElementFactory.getDefaultAssetMetadataAudit(AssetTypeEnum.SERVICES, service); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedAssetListAudit.getRESOURCE_URL()); + AuditValidationUtils.validateExternalAudit(expectedAssetListAudit, AuditingActionEnum.GET_ASSET_METADATA.getName(), body); + } + + @Test // (enabled = false) + public void getServiceAssetMetadataServiceNotFound() throws Exception { + + String serviceUuid = "notExistingServiceUuid"; + RestResponse assetResponse = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.SERVICES, serviceUuid); + + // Validate audit message + ArrayList variables = new ArrayList<>(); + variables.add(serviceUuid); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.SERVICE_NOT_FOUND.name(), variables, assetResponse.getResponse()); + } + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/SearchFilterCategoryExternalAPI.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/SearchFilterCategoryExternalAPI.java new file mode 100644 index 0000000000..ca7c5aefb9 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/SearchFilterCategoryExternalAPI.java @@ -0,0 +1,329 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.json.simple.parser.JSONParser; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.SearchCriteriaEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedExternalAudit; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +public class SearchFilterCategoryExternalAPI extends ComponentBaseTest { + + private static Logger log = LoggerFactory.getLogger(CRUDExternalAPI.class.getName()); + + protected Config config = Config.instance(); + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json"; + + protected Gson gson = new Gson(); + protected JSONParser jsonParser = new JSONParser(); + +// @BeforeMethod +// public void init() throws Exception{ +// AtomicOperationUtils.createDefaultConsumer(true); +// } + + ; + @Rule + public static TestName name = new TestName(); + + public SearchFilterCategoryExternalAPI() { + super(name, SearchFilterCategoryExternalAPI.class.getName()); + + } + + // Search for invalid resourceType + @Test + public void searchWithInvalidFilter() throws Exception { + RestResponse restResponse = ResourceRestUtils.getResourceListFilterByCriteria(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), AssetTypeEnum.RESOURCES.getValue(), SearchCriteriaEnum.RESOURCE_TYPE.getValue() + "invalid", ResourceTypeEnum.VFC.toString()); + + Integer expectedResponseCode = 400; + Assert.assertEquals(restResponse.getErrorCode(), expectedResponseCode); + + List variables = Arrays.asList("resourceTypeinvalid", "[resourceType, subCategory, category]"); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_FILTER_KEY.name(), variables, restResponse.getResponse()); + + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalAuditObject(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST, "?" + SearchCriteriaEnum.RESOURCE_TYPE.getValue() + "invalid=" + ResourceTypeEnum.VFC.toString()); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_FILTER_KEY.name()); + expectedExternalAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + expectedExternalAudit.setSTATUS("400"); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedExternalAudit.getRESOURCE_URL()); + AuditValidationUtils.validateAuditExternalSearchAPI(expectedExternalAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + @DataProvider(name="searchForResourceTypeNegativeTest", parallel=true) + public static Object[][] dataProviderSearchForResourceTypeNegativeTest() { + return new Object[][] { + {"invalidResourceType"}, + {""} + }; + } + + // Search for invalid resourceType + @Test(dataProvider="searchForResourceTypeNegativeTest") + public void searchForResourceTypeNegativeTest(String resourceType) throws Exception { + RestResponse restResponse = ResourceRestUtils.getResourceListFilterByCriteria(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), AssetTypeEnum.RESOURCES.getValue(), SearchCriteriaEnum.RESOURCE_TYPE.getValue(), resourceType); + + Integer expectedResponseCode = 400; + Assert.assertEquals(restResponse.getErrorCode(), expectedResponseCode); + + List variables = Arrays.asList(); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.INVALID_CONTENT.name(), variables, restResponse.getResponse()); + + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalAuditObject(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST, "?" + SearchCriteriaEnum.RESOURCE_TYPE.getValue() + "=" + resourceType); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_CONTENT.name()); + expectedExternalAudit.setDESC(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + expectedExternalAudit.setSTATUS("400"); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedExternalAudit.getRESOURCE_URL()); + AuditValidationUtils.validateAuditExternalSearchAPI(expectedExternalAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + + // Searching for resource filter incorrect resource type using external API + @Test + public void searchingForResouceFilterIncorrectResouceTypeUsingExternalAPI() throws Exception { + Resource resource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_DATABASE, UserRoleEnum.DESIGNER, true).left().value(); + List createdResoucesName = new ArrayList(); + createdResoucesName.add(resource.getName()); + + for(ResourceTypeEnum resourceTypeEnum: ResourceTypeEnum.values()) { + // Create resource for each type so it will not return 404 + AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(resourceTypeEnum, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_DATABASE, UserRoleEnum.DESIGNER, true).left().value(); + + RestResponse restResponse = ResourceRestUtils.getResourceListFilterByCriteria(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), AssetTypeEnum.RESOURCES.getValue(), SearchCriteriaEnum.RESOURCE_TYPE.getValue(), resourceTypeEnum.toString()); + + Integer expectedResponseCode = 200; + Assert.assertEquals(restResponse.getErrorCode(), expectedResponseCode); + if(resourceTypeEnum == ResourceTypeEnum.VF) { + validateJsonContainResource(restResponse.getResponse(), createdResoucesName, true); + } else { + validateJsonContainResource(restResponse.getResponse(), createdResoucesName, false); + } + + + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalAuditObject(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST, "?" + SearchCriteriaEnum.RESOURCE_TYPE.getValue() + "=" + resourceTypeEnum.toString()); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedExternalAudit.getRESOURCE_URL()); + AuditValidationUtils.validateAuditExternalSearchAPI(expectedExternalAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + } + + // Searching for several resource types using external API + @Test + public void searchingForSeveralResouceTypesUsingExternalAPI() throws Exception { + performClean(); + for(ResourceTypeEnum resourceTypeEnum: ResourceTypeEnum.values()) { + List createdResoucesName = new ArrayList(); + Resource resource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(resourceTypeEnum, NormativeTypesEnum.ROOT, ResourceCategoryEnum.GENERIC_DATABASE, UserRoleEnum.DESIGNER, true).left().value(); + createdResoucesName.add(resource.getName()); + + RestResponse restResponse = ResourceRestUtils.getResourceListFilterByCriteria(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), AssetTypeEnum.RESOURCES.getValue(), SearchCriteriaEnum.RESOURCE_TYPE.getValue(), resourceTypeEnum.toString()); + + Integer expectedResponseCode = 200; + Assert.assertEquals(restResponse.getErrorCode(), expectedResponseCode); + validateJsonContainResource(restResponse.getResponse(), createdResoucesName, true); + + ExpectedExternalAudit expectedExternalAudit = ElementFactory.getDefaultExternalAuditObject(AssetTypeEnum.RESOURCES, AuditingActionEnum.GET_FILTERED_ASSET_LIST, "?" + SearchCriteriaEnum.RESOURCE_TYPE.getValue() + "=" + resourceTypeEnum.toString()); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_URL, expectedExternalAudit.getRESOURCE_URL()); + AuditValidationUtils.validateAuditExternalSearchAPI(expectedExternalAudit, AuditingActionEnum.GET_FILTERED_ASSET_LIST.getName(), body); + } + } + + // Searching for several resources of type VFCMT using external API + @Test + public void searchingForSeveralResourcesOfTypeVFCMTUsingExternalAPI() throws Exception { + performClean(); + Random random = new Random(); + int numberOfResouceToCreate = random.nextInt(5) + 1; + List createdResoucesName = new ArrayList(); + + for(int i=0; i createdResoucesName = new ArrayList(); + createdResoucesName.add(resource.getName()); + + restResponse = ResourceRestUtils.getResourceListFilterByCategory(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), AssetTypeEnum.RESOURCES.getValue(), resourceCategoryEnum.getCategory()); + + Integer expectedResponseCode = 200; + Assert.assertEquals(restResponse.getErrorCode(), expectedResponseCode); + validateJsonContainResource(restResponse.getResponse(), createdResoucesName, true); + } + + // Verify search filter by sub-category + @Test + public void validateFilterBySubcategory() throws Exception { + ResourceCategoryEnum resourceCategoryEnum = getRandomCategoryFromResourceCategoryEnum(); + + Resource resource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, resourceCategoryEnum, UserRoleEnum.DESIGNER, true).left().value(); + List createdResoucesName = new ArrayList(); + createdResoucesName.add(resource.getName()); + + RestResponse restResponse = ResourceRestUtils.getResourceListFilterBySubCategory(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), AssetTypeEnum.RESOURCES.getValue(), resourceCategoryEnum.getSubCategory()); + + Integer expectedResponseCode = 200; + Assert.assertEquals(restResponse.getErrorCode(), expectedResponseCode); + validateJsonContainResource(restResponse.getResponse(), createdResoucesName, true); + } + + + protected ResourceCategoryEnum getRandomCategoryFromResourceCategoryEnum() throws Exception { + Random random = new Random(); + int randint = random.nextInt(ResourceCategoryEnum.values().length); + int i = 0; + for(ResourceCategoryEnum resourceTypeEnum: ResourceCategoryEnum.values()) { + if(randint == i) { + return resourceTypeEnum; + } + i++; + } + return null; + } + + protected CategoryDefinition getRandomCategory() throws Exception { + Random random = new Random(); + + RestResponse restResponse = CategoryRestUtils.getAllCategories(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), "resources"); + Gson gson = new Gson(); + JsonElement jelement = new JsonParser().parse(restResponse.getResponse()); + JsonArray jsonArray = jelement.getAsJsonArray(); + + CategoryDefinition categoryDefinition = gson.fromJson(jsonArray.get(random.nextInt(jsonArray.size())), CategoryDefinition.class); + + return categoryDefinition; + } + + protected void validateJsonContainResource(String json, List resourceNameList, Boolean willBeFound) { + int lenResourceNameList = resourceNameList.size(); + Gson gson = new Gson(); + JsonElement jsonElement = new JsonParser().parse(json); + JsonArray jsonArray = jsonElement.getAsJsonArray(); + for(JsonElement jElement: jsonArray) { + ResourceReqDetails jResource = gson.fromJson(jElement, ResourceReqDetails.class); + + if(resourceNameList.contains(jResource.getName())) { + resourceNameList.remove(jResource.getName()); + } + } + + if(resourceNameList.size() != 0 && willBeFound) { + Assert.assertTrue(false, "Created resource not found on search filtered by category."); + } else if (lenResourceNameList != resourceNameList.size() & !willBeFound) { + Assert.assertTrue(false, "Some of the resources found when expect that no resource will be found."); + } + } + + + + protected void validateJsonContainResourceCategory(String json, ResourceCategoryEnum resourceCategoryEnum) { + Gson gson = new Gson(); + JsonElement jelement = new JsonParser().parse(json); + JsonArray jsonArray = jelement.getAsJsonArray(); + for(JsonElement jsonElement : jsonArray){ + CategoryDefinition categoryDefinition = gson.fromJson(jsonElement, CategoryDefinition.class); + + if(categoryDefinition.getName().equals(resourceCategoryEnum.getCategory())) { + for(SubCategoryDefinition subcategory: categoryDefinition.getSubcategories()) { + if(subcategory.getName().equals(resourceCategoryEnum.getSubCategory())) { + return; + } + } + } + + } + + Assert.assertTrue(false, "Category and subcategory not found in categories list."); + } + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/UserAPIs.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/UserAPIs.java new file mode 100644 index 0000000000..ceafe204c8 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/UserAPIs.java @@ -0,0 +1,556 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.portalsdk.core.restful.domain.EcompRole; +import org.openecomp.portalsdk.core.restful.domain.EcompUser; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.BaseRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.EcompUserRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.UserRestUtils; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +public class UserAPIs extends ComponentBaseTest { + + @Rule + public static TestName name = new TestName(); + + public UserAPIs() { + super(name, UserAPIs.class.getName()); + } + + public User adminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + + @Test + public void createUserAllPosibleRolesThenDeactivate() throws Exception { + + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + + List allRoles = getAllRoles(); + + for (EcompRole ecompRole2 : allRoles) { + try { + + ///get list of users + List allusersList = getAllusersList(); + int sizeBeforeChange = allusersList.size(); + + //create user + ecompUser.setLoginId(getUser()); + ecompRole.setId((long) ecompRole2.getId()); + ecompRole.setName(ecompRole2.getName()); + System.out.println(ecompRole2.getName()); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + + ///get list of users verify list size changed + allusersList = getAllusersList(); + int sizeAfterChange = allusersList.size(); + + Assert.assertEquals(sizeBeforeChange + 1, sizeAfterChange, "Expected that list will change."); + sizeBeforeChange = sizeAfterChange; + pushUser = EcompUserRestUtils.pushUser(ecompUser); + + //deactivate user + ecompRole = new EcompRole();; + List list= new ArrayList(); + list.add(ecompRole); + + RestResponse deactivateUserResponse = EcompUserRestUtils.pushUserRoles(ecompUser.getLoginId(), list); + BaseRestUtils.checkSuccess(deactivateUserResponse); + + ///get list of users verify list size changed + allusersList = getAllusersList(); + sizeAfterChange = allusersList.size(); + Assert.assertEquals(sizeBeforeChange, sizeAfterChange + 1, "Expected that list will change."); + + } finally { + deleteUser(ecompUser.getLoginId()); + } + + } + + } + + @Test + public void createSameUserTwiceTest() throws Exception { + + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + try { + + ///get list of users + List allusersList = getAllusersList(); + int sizeBeforeChange = allusersList.size(); + + //create user + ecompUser.setLoginId(getUser()); + ecompRole.setId((long) 1); + ecompRole.setName("TESTER"); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + + ///get list of users verify list size changed + allusersList = getAllusersList(); + int sizeAfterChange = allusersList.size(); + + assertTrue("List is Equel" , sizeBeforeChange != sizeAfterChange ); + pushUser = EcompUserRestUtils.pushUser(ecompUser); + + } finally { + deleteUser(ecompUser.getLoginId()); + } + + } + + @Test + public void createSameUserTwiceDiffrentDataTest() throws Exception { + + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + try { + ///get list of users + List allusersList = getAllusersList(); + int sizeBeforeChange = allusersList.size(); + + //create user + ecompUser.setLoginId(getUser()); + ecompRole.setId((long) 1); + ecompRole.setName("TESTER"); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + + ///get list of users verify list size changed + allusersList = getAllusersList(); + int sizeAfterChange = allusersList.size(); + + assertTrue("List is Equel" , sizeBeforeChange != sizeAfterChange ); + + //update role + ecompRole.setId((long) 2); + ecompRole.setName("DESIGNER"); + setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + + pushUser = EcompUserRestUtils.pushUser(ecompUser); + + } finally { + deleteUser(ecompUser.getLoginId()); + } + + } + + @Test + public void updateUserRoleTest() throws Exception { + + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + try { + //create user + ecompUser.setLoginId(getUser()); + ecompRole.setId((long) 1); + ecompRole.setName("TESTER"); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + + List userRolesBefore = getUserRoles(ecompUser); + + //update role + ecompRole = new EcompRole(); + ecompRole.setId((long) 2); + ecompRole.setName("DESIGNER"); + List list= new ArrayList(); + list.add(ecompRole); + + EcompUserRestUtils.pushUserRoles(ecompUser.getLoginId(), list); + + List userRolesAfter = getUserRoles(ecompUser); + + assertFalse("role wasn't changed", userRolesBefore.equals(userRolesAfter)); + } finally { + deleteUser(ecompUser.getLoginId()); + } + + } + + @Test + public void addUserCreateResource() throws Exception { + + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + Resource resource = new Resource(); + + try { + //create user + ecompUser.setLoginId(getUser()); + ecompRole.setId((long) 2); + ecompRole.setName("DESIGNER"); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + + UserRoleEnum.DESIGNER.setUserId(ecompUser.getLoginId()); + resource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + + } finally { + ResourceRestUtils.deleteResource(resource.getUniqueId(), adminUser.getUserId()); + deleteUser(ecompUser.getLoginId()); + } + + } + + // First try update to Tester and verify it not success + // Then try to deactivate and verify it not success + @Test + public void changeUserRoleWithCheckOutResourceThenDeactivate() throws Exception { + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + Resource resource = new Resource(); + try { + //create user + ecompUser.setLoginId(getUser()); + ecompRole.setId((long) 2); + ecompRole.setName("DESIGNER"); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + + UserRoleEnum.DESIGNER.setUserId(ecompUser.getLoginId()); + resource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + + int sizeBeforeChange = getAllusersList().size(); + + //update role + ecompRole = new EcompRole(); + ecompRole.setId((long) 1); + ecompRole.setName("TESTER"); + List list= new ArrayList(); + list.add(ecompRole); + + RestResponse pushUserRoles = EcompUserRestUtils.pushUserRoles(ecompUser.getLoginId(), list); + Assert.assertEquals(pushUserRoles.getErrorCode(), (Integer)BaseRestUtils.STATUS_CODE_UNSUPPORTED_ERROR, "Not correct response code"); + + //deactivate user + ecompRole = new EcompRole();; + list= new ArrayList(); + list.add(ecompRole); + + RestResponse deactivateUserResponse = EcompUserRestUtils.pushUserRoles(ecompUser.getLoginId(), list); + Assert.assertEquals(deactivateUserResponse.getErrorCode(), (Integer)BaseRestUtils.STATUS_CODE_UNSUPPORTED_ERROR, "Not correct response code"); + + ///get list of users verify list size changed + int sizeAfterChange = getAllusersList().size(); + Assert.assertEquals(sizeBeforeChange, sizeAfterChange, "Expected that list will not change."); + + } finally { + ResourceRestUtils.deleteResource(resource.getUniqueId(), adminUser.getUserId()); + deleteUser(ecompUser.getLoginId()); + } + } + + @Test + public void deactivateUserRoleWithStartTestingResource() throws Exception { + + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + Resource resource= new Resource(); + + try { + //create user + ecompUser.setLoginId(getUser()); + ecompRole.setId((long) 2); + ecompRole.setName("DESIGNER"); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + int sizeBeforeChange = getAllusersList().size(); + UserRoleEnum.DESIGNER.setUserId(ecompUser.getLoginId()); + + resource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFICATIONREQUEST, true); + + + //update role + ecompRole = new EcompRole(); + ecompRole.setId((long) 1); + ecompRole.setName("TESTER"); + List list= new ArrayList(); + list.add(ecompRole); + + RestResponse pushUserRoles = EcompUserRestUtils.pushUserRoles(ecompUser.getLoginId(), list); + BaseRestUtils.checkSuccess(pushUserRoles); + + UserRoleEnum.TESTER.setUserId(ecompUser.getLoginId()); + AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.TESTER, LifeCycleStatesEnum.STARTCERTIFICATION, true); + + //deactivate user + ecompRole = new EcompRole();; + list= new ArrayList(); + list.add(ecompRole); + + RestResponse deactivateUserResponse = EcompUserRestUtils.pushUserRoles(ecompUser.getLoginId(), list); + Assert.assertEquals(deactivateUserResponse.getErrorCode(), (Integer)BaseRestUtils.STATUS_CODE_UNSUPPORTED_ERROR, "Not correct response code"); + + ///get list of users verify list size changed + int sizeAfterChange = getAllusersList().size(); + Assert.assertEquals(sizeBeforeChange, sizeAfterChange, "Expected that list will not change."); + + } finally { + ResourceRestUtils.deleteResource(resource.getUniqueId(), adminUser.getUserId()); + deleteUser(ecompUser.getLoginId()); + } + } + + @Test + public void changeUserRoleWithStartTestingResource() throws Exception { + + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + Resource resource= new Resource(); + + try { + //create user + ecompUser.setLoginId(getUser()); + ecompRole.setId((long) 2); + ecompRole.setName("DESIGNER"); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + + UserRoleEnum.DESIGNER.setUserId(ecompUser.getLoginId()); + + resource = AtomicOperationUtils.createResourceByType(ResourceTypeEnum.VF, UserRoleEnum.DESIGNER, true).left().value(); + AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.STARTCERTIFICATION, true); + + + //update role + ecompRole = new EcompRole(); + ecompRole.setId((long) 1); + ecompRole.setName("TESTER"); + List list= new ArrayList(); + list.add(ecompRole); + + RestResponse pushUserRoles = EcompUserRestUtils.pushUserRoles(ecompUser.getLoginId(), list); + BaseRestUtils.checkSuccess(pushUserRoles); + + } finally { + ResourceRestUtils.deleteResource(resource.getUniqueId(), adminUser.getUserId()); + deleteUser(ecompUser.getLoginId()); + } + } + + @Test + public void fillAllEcompFields() throws Exception { + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + try { + + ///get list of users + List allusersList = getAllusersList(); + int sizeBeforeChange = allusersList.size(); + + //create user + ecompUser.setLoginId(getUser()); + ecompUser.setOrgId((long) 123); + ecompUser.setManagerId("ci4321"); + ecompUser.setFirstName("firstName"); + ecompUser.setMiddleInitial("middleInitial"); + ecompUser.setLastName("lastName"); + ecompUser.setPhone("phone"); + ecompUser.setEmail("email@email.com"); + ecompUser.setHrid("hrid"); + ecompUser.setOrgUserId("orgUserId"); + ecompUser.setOrgCode("orgCode"); + ecompUser.setOrgManagerUserId("ci1234"); + ecompUser.setJobTitle("jobTitle"); + ecompUser.setActive(true); + + + ecompRole.setId((long) 1); + ecompRole.setName("TESTER"); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + + ///get list of users verify list size changed + allusersList = getAllusersList(); + int sizeAfterChange = allusersList.size(); + + assertTrue("List is Equel" , sizeBeforeChange != sizeAfterChange ); + + } finally { + + deleteUser(ecompUser.getLoginId()); + } + } + + @Test + public void missingMandatoryFieldRole() throws Exception { + + EcompUser ecompUser = new EcompUser(); + try { + ///get list of users + List allusersList = getAllusersList(); + int sizeBeforeChange = allusersList.size(); + + //create user + ecompUser.setLoginId(getUser()); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + BaseRestUtils.checkSuccess(pushUser); + + ///get list of users verify list size changed + allusersList = getAllusersList(); + int sizeAfterChange = allusersList.size(); + + assertTrue("List is Equel" , sizeBeforeChange != sizeAfterChange ); + + } finally { + deleteUser(ecompUser.getLoginId()); + } + } + + @Test + public void missingMandatoryFieldATTid() throws Exception { + + EcompUser ecompUser = new EcompUser(); + EcompRole ecompRole = new EcompRole(); + try { + + //create user + ecompUser.setLoginId(""); + ecompRole.setId((long) 1); + ecompRole.setName("TESTER"); + Set setRoles = new HashSet(); + setRoles.add(ecompRole); + ecompUser.setRoles(setRoles); + RestResponse pushUser = EcompUserRestUtils.pushUser(ecompUser); + assertTrue("wrong response code :" , pushUser.getErrorCode() == BaseRestUtils.STATUS_CODE_INVALID_CONTENT); + + } finally { + deleteUser(ecompUser.getLoginId()); + } + + + } + + private List getUserRoles(EcompUser ecompUser) throws IOException { + RestResponse userRoles = EcompUserRestUtils.getUserRoles(ecompUser.getLoginId()); + Type listType = new TypeToken>() {}.getType(); + List roleList = new Gson().fromJson(userRoles.getResponse(), listType); + return roleList; + } + + private void deleteUser(String userId) throws IOException { + User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + defaultUser.setUserId(userId); + + UserRestUtils.deleteUser(defaultUser, adminUser, true); + } + + private List getAllusersList() throws IOException { + RestResponse allUsers = EcompUserRestUtils.getAllUsers(); + + Type listType = new TypeToken>() {}.getType(); + List usersList = new Gson().fromJson(allUsers.getResponse(), listType); + + return usersList; + } + + private List getAllRoles() throws IOException { + RestResponse allRoles = EcompUserRestUtils.getAllAvailableRoles(); + + Type listType = new TypeToken>() {}.getType(); + List availableRoles = new Gson().fromJson(allRoles.getResponse(), listType); + + return availableRoles; + } + + private String getUser() { + int nextInt = rnd.nextInt(8999) + 1000; +// String returnMe = "ci"+ new BigInteger(getRandomNumber(4)); + String returnMe = "ci"+ nextInt; + System.out.println(returnMe); + + + return returnMe; + } + + private static Random rnd = new Random(); + + public static String getRandomNumber(int digCount) { + StringBuilder sb = new StringBuilder(digCount); + for(int i=1; i <= digCount; i++){ + sb.append((char)('0' + rnd.nextInt(10))); + } + return sb.toString(); + } +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/VFCMTExternalAPI.java b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/VFCMTExternalAPI.java new file mode 100644 index 0000000000..f93958542d --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/externalApis/VFCMTExternalAPI.java @@ -0,0 +1,396 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.externalApis; + +import static java.util.Arrays.asList; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.json.simple.parser.JSONParser; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.AssetTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ResourceAssetStructure; +import org.openecomp.sdc.ci.tests.datatypes.ResourceExternalReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.SearchCriteriaEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.AssetRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtilsExternalAPI; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.datastructure.AuditingFieldsKeysEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; + +public class VFCMTExternalAPI extends ComponentBaseTest { + + private static Logger log = LoggerFactory.getLogger(CRUDExternalAPI.class.getName()); + protected static final String UPLOAD_ARTIFACT_PAYLOAD = "UHVUVFktVXNlci1LZXktRmlsZS0yOiBzc2gtcnNhDQpFbmNyeXB0aW9uOiBhZXMyNTYtY2JjDQpDb21tZW5wOA0K"; + protected static final String UPLOAD_ARTIFACT_NAME = "TLV_prv.ppk"; + + protected Config config = Config.instance(); + protected String contentTypeHeaderData = "application/json"; + protected String acceptHeaderDate = "application/json"; + + + + protected Gson gson = new Gson(); + protected JSONParser jsonParser = new JSONParser(); + + + protected String serviceVersion; + protected ResourceReqDetails resourceDetails; + protected User sdncUserDetails; + protected ServiceReqDetails serviceDetails; + + +// @BeforeMethod +// public synchronized void init() throws Exception{ +// AtomicOperationUtils.createDefaultConsumer(true); +// } + + + @Rule + public static TestName name = new TestName(); + + public VFCMTExternalAPI() { + super(name, VFCMTExternalAPI.class.getName()); + + } + + // Create VFCMT - validate response + search external api + retrieve metadata via external api - success flow + @Test + public void createVfcmt() throws Exception { + User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ResourceExternalReqDetails defaultResource = ElementFactory.getDefaultResourceByType("ci", ResourceCategoryEnum.TEMPLATE_MONITORING_TEMPLATE, defaultUser.getUserId(), ResourceTypeEnum.VFCMT.toString()); + + RestResponse restResponse = ResourceRestUtilsExternalAPI.createResource(defaultResource, defaultUser); + ResourceAssetStructure parsedCreatedResponse = gson.fromJson(restResponse.getResponse(), ResourceAssetStructure.class); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CREATE_RESOURCE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, parsedCreatedResponse.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultCreateResourceExternalAPI(parsedCreatedResponse.getName()); + AuditValidationUtils.validateAuditExternalCreateResource(expectedResourceAuditJavaObject, action.getName(), body); + + // search for vfcmt via external api - validate created resource exist + RestResponse searchResult = ResourceRestUtils.getResourceListFilterByCriteria(ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), AssetTypeEnum.RESOURCES.getValue(), SearchCriteriaEnum.RESOURCE_TYPE.getValue(), ResourceTypeEnum.VFCMT.toString()); + JsonArray listSearchResult = gson.fromJson(searchResult.getResponse(), JsonArray.class); + boolean found = false; + for(JsonElement result: listSearchResult) { + ResourceAssetStructure parsedResult = gson.fromJson(result, ResourceAssetStructure.class); + if(parsedResult.getName().equals(defaultResource.getName())) { + found = true; + } + } + Assert.assertEquals(found, true); + + // get created vfcmt metadata via external api - validate data + RestResponse resourceMetadata = AssetRestUtils.getAssetMetadataByAssetTypeAndUuid(true, AssetTypeEnum.RESOURCES, parsedCreatedResponse.getUuid()); + ResourceAssetStructure parsedMetadata = gson.fromJson(resourceMetadata.getResponse(), ResourceAssetStructure.class); + + Assert.assertEquals(parsedCreatedResponse.getUuid(), parsedMetadata.getUuid()); + Assert.assertEquals(parsedCreatedResponse.getInvariantUUID(), parsedMetadata.getInvariantUUID()); + Assert.assertEquals(parsedCreatedResponse.getName(), parsedMetadata.getName()); + Assert.assertEquals(parsedCreatedResponse.getVersion(), parsedMetadata.getVersion()); + Assert.assertEquals(parsedCreatedResponse.getCategory(), parsedMetadata.getCategory()); + Assert.assertEquals(parsedCreatedResponse.getSubCategory(), parsedMetadata.getSubCategory()); + Assert.assertEquals(parsedCreatedResponse.getResourceType(), parsedMetadata.getResourceType()); + Assert.assertEquals(parsedCreatedResponse.getLifecycleState(), parsedMetadata.getLifecycleState()); + Assert.assertEquals(parsedCreatedResponse.getLastUpdaterUserId(), parsedMetadata.getLastUpdaterUserId()); + Assert.assertEquals(parsedCreatedResponse.getLastUpdaterFullName(), parsedMetadata.getLastUpdaterFullName()); + Assert.assertEquals(parsedCreatedResponse.getToscaResourceName(), parsedMetadata.getToscaResourceName()); + } + + + + // Create two VFCMT with same name - validate error + audit - failure flow + @Test + public void createTwoVfcmtWithSameName() throws Exception { + User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ResourceExternalReqDetails defaultResource = ElementFactory.getDefaultResourceByType("ci", ResourceCategoryEnum.TEMPLATE_MONITORING_TEMPLATE, defaultUser.getUserId(), ResourceTypeEnum.VFCMT.toString()); + + // create vfcmt + RestResponse firstTryToCreate = ResourceRestUtilsExternalAPI.createResource(defaultResource, defaultUser); + ResourceAssetStructure parsedCreatedResponse = gson.fromJson(firstTryToCreate.getResponse(), ResourceAssetStructure.class); + + // auditing verification + AuditingActionEnum action = AuditingActionEnum.CREATE_RESOURCE_BY_API; + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, parsedCreatedResponse.getName()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultCreateResourceExternalAPI(parsedCreatedResponse.getName()); + AuditValidationUtils.validateAuditExternalCreateResource(expectedResourceAuditJavaObject, action.getName(), body); + + // try to create another vfcmt wit same name + RestResponse secondTryToCreate = ResourceRestUtilsExternalAPI.createResource(defaultResource, defaultUser); + Assert.assertEquals((int)secondTryToCreate.getErrorCode(), 409); + + body.put(AuditingFieldsKeysEnum.AUDIT_STATUS, "409"); + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_NAME_ALREADY_EXIST.name()); + List variables = asList(ComponentTypeEnum.RESOURCE.getValue(), defaultResource.getName()); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + expectedResourceAuditJavaObject.setStatus("409"); + AuditValidationUtils.validateAuditExternalCreateResource(expectedResourceAuditJavaObject, action.getName(), body); + } + + + + @DataProvider(name="createVfcmtVariousFailureFlows", parallel=true) + public static Object[][] dataProviderCreateVfcmtVariousFailureFlows() { + return new Object[][] { + {"name_missing"}, + {"name_to_long"}, + {"name_with_invalid_char"}, + {"description_missing"}, + {"description_to_long"}, + {"description_with_invalid_char"}, + {"resource_type_missing"}, + {"resource_type_invalid"}, + {"category_type_missing"}, + {"category_type_invalid"}, + {"subcategory_type_missing"}, + {"subcategory_type_invalid"}, + {"vendor_name_missing"}, + {"vendor_name_to_long"}, + {"vendor_name_with_invalid_char"}, + {"vendor_release_missing"}, + {"vendor_release_to_long"}, + {"vendor_release_with_invalid_char"}, + {"tags_missing"}, + {"tags_to_long"}, + {"tags_invalid"}, + {"icon_missing"}, + {"user_contact_missing"}, + {"user_contact_invalid"}, + }; + } + + // Various failure flows + @Test(dataProvider="createVfcmtVariousFailureFlows") + public void createVfcmtVariousFailureFlows(String flow) throws Exception { + + if(flow.equals("resource_type_missing") || flow.equals("resource_type_invalid")) { + throw new SkipException("TC require repairs"); + } + + User defaultUser = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + ResourceExternalReqDetails defaultResource = ElementFactory.getDefaultResourceByType("ci", ResourceCategoryEnum.TEMPLATE_MONITORING_TEMPLATE, defaultUser.getUserId(), ResourceTypeEnum.VFCMT.toString()); + + ErrorInfo errorInfo = null; + List variables = null; + AuditingActionEnum action = AuditingActionEnum.CREATE_RESOURCE_BY_API; + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = ElementFactory.getDefaultCreateResourceExternalAPI(defaultResource.getName()); + Map body = new HashMap<>(); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, defaultResource.getName()); + + switch (flow) { + case "name_missing": + defaultResource.setName(""); + List resourceTags = defaultResource.getTags(); + resourceTags.add(""); + defaultResource.setTags(resourceTags); + expectedResourceAuditJavaObject.setResourceName(""); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_COMPONENT_NAME.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, ""); + break; + case "name_to_long": + defaultResource.setName("asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1"); + expectedResourceAuditJavaObject.setResourceName("asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_NAME_EXCEEDS_LIMIT.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue(), "1024"); + + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, "asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1"); + break; + case "name_with_invalid_char": + defaultResource.setName("!@#$%^&*("); + expectedResourceAuditJavaObject.setResourceName("!@#$%^&*("); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_COMPONENT_NAME.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + body.put(AuditingFieldsKeysEnum.AUDIT_RESOURCE_NAME, "!@#$%^&*("); + break; + case "description_missing": + defaultResource.setDescription(""); + expectedResourceAuditJavaObject.setDesc(""); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "description_to_long": + defaultResource.setDescription("asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1"); + expectedResourceAuditJavaObject.setDesc("asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1asdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjklasdfghjk1"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_DESCRIPTION_EXCEEDS_LIMIT.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue(), "1024"); + break; + case "description_with_invalid_char": + defaultResource.setDescription("\uC2B5"); + expectedResourceAuditJavaObject.setDesc("t"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_INVALID_DESCRIPTION.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + // TODO: defect on the flow - need to get error instead create VFC + case "resource_type_missing": + defaultResource.setResourceType(""); + expectedResourceAuditJavaObject.setResourceType(""); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_DESCRIPTION.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + // TODO: in audit RESOURCE_NAME is empty + case "resource_type_invalid": + defaultResource.setResourceType("invalid"); + expectedResourceAuditJavaObject.setResourceType(ComponentTypeEnum.RESOURCE.getValue()); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_CONTENT.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "category_type_missing": + defaultResource.setCategory(""); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_CATEGORY.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + // TODO: not correct response code in this flow - 500 instead 400 + case "category_type_invalid": + defaultResource.setCategory("invalid"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_INVALID_CATEGORY.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "subcategory_type_missing": + defaultResource.setSubcategory(""); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_SUBCATEGORY.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + // TODO: not correct error - it not missing it not correct + case "subcategory_type_invalid": + defaultResource.setSubcategory("invalid"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_INVALID_SUBCATEGORY.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "vendor_name_missing": + defaultResource.setVendorName(""); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_VENDOR_NAME.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "vendor_name_to_long": + defaultResource.setVendorName("asdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdff"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.VENDOR_NAME_EXCEEDS_LIMIT.name()); + variables = asList("25"); + break; + case "vendor_name_with_invalid_char": + defaultResource.setVendorName("!@#$*()&*^%$#@"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_VENDOR_NAME.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "vendor_release_missing": + defaultResource.setVendorRelease(""); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.MISSING_VENDOR_RELEASE.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "vendor_release_to_long": + defaultResource.setVendorRelease("asdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdff"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.VENDOR_RELEASE_EXCEEDS_LIMIT.name()); + variables = asList("25"); + break; + case "vendor_release_with_invalid_char": + defaultResource.setVendorRelease("!@#$*()&*^%$#@"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_VENDOR_RELEASE.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "tags_missing": + defaultResource.setTags(asList("")); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.INVALID_FIELD_FORMAT.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue(), "tag"); + break; + case "tags_to_long": + defaultResource.setTags(asList("asdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdffasdff")); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_SINGLE_TAG_EXCEED_LIMIT.name()); + variables = asList("1024"); + break; + case "tags_invalid": + defaultResource.setTags(asList("asfdg")); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_INVALID_TAGS_NO_COMP_NAME.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "icon_missing": + defaultResource.setIcon(""); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_ICON.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "user_contact_missing": + defaultResource.setContactId(""); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_MISSING_CONTACT.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + case "user_contact_invalid": + default: + defaultResource.setContactId("abcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfdabcderfffdfdfd"); + errorInfo = ErrorValidationUtils.parseErrorConfigYaml(ActionStatus.COMPONENT_INVALID_CONTACT.name()); + variables = asList(ComponentTypeEnum.RESOURCE.getValue()); + break; + } + + // create vfcmt + RestResponse restResponse = ResourceRestUtilsExternalAPI.createResource(defaultResource, defaultUser); + + expectedResourceAuditJavaObject.setStatus("400"); + expectedResourceAuditJavaObject.setDesc(AuditValidationUtils.buildAuditDescription(errorInfo, variables)); + AuditValidationUtils.validateAuditExternalCreateResource(expectedResourceAuditJavaObject, action.getName(), body); + + } + + + + + + + + + + + +} diff --git a/test-apis-ci/src/main/java/org/openecomp/sdc/post/Install.java b/test-apis-ci/src/main/java/org/openecomp/sdc/post/Install.java new file mode 100644 index 0000000000..5e9e02c479 --- /dev/null +++ b/test-apis-ci/src/main/java/org/openecomp/sdc/post/Install.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.post; + +import java.io.File; + +import org.openecomp.sdc.be.dao.DAOTitanStrategy; +import org.openecomp.sdc.be.dao.titan.TitanGraphClient; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; + +public class Install { + public static void main(String[] args) { + + if (args == null || args.length == 0) { + System.out.println("Usage: org.openecomp.sdc.post.Install path_to_titan.properties"); + System.exit(1); + } + String titanPropsFile = args[0]; + + if (!isFileExists(titanPropsFile)) { + System.exit(2); + } + + if (!createTitanSchema(titanPropsFile)) { + System.exit(3); + } + + System.exit(0); + } + + private static boolean createTitanSchema(String titanPropsFile) { + TitanGraphClient titanGraphClient = new TitanGraphClient(new DAOTitanStrategy()); + TitanOperationStatus status = titanGraphClient.createGraph(titanPropsFile); + if (TitanOperationStatus.OK == status) { + System.out.println("Titan schema ,indexes and default values created successfully."); + return true; + } else { + System.out.println( + "Problem while creating titan schema ,indexes and default values. (" + status.name() + ")"); + return false; + } + } + + private static boolean isFileExists(String titanPropsFile) { + File f = new File(titanPropsFile); + if (!f.exists()) { + System.out.println(titanPropsFile + " not found"); + return false; + } + return true; + } +} diff --git a/test-apis-ci/src/main/resources/ci/conf/attsdc-packages.yaml b/test-apis-ci/src/main/resources/ci/conf/attsdc-packages.yaml new file mode 100644 index 0000000000..5d1a3e1537 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/conf/attsdc-packages.yaml @@ -0,0 +1,12 @@ +packages: + - org.openecomp.sdc.ci.tests.execute.general + - org.openecomp.sdc.ci.tests.execute.user + - org.openecomp.sdc.ci.tests.execute.property + - org.openecomp.sdc.ci.tests.execute.lifecycle + - org.openecomp.sdc.ci.tests.execute.resource + - org.openecomp.sdc.ci.tests.execute.service + - org.openecomp.sdc.ci.tests.execute.artifacts + - org.openecomp.sdc.ci.tests.execute.imports + - org.openecomp.sdc.ci.tests.execute.category + - org.openecomp.sdc.ci.tests.execute.distribution + - org.openecomp.sdc.ci.tests.execute.product \ No newline at end of file diff --git a/test-apis-ci/src/main/resources/ci/conf/attsdc.yaml b/test-apis-ci/src/main/resources/ci/conf/attsdc.yaml new file mode 100644 index 0000000000..7273344672 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/conf/attsdc.yaml @@ -0,0 +1,93 @@ +outputFolder: target +reportName: index.html +catalogBeHost: behost +catalogFeHost: fehost +esHost: eshost +disributionClientHost: disClient +catalogFePort: 8181 +catalogBePort: 8080 +disributionClientPort: 8181 +isDistributionClientRunning: true +esPort: 9200 +neoHost: neoHost +neoPort: 7474 +neoDBusername: neo4j +neoDBpassword: 123456 +windowsDownloadDirectory: "c:\\apache-ftpserver-1.1.0\\res\\home" + +resourceConfigDir: src/test/resources/CI/tests +componentsConfigDir: src/test/resources/CI/components +importResourceConfigDir: ../catalog-be/src/main/resources/import/tosca/capability-types +importResourceTestsConfigDir: src/test/resources/CI/importResourceTests +errorConfigurationFile: ../catalog-be/src/main/resources/config/error-configuration.yaml +configurationFile: ../catalog-be/src/main/resources/config/configuration.yaml +importTypesConfigDir: src/test/resources/CI/importTypesTest + + +titanPropertiesFile: src/main/resources/ci/conf/titan.properties +cassandraHost: 127.0.0.1 +cassandraAuthenticate: false +cassandraUsername: koko +cassandraPassword: bobo +cassandraSsl: false +cassandraTruststorePath : /path/path +cassandraTruststorePassword : 123123 +cassandraAuditKeySpace: sdcaudit +cassandraArtifactKeySpace: sdcartifact +url: http://localhost:8181/sdc1/proxy-designer1#/dashboard + + +stopOnClassFailure: false + +#List of non-abstract resources to keep during titan cleanup between tests +#Only 1.0 version will be kept +resourcesNotToDelete: + - Compute + - Database + - ObjectStorage + - BlockStorage + - LoadBalancer + - Port + - Network + - Root + - ContainerApplication + - ContainerRuntime + - DBMS + - SoftwareComponent + - WebApplication + - WebServer + - CinderVolume + - ContrailVirtualNetwork + - NeutronNet + - NeutronPort + - NovaServer + - AbstractSubstitute + - ContrailAbstractSubstitute + - ContrailCompute + - ContrailNetworkRules + - ContrailPort + - ContrailV2NetworkRules + - ContrailV2VirtualMachineInterface + - ContrailV2VirtualNetwork + - ContrailVirtualNetwork + - VL ELINE + - SecurityRules + - VL + +#Resource categories to keep (including all their subcategories) +resourceCategoriesNotToDelete: + - Generic + - Network L2-3 + - Network L4+ + - Application L4+ + - Network Connectivity + - DCAE Component + - Template + - Allotted Resource + +#Service categories to keep +serviceCategoriesNotToDelete: + - Mobility + - Network L1-3 + - Network L4+ + - VoIP Call Control \ No newline at end of file diff --git a/test-apis-ci/src/main/resources/ci/conf/extent-config.xml b/test-apis-ci/src/main/resources/ci/conf/extent-config.xml new file mode 100644 index 0000000000..ab04b2678a --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/conf/extent-config.xml @@ -0,0 +1,51 @@ + + + + + + standard + + + + UTF-8 + + + + https + + + ASDC Automation Report + + + ASDC Automation Report + + + + + + + yyyy-MM-dd + + + + HH:mm:ss + + + + "); + $('.logo-content' ).remove(); + $('.charts div:nth-child(2)').remove(); + }); + ]]> + + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/main/resources/ci/conf/log4j.properties b/test-apis-ci/src/main/resources/ci/conf/log4j.properties new file mode 100644 index 0000000000..d313e92b55 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/conf/log4j.properties @@ -0,0 +1,34 @@ +# Define the root logger with appender file +log4j.rootLogger = INFO, FILE, stdout + +# Define the file appender +log4j.appender.FILE=org.apache.log4j.RollingFileAppender +log4j.appender.FILE.File=${targetlog}logs/ci-log.out + +# Define the layout for file appender +log4j.appender.FILE.layout=org.apache.log4j.PatternLayout +log4j.appender.FILE.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p [%10c] : %m%n + +# Set the maximum file size before rollover +log4j.appender.FILE.maxFileSize=5MB + +# Set the the backup index +log4j.appender.FILE.maxBackupIndex=10 + + +############################################################# + +# Direct log messages to stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %10c:%L - %m%n + +log4j.logger.org.apache.cassandra.service.StorageProxy=INFO +log4j.logger.com.thinkaurelius.titan.diskstorage.cassandra.CassandraTransaction=INFO, FILE, stdout + +log4j.logger.org.openecomp.sdc.ci.tests.utils=INFO, FILE, stdout +log4j.additivity.org.openecomp.sdc.ci.tests.utils=false + + diff --git a/test-apis-ci/src/main/resources/ci/conf/log4j.xml b/test-apis-ci/src/main/resources/ci/conf/log4j.xml new file mode 100644 index 0000000000..6db233a1da --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/conf/log4j.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/ci/conf/testngLifeCycle.xml b/test-apis-ci/src/main/resources/ci/conf/testngLifeCycle.xml new file mode 100644 index 0000000000..aa390dc213 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/conf/testngLifeCycle.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/ci/conf/titan.properties b/test-apis-ci/src/main/resources/ci/conf/titan.properties new file mode 100644 index 0000000000..42e1998f89 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/conf/titan.properties @@ -0,0 +1,8 @@ +storage.backend=cassandra +#storage.hostname=cassandrahost +storage.hostname=localhost +storage.port=9160 + +cache.db-cache = false + + diff --git a/test-apis-ci/src/main/resources/ci/conf/truststore b/test-apis-ci/src/main/resources/ci/conf/truststore new file mode 100644 index 0000000000000000000000000000000000000000..bdec93d86257edaf58480600062efeeac1d40b29 GIT binary patch literal 971 zcmezO_TO6u1_mY|W(3o`xh08tS!I^RDaq+Z20+met{9Oy46G4)rUsS_49u+tP0Wo3 zO-z{!n3))vm{@H6=4%=7vTh&tTBR$i>ve$jC5t5u3`JW-;&k?`B=RH2D7rl@< z!pd1W`{(7|ykfQyPoh$0Ren{~Te)=Cj&+vlw9Pe7=q&d-V>=k20f7WkWrJ95o9|8U2nkJ0OcHR?_8c3hC)RSf*cu-N#{nWy2p z_w$Z0t6j;Ryd;--lYn4!c%J0XUYE*{?%1^f3$C^1)bC7{D%KS*{$Fb_?O?+)Be9b# zUsl#tA84_yZe6@T!PGBX!K;9!xbKG0`vs}Knys9#65_jk+(fqp|10rX&A3anYxN=L z)at%v(l-12eywkJ_@wDnGbW)KxBX8A(5U#3QwJ@zy?F-Pvm z7VZ9d4iPPJQa8NBtCk;$ali3WonbZajde>HR6f@T@8pg9ulXz1A@sU~%EB+dKcCB$ z5Wd80XJSyGdG^yszvD%Xl07$0^Lj1+*(GDRNB()miQO6#+rnNgzn2!7)N3rMFehuK z#>)Cr{Y4iAu&aM1so2F=`0r)^K2!f?A_ zrKXGT-K|c7JVuu;F1#?UoayDUrF$gpKXQ522kc3BYX0z;=c_~WqNUCs(aGO9QR4a| S_04-ySEnqfh^XJ%xBviixL{!b literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/main/resources/ci/scripts/addUsersFromList_new.sh b/test-apis-ci/src/main/resources/ci/scripts/addUsersFromList_new.sh new file mode 100644 index 0000000000..0d494d919d --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/scripts/addUsersFromList_new.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +function help_usage () +{ + echo "$0 -ip -f " + echo "for example: -ip 127.0.0.1 -f /var/tmp/userToAdd.txt" + exit +} + +function check_file_existance () +{ +echo "check_file_existance $1" +if [ $1 == "" ]; then + echo "Please provide full path to user file" + exit; +elif [ -f $1 ]; then + source $1 + USERS=("${USER_LIST[@]}") + echo "file exist" $1 +else + echo "Provided user file does not exist" + exit +fi +} + +function check_ip_existance () +{ +if [ $1 == "" ]; then + echo "Please provide ip address" + exit; +fi +} + +function addUser () +{ + #for user in "${USER_LIST[@]}"; do + for user in "${USERS[@]}"; do + PING=`ping -c 1 $IP > /var/tmp/ping.log` + pattern1='100% packet loss' + pattern2='Host Unreachable' + COUNT=`egrep -c "$pattern1|$pattern2" /var/tmp/ping.log` + if [ $COUNT -eq 0 ]; then + # curl -i -X post -d '{ "userId" : "kk1123", "role" : "ADMIN" }' -H "Content-Type: application/json" -H "USER_ID: jh0003" http://192.168.111.9:8080/sdc2/rest/v1/user + userId=`echo $user|awk '{print $1}'` + role=`echo $user|awk '{print $2}'` + curl -i -X post -d '{ "userId" : "'${userId}'", "role" : "'${role}'" }' -H "Content-Type: application/json" -H "USER_ID: jh0003" http://${IP}:8080/sdc2/rest/v1/user + else + echo "Host" $IP "Is Unreachable" + fi + done +} + +#main +[ $# -eq 0 ] && help_usage +while [ $# -ne 0 ]; do + case $1 in + "-f") + USER_FILE=$2 + shift 1 + shift 1 + ;; + -ip) + IP=$2 + shift 1 + shift 1 + ;; + *) +# help_usage + ;; + esac +done + +check_file_existance $USER_FILE +check_ip_existance $IP +addUser diff --git a/test-apis-ci/src/main/resources/ci/scripts/copyToStorage.sh b/test-apis-ci/src/main/resources/ci/scripts/copyToStorage.sh new file mode 100644 index 0000000000..30094fe235 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/scripts/copyToStorage.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +REPORT_NAME=$1 +VERSION=$2 +ENV=$3 +IP=$4 + +if [ -z "$REPORT_NAME" ] + then + source ExtentReport/versions.info + now=$(date -d '+7 hour' "+%Y-%m-%d_%H_%M") + REPORT_NAME="${now}" + VERSION="${osVersion}" + if [[ $env == *"DEV20"* ]] + then + ENV="Nightly" + else + ENV="" + fi + + fi + +/usr/bin/expect << EOF +spawn ssh admin@${IP} mkdir -p -m 775 /home/admin/reports/${ENV}/${VERSION}/APIs/ + +expect { + -re ".*es.*o.*" { + exp_send "yes\r" + exp_continue + } + -re ".*sword.*" { + exp_send "Aa123456\r" + } +} + +expect eof + +spawn scp -r ExtentReport admin@${IP}:/home/admin/reports/${ENV}/${VERSION}/APIs/${REPORT_NAME}/ + +expect { + -re ".*es.*o.*" { + exp_send "yes\r" + exp_continue + } + -re ".*sword.*" { + exp_send "Aa123456\r" + } +} + +expect eof + +spawn ssh admin@${IP} chmod -R 775 /home/admin/reports/${ENV}/${VERSION}/APIs/${REPORT_NAME}/ + +expect { + -re ".*es.*o.*" { + exp_send "yes\r" + exp_continue + } + -re ".*sword.*" { + exp_send "Aa123456\r" + } +} + +expect eof + +EOF diff --git a/test-apis-ci/src/main/resources/ci/scripts/sendMail.sh b/test-apis-ci/src/main/resources/ci/scripts/sendMail.sh new file mode 100644 index 0000000000..4c23a7973e --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/scripts/sendMail.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +now=$(date +'%Y%-m%d%H%M') + +REPORT_NAME=$1 +VERSION=$2 +ENV=$3 + +RECIPIENTS1="dl-sdcqa@intl.att.com,ml636r@intl.att.com,bl5783intl.att.com,ak314p@intl.att.com,el489u@intl.att.com,hk096q@intl.att.com,bs5719@intl.att.com" +RECIPIENTS2="dl-asdcqa@intl.att.com" + +source ExtentReport/versions.info +if [ -z "$REPORT_NAME" ] + then + now=$(date -d '+7 hour' "+%Y-%m-%d_%H_%M") + REPORT_NAME="${now}" + VERSION="${osVersion}" +fi + +if [[ $env == *"DEV20"* ]] + then + ENV="Nightly" + RECIPIENTS=$RECIPIENTS1 + else + ENV="" + RECIPIENTS=$RECIPIENTS2 +fi + + +#REPORT_ZIP_FILE=ExtentReport_${now}.zip +REPORT_FOLDER='ExtentReport' +REPORT_HTML_FILE=${REPORT_FOLDER}/*Report.html +BODY_MESSAGE='Hello, \n\n Please find automation results on following link: \n\n http://asdc-srv-210-45.tlv.intl.att.com/'${ENV}'/'${VERSION}'/APIs/'${REPORT_NAME}'/SDC_CI_Extent_Report.html \n\nThanks, \nSDC QA Team\n\n ' + +#OLD_FILE=$(find ./ -type f -name ${REPORT_ZIP_FILE} -print) +#if [ ! -z ${OLD_FILE} ] +#then +# rm -f ${REPORT_ZIP_FILE} +# echo "Removing old zip file............" +#fi + +#echo "Creating new zip file" +#zip -r ${REPORT_ZIP_FILE} ./${REPORT_FOLDER} + + +echo -e ${BODY_MESSAGE} | mail -s 'External APIs Automation '$ENV' results - ASDC '$VERSION -r 'ASDC@Automation.team' $RECIPIENTS diff --git a/test-apis-ci/src/main/resources/ci/scripts/startTest.sh b/test-apis-ci/src/main/resources/ci/scripts/startTest.sh new file mode 100644 index 0000000000..d3c15026cd --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/scripts/startTest.sh @@ -0,0 +1,153 @@ +#!/bin/bash +REMOTE_DEBUG=false +RERUN=false +JAVA_OPTION="" +debug_port=8000 +TEST_SUITES=testSuites +fileName=testng-failed.xml + +function help_usage () +{ + echo + echo "$0 ( ) [-r/rerun -d/debug ]" + echo "nohup ./startTest.sh ui-ci-1707.0.5-SNAPSHOT-jar-with-dependencies.jar extendedSanity.xml -r false -d true &" + echo "by default rerun is true and remote debug is false." + echo + exit 2 +} + +function isBoolean () +{ + PARAM_NAME=$1 + VALUE=$2 + if [[ ${VALUE} != "true" ]] && [[ ${VALUE} != "false" ]]; then + echo "Valid parameter" ${PARAM_NAME} "values are: true/false" + help_usage + fi +} + +function prepareFailedXmlFile () +{ + echo "1="$1 "2="$2 "fileName="${fileName} + PATTERN=`grep -w "test name=" ${FULL_PATH}/${TEST_SUITES}/$2 | awk -F'"' '{print $2}'` + sed '/ ${FULL_PATH}/${TEST_SUITES}/${fileName} + sed -i 's/thread-count="[0-9]\+"/thread-count="1"/g' ${FULL_PATH}/${TEST_SUITES}/${fileName} +} + +#main +[ $# -lt 2 ] && help_usage + +JAR_FILE=$1 +SUITE_FILE=$2 + +while [ $# -ne 0 ]; do + case $1 in + -r|rerun) + RERUN=$2 + isBoolean $1 ${RERUN} + shift 1 + shift 1 + ;; + -d|debug) + REMOTE_DEBUG=$2 + isBoolean $1 ${REMOTE_DEBUG} + shift 1 + shift 1 + ;; + *) + shift 1 + ;; + esac +done + +CURRENT_DIR=`pwd` +BASEDIR=$(dirname $0) + +if [ ${BASEDIR:0:1} = "/" ] +then + FULL_PATH=$BASEDIR +else + FULL_PATH=$CURRENT_DIR/$BASEDIR +fi +LOGS_PROP_FILE=file:${FULL_PATH}/conf/log4j.properties +############################################# +TARGET_DIR=${FULL_PATH}/target +CONF_FILE=${FULL_PATH}/conf/attsdc.yaml + +DEBUG=true +MainClass=org.openecomp.sdc.ci.tests.run.StartTest + +TESTS_DIR=/opt/app/sdc/ci/resources/tests +COMPONENTS_DIR=/opt/app/sdc/ci/resources/components + + +TARGET_LOG_DIR="${TARGET_DIR}/" + +######ADD USERS################ + +BE_IP=`cat conf/attsdc.yaml | grep catalogBeHost| awk '{print $2}'` + +ADD_USERS_SCRIPT="addUsersFromList_new.sh" +USER_LIST="userList.txt" +chmod +x ${ADD_USERS_SCRIPT} +echo "add users..." +`./${ADD_USERS_SCRIPT} -ip ${BE_IP} -f ${USER_LIST}` + + + +if [ ${REMOTE_DEBUG} == "true" ]; then + echo "Debug mode, Listen on port $debug_port"; + JAVA_OPTION="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${debug_port}" ; +fi + +cmd="java -Xmx2048m -Xms1024m $JAVA_OPTION -DdisplayException=true -Dtargetlog=${TARGET_LOG_DIR} -Dfilepath=${FILES_TEST} -Dconfig.resource=${CONF_FILE} -Ddebug=${DEBUG} -Dlog4j.configuration=${LOGS_PROP_FILE} -cp $JAR_FILE ${MainClass} $SUITE_FILE &" + + +if [ $DEBUG == "true" ] +then + $cmd +else + $cmd >> /dev/null +fi + +if [ ${RERUN} == "true" ]; then + if [ -f ${TARGET_DIR}/${fileName} ]; then + echo "Prepare" ${TARGET_DIR}/${fileName} "file to rerun all failed tests ..."; + prepareFailedXmlFile ${TARGET_DIR}/${fileName} $SUITE_FILE; + SUITE_FILE=${fileName}; + cmd="java -Xmx2048m -Xms1024m $JAVA_OPTION -DdisplayException=true -Dtargetlog=${TARGET_LOG_DIR} -Dfilepath=${FILES_TEST} -Dconfig.resource=${CONF_FILE} -Ddebug=${DEBUG} -Dlog4j.configuration=${LOGS_PROP_FILE} -cp $JAR_FILE ${MainClass} $SUITE_FILE &" + $cmd; + fi +fi + +status=`echo $?` + +source ExtentReport/versions.info +now=$(date +'%Y-%m-%d_%H_%M') +REPORT_NAME=${now} +VERSION=${osVersion} + +if [[ $env == *"DEV20"* ]] +then + MYENV="Nightly" +else + MYENV="" +fi + +COPY_REPORT_SCRIPT="copyToStorage.sh" +chmod +x ${COPY_REPORT_SCRIPT} +echo "copy report to storage..." +sh ./${COPY_REPORT_SCRIPT} ${REPORT_NAME} ${VERSION} ${MYENV} + + +MAILING_SCRIPT_NAME="sendMail.sh" +chmod +x ${MAILING_SCRIPT_NAME} +echo "Sending report via mail..." +`./${MAILING_SCRIPT_NAME} ${REPORT_NAME} ${VERSION} ${MYENV}` + + +echo "##################################################" +echo "################# status is ${status} #################" +echo "##################################################" + +exit $status diff --git a/test-apis-ci/src/main/resources/ci/scripts/userList.txt b/test-apis-ci/src/main/resources/ci/scripts/userList.txt new file mode 100644 index 0000000000..a1326599dc --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/scripts/userList.txt @@ -0,0 +1 @@ +export USER_LIST=( "m99121 DESIGNER" "cs0008 DESIGNER" "kb0004 TESTER" "af0006 OPS" "ah0002 GOVERNOR" "m08740 DESIGNER" "m99124 TESTER" "m08743 TESTER" "m99123 OPS" "m08742 OPS" "m99125 GOVERNOR" "m08744 GOVERNOR" "m99122 ADMIN" "m08741 ADMIN" "m99126 PRODUCT_STRATEGIST" "m08745 PRODUCT_STRATEGIST" "m99127 PRODUCT_MANAGER" "m08746 PRODUCT_MANAGER" "md9897 DESIGNER" "m08748 DESIGNER" "m08749 TESTER" "be0695 DESIGNER" "er434w DESIGNER" "ya107f DESIGNER" "ds200p DESIGNER" "ak0333 ADMIN" "th0695 DESIGNER" "al714h DESIGNER" "ys9693 DESIGNER" "ss8214 DESIGNER" "bt750h DESIGNER" "rp955r DESIGNER" "ez6451 DESIGNER" "ia901h DESIGNER" "ah7840 DESIGNER" "ea394r DESIGNER" "ms656r DESIGNER" "ml636r DESIGNER" "it1721 DESIGNER" "sg473v DESIGNER" "sa997j DESIGNER" "az2497 DESIGNER" "ys189e DESIGNER" "ig642y DESIGNER" ) diff --git a/test-apis-ci/src/main/resources/ci/testSuites/CRUDArtifacts.xml b/test-apis-ci/src/main/resources/ci/testSuites/CRUDArtifacts.xml new file mode 100644 index 0000000000..e53da8da8a --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/CRUDArtifacts.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/main/resources/ci/testSuites/SearchExternalAPI.xml b/test-apis-ci/src/main/resources/ci/testSuites/SearchExternalAPI.xml new file mode 100644 index 0000000000..40c462a4cb --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/SearchExternalAPI.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/main/resources/ci/testSuites/artifacts.xml b/test-apis-ci/src/main/resources/ci/testSuites/artifacts.xml new file mode 100644 index 0000000000..24229b8586 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/artifacts.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/ci/testSuites/category.xml b/test-apis-ci/src/main/resources/ci/testSuites/category.xml new file mode 100644 index 0000000000..f2a0b3790c --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/category.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/ci/testSuites/ciFull.xml b/test-apis-ci/src/main/resources/ci/testSuites/ciFull.xml new file mode 100644 index 0000000000..26a85fd9c6 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/ciFull.xml @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/main/resources/ci/testSuites/externalAPIs.xml b/test-apis-ci/src/main/resources/ci/testSuites/externalAPIs.xml new file mode 100644 index 0000000000..3505dad3c4 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/externalAPIs.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/main/resources/ci/testSuites/general.xml b/test-apis-ci/src/main/resources/ci/testSuites/general.xml new file mode 100644 index 0000000000..bd7e6b6650 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/general.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/ci/testSuites/imports.xml b/test-apis-ci/src/main/resources/ci/testSuites/imports.xml new file mode 100644 index 0000000000..ae4a5bc1f8 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/imports.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/asdc-tests/src/main/resources/ci/testSuites/product.xml b/test-apis-ci/src/main/resources/ci/testSuites/product.xml similarity index 100% rename from asdc-tests/src/main/resources/ci/testSuites/product.xml rename to test-apis-ci/src/main/resources/ci/testSuites/product.xml diff --git a/test-apis-ci/src/main/resources/ci/testSuites/productAPIs.xml b/test-apis-ci/src/main/resources/ci/testSuites/productAPIs.xml new file mode 100644 index 0000000000..61950e9de7 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/productAPIs.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/main/resources/ci/testSuites/property.xml b/test-apis-ci/src/main/resources/ci/testSuites/property.xml new file mode 100644 index 0000000000..f94f89737a --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/property.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/ci/testSuites/resource.xml b/test-apis-ci/src/main/resources/ci/testSuites/resource.xml new file mode 100644 index 0000000000..803fb01e70 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/resource.xml @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/ci/testSuites/sanity.xml b/test-apis-ci/src/main/resources/ci/testSuites/sanity.xml new file mode 100644 index 0000000000..f642170b34 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/sanity.xml @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/main/resources/ci/testSuites/service.xml b/test-apis-ci/src/main/resources/ci/testSuites/service.xml new file mode 100644 index 0000000000..18d5630c4e --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/service.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/ci/testSuites/testngLifeCycle.xml b/test-apis-ci/src/main/resources/ci/testSuites/testngLifeCycle.xml new file mode 100644 index 0000000000..54f1868470 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/testngLifeCycle.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/ci/testSuites/user.xml b/test-apis-ci/src/main/resources/ci/testSuites/user.xml new file mode 100644 index 0000000000..948993c144 --- /dev/null +++ b/test-apis-ci/src/main/resources/ci/testSuites/user.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/log4j.properties b/test-apis-ci/src/main/resources/log4j.properties new file mode 100644 index 0000000000..d313e92b55 --- /dev/null +++ b/test-apis-ci/src/main/resources/log4j.properties @@ -0,0 +1,34 @@ +# Define the root logger with appender file +log4j.rootLogger = INFO, FILE, stdout + +# Define the file appender +log4j.appender.FILE=org.apache.log4j.RollingFileAppender +log4j.appender.FILE.File=${targetlog}logs/ci-log.out + +# Define the layout for file appender +log4j.appender.FILE.layout=org.apache.log4j.PatternLayout +log4j.appender.FILE.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p [%10c] : %m%n + +# Set the maximum file size before rollover +log4j.appender.FILE.maxFileSize=5MB + +# Set the the backup index +log4j.appender.FILE.maxBackupIndex=10 + + +############################################################# + +# Direct log messages to stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %10c:%L - %m%n + +log4j.logger.org.apache.cassandra.service.StorageProxy=INFO +log4j.logger.com.thinkaurelius.titan.diskstorage.cassandra.CassandraTransaction=INFO, FILE, stdout + +log4j.logger.org.openecomp.sdc.ci.tests.utils=INFO, FILE, stdout +log4j.additivity.org.openecomp.sdc.ci.tests.utils=false + + diff --git a/test-apis-ci/src/main/resources/log4j.xml b/test-apis-ci/src/main/resources/log4j.xml new file mode 100644 index 0000000000..6db233a1da --- /dev/null +++ b/test-apis-ci/src/main/resources/log4j.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-apis-ci/src/main/resources/logback.xml b/test-apis-ci/src/main/resources/logback.xml new file mode 100644 index 0000000000..4723bc24cb --- /dev/null +++ b/test-apis-ci/src/main/resources/logback.xml @@ -0,0 +1,25 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss} | %-5p | [%thread] %logger{5}:%L - %msg%n + + + + + logFile.log + true + + %d{yyyy-MM-dd HH:mm:ss} | %-5p | [%thread] %logger{5}:%L - %msg%n + + + + + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/ecomp-error-configuration.yaml b/test-apis-ci/src/test/resources/CI/ecomp-error-configuration.yaml new file mode 100644 index 0000000000..9d7cd74a2b --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/ecomp-error-configuration.yaml @@ -0,0 +1,383 @@ +########################################### +# Note the conventions of the field values: +# type can be one of: CONFIG_ERROR, SYSTEM_ERROR, DATA_ERROR, CONNECTION_PROBLEM, AUTHENTICATION_PROBLEM +# severity can be one of: WARN, ERROR, FATAL +# alarmSeverity can be one of: CRITICAL,MAJOR,MINOR,INFORMATIONAL,NONE +# code is a unique integer in range of 3003-9999 (3000-3002 are occupied for internal usage) +# The above enumeration values are out-of-the-box and can be changed in code. +# In case of config and code mismatch, the appropriate error will be printed to log +# +## Range of BE codes - 3010-7999 + +errors: + + BeRestApiGeneralError: { + type: SYSTEM_ERROR, + code: ASDC_4000, + severity: ERROR, + description: "Unexpected error during BE REST API execution", + alarmSeverity: CRITICAL + } + + BeHealthCheckError: { + type: SYSTEM_ERROR, + code: ASDC_3010, + severity: ERROR, + description: "Error during BE Health Check", + alarmSeverity: CRITICAL + } + + BeInitializationError: { + type: SYSTEM_ERROR, + code: ASDC_4019, + severity: ERROR, + description: "Catalog-BE was not initialized properly", + alarmSeverity: CRITICAL + } + + BeResourceMissingError: { + type: SYSTEM_ERROR, + code: ASDC_3011, + severity: ERROR, + description: "Mandatory resource %s cannot be found in repository", + alarmSeverity: MAJOR + } + + BeServiceMissingError: { + type: SYSTEM_ERROR, + code: ASDC_3012, + severity: ERROR, + description: "Mandatory service %s cannot be found in repository", + alarmSeverity: MAJOR + } + + BeFailedAddingResourceInstanceError: { + type: SYSTEM_ERROR, + code: ASDC_3013, + severity: ERROR, + description: "Failed to add resource instance of resource %s to service %s", + alarmSeverity: MAJOR + } + + BeIncorrectServiceError: { + type: SYSTEM_ERROR, + code: ASDC_3014, + severity: ERROR, + description: "Service %s is not valid", + alarmSeverity: MAJOR + } + + BeRepositoryDeleteError: { + type: SYSTEM_ERROR, + code: ASDC_3015, + severity: ERROR, + description: "Failed to delete object %s from repository", + alarmSeverity: CRITICAL + } + + BeRepositoryQueryError: { + type: SYSTEM_ERROR, + code: ASDC_3016, + severity: ERROR, + description: "Failed to fetch from repository %s", + alarmSeverity: MAJOR + } + + BeInvalidConfigurationError: { + type: CONFIG_ERROR, + code: ASDC_3017, + severity: FATAL, + description: "Configuration parameter %s is invalid. Value configured is %s", + alarmSeverity: MAJOR + } + + BeUebConnectionError: { + type: CONNECTION_PROBLEM, + code: ASDC_4001, + severity: ERROR, + description: "Connection problem towards U-EB server. Reason: %s", + alarmSeverity: MAJOR + } + + BeUebSystemError: { + type: SYSTEM_ERROR, + code: ASDC_3019, + severity: ERROR, + description: "Error occured during access to U-EB Server. Operation: %s", + alarmSeverity: MAJOR + } + + BeUebObjectNotFoundError: { + type: DATA_ERROR, + code: ASDC_4005, + severity: ERROR, + description: "Error occured during access to U-EB Server. Data not found: %s", + alarmSeverity: MAJOR + } + + BeDistributionEngineSystemError: { + type: SYSTEM_ERROR, + code: ASDC_3021, + severity: ERROR, + description: "Error occured in Distribution Engine. Failed operation: %s", + alarmSeverity: MAJOR + } + + BeUebAuthenticationError: { + type: AUTHENTICATION_PROBLEM, + code: ASDC_4003, + severity: ERROR, + description: "Authentication problem towards U-EB server. Reason: %s", + alarmSeverity: MAJOR + } + + BeUebUnkownHostError: { + type: CONNECTION_PROBLEM, + code: ASDC_4002, + severity: ERROR, + description: "Connection problem towards U-EB server. Cannot reach host %s", + alarmSeverity: MAJOR + } + + BeDistributionEngineInvalidArtifactType: { + type: DATA_ERROR, + code: ASDC_4006, + severity: WARN, + description: "The artifact type %s does not appear in the list of valid artifacts %s", + alarmSeverity: MAJOR + } + BeInvalidTypeError: { + type: DATA_ERROR, + code: ASDC_4008, + severity: WARN, + description: "The type %s of %s is invalid", + alarmSeverity: MAJOR + } + BeInvalidValueError: { + type: DATA_ERROR, + code: ASDC_3028, + severity: WARN, + description: "The value %s of %s from type %s is invalid", + alarmSeverity: MAJOR + } + + BeFailedDeletingResourceInstanceError: { + type: SYSTEM_ERROR, + code: ASDC_3029, + severity: ERROR, + description: "Failed to delete resource instance %s from service %s", + alarmSeverity: MAJOR + } + + BeMissingConfigurationError: { + type: CONFIG_ERROR, + code: ASDC_3030, + severity: FATAL, + description: "Configuration parameter %s is missing", + alarmSeverity: MAJOR + } + + BeConfigurationInvalidListSizeError: { + type: CONFIG_ERROR, + code: ASDC_3031, + severity: FATAL, + description: "Configuration parameter %s is invalid. At least %s values shall be configured", + alarmSeverity: MAJOR + } + + ErrorConfigFileFormat: { + type: CONFIG_ERROR, + code: ASDC_3032, + severity: ERROR, + description: "Error element not found in YAML name: %s", + alarmSeverity: MAJOR + } + + BeMissingArtifactInformationError: { + type: DATA_ERROR, + code: ASDC_4010, + severity: ERROR, + description: "Artifact uploaded has missing information. Missing %s", + alarmSeverity: MAJOR + } + + BeArtifactMissingError: { + type: DATA_ERROR, + code: ASDC_4011, + severity: ERROR, + description: "Artifact %s requested is not found", + alarmSeverity: MAJOR + } + + BeArtifactPayloadInvalid: { + type: DATA_ERROR, + code: ASDC_4012, + severity: ERROR, + description: "Payload of artifact uploaded is invalid (invalid MD5 or encryption)", + alarmSeverity: MAJOR + } + + BeUserMissingError: { + type: DATA_ERROR, + code: ASDC_4009, + severity: ERROR, + description: "User %s requested is not found", + alarmSeverity: MAJOR + } + + BeArtifactInformationInvalidError: { + type: DATA_ERROR, + code: ASDC_4013, + severity: ERROR, + description: "Input for artifact metadata is invalid", + alarmSeverity: MAJOR + } + BeFailedAddingCapabilityTypeError: { + type: DATA_ERROR, + code: ASDC_4015, + severity: ERROR, + description: "Failed adding capability type", + alarmSeverity: CRITICAL + } + + BeCapabilityTypeMissingError: { + type: DATA_ERROR, + code: ASDC_4016, + severity: ERROR, + description: "Capability Type %s not found", + alarmSeverity: CRITICAL + } + + BeInterfaceMissingError: { + type: DATA_ERROR, + code: ASDC_4020, + severity: ERROR, + description: "Interface %s required is missing", + alarmSeverity: MAJOR + } + + BeDaoSystemError: { + type: SYSTEM_ERROR, + code: ASDC_4014, + severity: ERROR, + description: "Operation towards database failed", + alarmSeverity: CRITICAL + } + + BeSystemError: { + type: SYSTEM_ERROR, + code: ASDC_4017, + severity: ERROR, + description: "Unexpected error during operation", + alarmSeverity: CRITICAL + } + + BeFailedLockObjectError: { + type: SYSTEM_ERROR, + code: ASDC_4007, + severity: WARN, + description: "Failed to lock object for update", + alarmSeverity: CRITICAL + } + + BeInvalidJsonInput: { + type: SYSTEM_ERROR, + code: ASDC_4018, + severity: ERROR, + description: "Failed to convert json input to object", + alarmSeverity: MAJOR + } + + BeDistributionMissingError: { + type: DATA_ERROR, + code: ASDC_4021, + severity: ERROR, + description: "Distribution %s required is missing", + alarmSeverity: MAJOR + } + + BeHealthCheckRecovery: { + type: RECOVERY, + code: ASDC_4022, + severity: INFO, + description: "BE Health Check Recovery", + alarmSeverity: INFORMATIONAL + } + BeFailedCreateNodeError: { + type: DATA_ERROR, + code: ASDC_6000, + severity: ERROR, + description: "Failed to create node %s on graph. status is %s", + alarmSeverity: MAJOR + } + BeFailedUpdateNodeError: { + type: DATA_ERROR, + code: ASDC_6001, + severity: ERROR, + description: "Failed to update node %s on graph. Status is %s", + alarmSeverity: MAJOR + } + + BeFailedDeleteNodeError: { + type: DATA_ERROR, + code: ASDC_6002, + severity: ERROR, + description: "Failed to delete node %s on graph. Status is %s", + alarmSeverity: MAJOR + } + + BeFailedRetrieveNodeError: { + type: DATA_ERROR, + code: ASDC_6003, + severity: ERROR, + description: "Failed to retrieve node %s from graph. Status is %s", + alarmSeverity: MAJOR + } + + BeExecuteRollbackError: { + type: DATA_ERROR, + code: ASDC_6004, + severity: ERROR, + description: "Going to execute rollback on graph.", + alarmSeverity: MAJOR + } + + BeFailedFindParentError: { + type: DATA_ERROR, + code: ASDC_6005, + severity: ERROR, + description: "Failed to find parent node %s on graph. Status is %s", + alarmSeverity: MAJOR + } + + BeFailedFindAllNodesError: { + type: DATA_ERROR, + code: ASDC_6006, + severity: ERROR, + description: "Failed to fetch all nodes with type %s of parent node %s . Status is %s", + alarmSeverity: MAJOR + } + + BeFailedFindAssociationError: { + type: DATA_ERROR, + code: ASDC_6007, + severity: ERROR, + description: "Cannot find node with type %s associated with node %s . Status is %s", + alarmSeverity: MAJOR + } + + BeFailedFindAssociationError: { + type: DATA_ERROR, + code: ASDC_6008, + severity: ERROR, + description: "Cannot find node with type %s associated with node %s . Status is %s", + alarmSeverity: MAJOR + } + BeComponentCleanerSystemError: { + type: SYSTEM_ERROR, + code: ASDC_6009, + severity: ERROR, + description: "Error occured in Component Cleaner Task. Failed operation: %s", + alarmSeverity: MAJOR + } + \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/error-configuration.yaml b/test-apis-ci/src/test/resources/CI/error-configuration.yaml new file mode 100644 index 0000000000..ef7a885678 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/error-configuration.yaml @@ -0,0 +1,1778 @@ +# Errors +errors: + OK: { + code: 200, + message: "OK" + } + CREATED: { + code: 201, + message: "OK" + } + NO_CONTENT: { + code: 204, + message: "No Content" + } +#--------POL4050----------------------------- + NOT_ALLOWED: { + code: 405, + message: "Error: Method not allowed.", + messageId: "POL4050" + } +#--------POL5000----------------------------- + GENERAL_ERROR: { + code: 500, + message: "Error: Internal Server Error. Please try again later.", + messageId: "POL5000" + } +#---------POL5001------------------------------ + MISSING_X_ECOMP_INSTANCE_ID: { + code: 400 , + message: "Error: Missing 'X-ECOMP-InstanceID' HTTP header.", + messageId: "POL5001" + } +#---------POL5002------------------------------ + AUTH_REQUIRED: { + code: 401 , + message: "Error: Authentication is required to use the API.", + messageId: "POL5002" + } +#---------POL5003------------------------------ + AUTH_FAILED: { + code: 403 , + message: "Error: Not authorized to use the API.", + messageId: "POL5003" + } +#---------POL5004------------------------------ + MISSING_USER_ID: { + code: 400 , + message: "Error: Missing 'USER_ID' HTTP header.", + messageId: "POL5004" + } +#---------SVC4000----------------------------- + INVALID_CONTENT: { + code: 400, + message: "Error: Invalid content.", + messageId: "SVC4000" + } +#---------SVC4002----------------------------- + MISSING_INFORMATION: { + code: 403, + message: "Error: Missing information.", + messageId: "SVC4002" + } +#---------SVC4003------------------------------ +# %1 - Users's ID + USER_NOT_FOUND: { + code: 404, + message: "Error: User '%1' was not found.", + messageId: "SVC4003" + } +#---------SVC4004----------------------------- +# %1 - Users's email address + INVALID_EMAIL_ADDRESS: { + code: 400, + message: "Error: Invalid email address '%1'.", + messageId: "SVC4004" + } +#---------SVC4005------------------------------ +# %1 - role + INVALID_ROLE: { + code: 400, + message: "Error: Invalid role '%1'.", + messageId: "SVC4005" + } +#---------SVC4006------------------------------ +# %1 - Users's USER_ID + USER_ALREADY_EXIST: { + code: 409, + message: "Error: User with '%1' ID already exists.", + messageId: "SVC4006" + } +#---------SVC4007------------------------------ + DELETE_USER_ADMIN_CONFLICT: { + code: 409, + message: "Error: An administrator can only be deleted by another administrator.", + messageId: "SVC4007" + } +#---------SVC4008----------------------------- +# %1 - Users's userId + INVALID_USER_ID: { + code: 400, + message: "Error: Invalid userId '%1'.", + messageId: "SVC4008" + } +#---------SVC4049------------------------------ +# %1 - service/resource + COMPONENT_MISSING_CONTACT: { + code: 400, + message: "Error: Invalid Content. Missing %1 contact.", + messageId: "SVC4049" + } +#---------SVC4050----------------------------- +# %1 - Service/Resource/Additional parameter +# %2 - service/resource/label name + COMPONENT_NAME_ALREADY_EXIST: { + code: 409, + message: "Error: %1 with name '%2' already exists.", + messageId: "SVC4050" + } +#---------SVC4051------------------------------ +# %1 - resource/service + COMPONENT_MISSING_CATEGORY: { + code: 400, + message: "Error: Invalid Content. Missing %1 category.", + messageId: "SVC4051" + } + +#---------SVC4052------------------------------ + COMPONENT_MISSING_TAGS: { + code: 400, + message: "Error: Invalid Content. At least one tag has to be specified.", + messageId: "SVC4052" + } + +#---------SVC4053------------------------------ +# %1 - service/resource + COMPONENT_MISSING_DESCRIPTION: { + code: 400, + message: "Error: Invalid Content. Missing %1 description.", + messageId: "SVC4053" + } +#---------SVC4054------------------------------ +# %1 - resource/service + COMPONENT_INVALID_CATEGORY: { + code: 400, + message: "Error: Invalid Content. Invalid %1 category.", + messageId: "SVC4054" + } +#---------SVC4055------------------------------ + MISSING_VENDOR_NAME: { + code: 400, + message: "Error: Invalid Content. Missing vendor name.", + messageId: "SVC4055" + } +#---------SVC4056------------------------------ + MISSING_VENDOR_RELEASE: { + code: 400, + message: "Error: Invalid Content. Missing vendor release.", + messageId: "SVC4056" + } + +#---------SVC4057------------------------------ + MISSING_DERIVED_FROM_TEMPLATE: { + code: 400, + message: "Error: Invalid Content. Missing derived from template specification.", + messageId: "SVC4057" + } + +#---------SVC4058------------------------------ +# %1 - service/resource + COMPONENT_MISSING_ICON: { + code: 400, + message: "Error: Invalid Content. Missing %1 icon.", + messageId: "SVC4058" + } +#---------SVC4059------------------------------ +# %1 - service/resource + COMPONENT_INVALID_ICON: { + code: 400, + message: "Error: Invalid Content. Invalid %1 icon.", + messageId: "SVC4059" + } +#---------SVC4060------------------------------ + PARENT_RESOURCE_NOT_FOUND: { + code: 400, + message: "Error: Invalid Content. Derived from resource template was not found.", + messageId: "SVC4060" + } +#---------SVC4061------------------------------ + MULTIPLE_PARENT_RESOURCE_FOUND: { + code: 400, + message: "Error: Invalid Content. Multiple derived from resource template is not allowed.", + messageId: "SVC4061" + } + +#---------SVC4062------------------------------ +# %1 - service/resource + MISSING_COMPONENT_NAME: { + code: 400, + message: "Error: Invalid Content. Missing %1 name.", + messageId: "SVC4062" + } +#---------SVC4063------------------------------ + #%1  -  resource/service name + RESOURCE_NOT_FOUND: { + code: 404, + message: "Error: Requested '%1' resource was not found.", + messageId: "SVC4063" + } + +#---------SVC4064------------------------------ +# %1 - Service/Resource/Property + COMPONENT_INVALID_DESCRIPTION: { + code: 400, + message: "Error: Invalid Content. %1 description contains non-english characters.", + messageId: "SVC4064" + } +#---------SVC4065------------------------------ +# %1 - Service/Resource/Property +# %2 - max resource/service name length + COMPONENT_DESCRIPTION_EXCEEDS_LIMIT: { + code: 400, + message: "Error: Invalid Content. %1 description exceeds limit of %2 characters.", + messageId: "SVC4065" + } +#---------SVC4066------------------------------ +# %1 - max length + COMPONENT_TAGS_EXCEED_LIMIT: { + code: 400, + message: "Error: Invalid Content. Tags overall length exceeds limit of %1 characters.", + messageId: "SVC4066" + } +#---------SVC4067------------------------------ +# %1 - max length + VENDOR_NAME_EXCEEDS_LIMIT: { + code: 400, + message: "Error: Invalid Content. Vendor name exceeds limit of %1 characters.", + messageId: "SVC4067" + } +#---------SVC4068------------------------------ +# %1 - max length + VENDOR_RELEASE_EXCEEDS_LIMIT: { + code: 400, + message: "Error: Invalid Content. Vendor release exceeds limit of %1 characters.", + messageId: "SVC4068" + } + +#---------SVC4069------------------------------ +# %1 - Service/Resource/Product + COMPONENT_INVALID_CONTACT: { + code: 400, + message: "Error: Invalid Content. %1 Contact Id should be in format 'mnnnnnn' or 'aannna' or 'aannnn', where m=m ,a=a-zA-Z and n=0-9", + messageId: "SVC4069" + } +#---------SVC4070------------------------------ +# %1 - Service/Resource + INVALID_COMPONENT_NAME: { + code: 400, + message: 'Error: Invalid Content. %1 name is not allowed to contain characters like <>:"\/|?* and space characters other than regular space.', + messageId: "SVC4070" + } + +#---------SVC4071------------------------------ + INVALID_VENDOR_NAME: { + code: 400, + message: 'Error: Invalid Content. Vendor name is not allowed to contain characters like <>:"\/|?* and space characters other than regular space.', + messageId: "SVC4071" + } +#---------SVC4072------------------------------ + INVALID_VENDOR_RELEASE: { + code: 400, + message: 'Error: Invalid Content. Vendor release is not allowed to contain characters like <>:"\/|?* and space characters other than regular space.', + messageId: "SVC4072" + } +#---------SVC4073------------------------------ +# %1 - Service/Resource +# %2 - max resource/service name + COMPONENT_NAME_EXCEEDS_LIMIT: { + code: 400, + message: "Error: Invalid Content. %1 name exceeds limit of %2 characters.", + messageId: "SVC4073" + } +#---------SVC4080------------------------------ +# %1 - resource/service name +# %2 - resource/service +# %3 - First name of last modifier +# %4 - Last name of last modifier +# %5 - USER_ID of last modifier + COMPONENT_IN_CHECKOUT_STATE: { + code: 403, + message: "Error: Requested '%1' %2 is locked for modification by %3 %4(%5).", + messageId: "SVC4080" + } +#---------SVC4081----------------------------- +# %1 - resource/service name +# %2 - resource/service +# %3 - First name of last modifier +# %4 - Last name of last modifier +# %5 - USER_ID of last modifier + COMPONENT_IN_CERT_IN_PROGRESS_STATE: { + code: 403, + message: "Error: Requested '%1' %2 is locked for certification by %3 %4(%5).", + messageId: "SVC4081" + } + +#-----------SVC4082--------------------------- +# %1 - resource/service name +# %2 - resource/service +# %3 - First name of last modifier +# %4 - Last name of last modifier +# %5 - USER_ID of last modifier + COMPONENT_SENT_FOR_CERTIFICATION: { + code: 403, + message: "Error: Requested '%1' %2 is sent for certification by %3 %4(%5).", + messageId: "SVC4082" + } +#-----------SVC4083--------------------------- + COMPONENT_VERSION_ALREADY_EXIST: { + code: 409, + message: "Error: Version of this %1 was already promoted.", + messageId: "SVC4083" + } +#-----------SVC4084--------------------------- +# %1 - resource/service/product name +# %2 - resource/service/product +# %3 - First name of last modifier +# %4 - Last name of last modifier +# %5 - USER_ID of last modifier + COMPONENT_ALREADY_CHECKED_IN: { + code: 409, + message: "Error: The current version of '%1' %2 was already checked-in by %3 %4(%5).", + messageId: "SVC4084" + } +#-----------SVC4085--------------------------- +# %1 - resource/service/product name +# %2 - resource/service/product +# %3 - First name of last modifier +# %4 - Last name of last modifier +# %5 - USER_ID of last modifier + COMPONENT_CHECKOUT_BY_ANOTHER_USER: { + code: 403, + message: "Error: %1 %2 has already been checked out by %3 %4(%5).", + messageId: "SVC4085" + } +#-----------SVC4086--------------------------- +# %1  - resource/service name +# %2  - resource/service + COMPONENT_IN_USE: { + code: 403, + message: "Error: Requested '%1' %2 is in use by another user.", + messageId: "SVC4086" + } +#-----------SVC4087--------------------------- +# %1 - component name +# %2 - resource/service/product + COMPONENT_HAS_NEWER_VERSION: { + code: 409, + message: "Error: Checking out of the requested version of the '%1' %2 is not allowed as a newer version exists.", + messageId: "SVC4087" + } +#-----------SVC4088--------------------------- +# %1 - resource/service name +# %2 - resource/service +# %3 - First name of last modifier +# %4 - Last name of last modifier +# %5 - USER_ID of last modifier + COMPONENT_ALREADY_CERTIFIED: { + code: 403, + message: "Error: Requested %1 %2 has already been certified by %3 %4(%5).", + messageId: "SVC4088" + } +#-----------SVC4089--------------------------- +# %1 - resource/service name +# %2 - resource/service + COMPONENT_NOT_READY_FOR_CERTIFICATION: { + code: 403, + message: "Error: Requested '%1' %2 is not ready for certification.", + messageId: "SVC4089" + } +#-----------SVC4100--------------------------- +#%1 - property name + PROPERTY_NOT_FOUND: { + code: 404, + message: "Error: Requested '%1' property was not found.", + messageId: "SVC4100" + } +#-----------SVC4101--------------------------- +#%1 - property name + PROPERTY_ALREADY_EXIST: { + code: 409, + message: "Error: Property with '%1' name already exists.", + messageId: "SVC4101" + } + +#-----------SVC4102--------------------------- +# %1 - capability type name + CAPABILITY_TYPE_ALREADY_EXIST: { + code: 409, + message: "Error: Capability Type with name '%1' already exists.", + messageId: "SVC4102" + } +#-----------SVC4114--------------------------- + AUTH_FAILED_INVALIDE_HEADER: { + code: 400, + message: "Error: Invalid Authorization header.", + messageId: "SVC4114" + } +#-----------SVC4115--------------------------- +# %1 - capability type name + MISSING_CAPABILITY_TYPE: { + code: 400, + message: "Error: Invalid Content. Missing Capability Type '%1'.", + messageId: "SVC4115" + } + RESOURCE_INSTANCE_BAD_REQUEST: { + code: 400, + message: "Error: Invalid Content.", + messageId: "SVC4116" + } +#-----------SVC4117--------------------------- +# %1 - resource instance name +# %2 - resource instance name +# %3 - requirement name + RESOURCE_INSTANCE_MATCH_NOT_FOUND: { + code: 404, + message: "Error: Match not found between resource instance '%1' and resource instance '%2' for requirement '%3'.", + messageId: "SVC4117" + } +#-----------SVC4118--------------------------- +# %1 - resource instance name +# %2 - resource instance name +# %3 - requirement name + RESOURCE_INSTANCE_ALREADY_EXIST: { + code: 409, + message: "Error: Resource instances '%1' and '%2' are already associated with requirement '%3'.", + messageId: "SVC4118" + } +#-----------SVC4119--------------------------- +# %1 - resource instance name +# %2 - resource instance name +# %3 - requirement name + RESOURCE_INSTANCE_RELATION_NOT_FOUND: { + code: 404, + message: "Error: No relation found between resource instances '%1' and '%2' for requirement '%3'.", + messageId: "SVC4119" + } +#-----------SVC4120--------------------------- +# %1 - User's USER_ID + USER_INACTIVE: { + code: 404, + message: "Error: User %1 was not found.", + messageId: "SVC4120" + } +#-----------SVC4121--------------------------- +# %1 - User's USER_ID + USER_HAS_ACTIVE_ELEMENTS: { + code: 403, + message: "Error: User with %1 ID can not be deleted since it has active elements(resources/services/artifacts).", + messageId: "SVC4121" + } +#-----------SVC4122--------------------------- +# %1 - artifact type + ARTIFACT_TYPE_NOT_SUPPORTED: { + code: 400, + message: "Error: Invalid artifact type '%1'.", + messageId: "SVC4122" + } +#-----------SVC4123--------------------------- + ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: Artifact logical name cannot be changed.", + messageId: "SVC4123" + } +#-----------SVC4124--------------------------- + MISSING_ARTIFACT_TYPE: { + code: 400, + message: "Error: Missing artifact type.", + messageId: "SVC4124" + } +#-----------SVC4125--------------------------- +# %1-artifact name + ARTIFACT_EXIST: { + code: 400, + message: "Error: Artifact '%1' already exists.", + messageId: "SVC4125" + } +#---------SVC4126------------------------------ +# %1 - resource/service/product/... +# %2 - field (tag, vendor name...) + INVALID_FIELD_FORMAT: { + code: 400, + message: "Error: Invalid %1 %2 format.", + messageId: "SVC4126" + } +#-----------SVC4127--------------------------- + ARTIFACT_INVALID_MD5: { + code: 400, + message: "Error: Invalid artifact checksum.", + messageId: "SVC4127" + } +#-----------SVC4128--------------------------- + MISSING_ARTIFACT_NAME: { + code: 400, + message: "Error: Invalid content. Missing artifact name.", + messageId: "SVC4128" + } +#-----------SVC4129--------------------------- + MISSING_PROJECT_CODE: { + code: 400, + message: "Error: Invalid Content. Missing PROJECT_CODE number.", + messageId: "SVC4129" + } +#-----------SVC4130--------------------------- + INVALID_PROJECT_CODE: { + code: 400, + message: "Error: Invalid Content. PROJECT_CODE must be from 3 up to 50 characters.", + messageId: "SVC4130" + } +#-----------SVC4131--------------------------- +# %1-resource/service +# %2-srtifact/artifacts +# %3-semicolomn separated list of artifact + COMPONENT_MISSING_MANDATORY_ARTIFACTS: { + code: 403, + message: "Error: Missing mandatory informational %1 %2: [%3].", + messageId: "SVC4131" + } +#-----------SVC4132--------------------------- +# %1 - lifecycle type name + LIFECYCLE_TYPE_ALREADY_EXIST: { + code: 409, + message: "Error: Lifecycle Type with name '%1' already exists.", + messageId: "SVC4132" + } +#-----------SVC4133--------------------------- +# %1 - service version +# %2 - service name + SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION: { + code: 403, + message: "Error: Version %1 of '%2' service is not available for distribution.", + messageId: "SVC4133" + } +#-----------SVC4134--------------------------- + MISSING_LIFECYCLE_TYPE: { + code: 400, + message: "Error: Invalid Content. Missing interface life-cycle type.", + messageId: "SVC4134" + } +#---------SVC4135------------------------------ + SERVICE_CATEGORY_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: Service category cannot be changed once the service is certified.", + messageId: "SVC4135" + } +#---------SVC4136------------------------------ +# %1 - distribution environment name + DISTRIBUTION_ENVIRONMENT_NOT_AVAILABLE: { + code: 500, + message: "Error: Requested distribution environment '%1' is not available.", + messageId: "SVC4136" + } +#---------SVC4137------------------------------ +# %1 - distribution environment name + DISTRIBUTION_ENVIRONMENT_NOT_FOUND: { + code: 400, + message: "Error: Requested distribution environment '%1' was not found.", + messageId: "SVC4137" + } +#---------SVC4138------------------------------ + DISTRIBUTION_ENVIRONMENT_INVALID: { + code: 400, + message: "Error: Invalid distribution environment.", + messageId: "SVC4138" + } +#---------SVC4139------------------------------ +# %1 - service name + DISTRIBUTION_ARTIFACT_NOT_FOUND: { + code: 409, + message: "Error: Service '%1' cannot be distributed due to missing deployment artifacts.", + messageId: "SVC4139" + } +#---------SVC4200------------------------------ +# %1 - Service/Resource +# %2 - max icon name length + COMPONENT_ICON_EXCEEDS_LIMIT: { + code: 400, + message: "Error: Invalid Content. %1 icon name exceeds limit of %2 characters.", + messageId: "SVC4200" + } +#---------SVC4300------------------------------ + RESTRICTED_ACCESS: { + code: 403, + message: "Error: Restricted access.", + messageId: "SVC4300" + } +#---------SVC4301------------------------------ + RESTRICTED_OPERATION: { + code: 409, + message: "Error: Restricted operation.", + messageId: "SVC4301" + } +#---------SVC4500------------------------------ + MISSING_BODY: { + code: 400 , + message: "Error: Missing request body.", + messageId: "SVC4500" + } +#---------SVC4501------------------------------ + MISSING_PUBLIC_KEY: { + code: 400 , + message: "Error: Invalid Content. Missing mandatory parameter 'apiPublicKey'." , + messageId: "SVC4501" + } +#---------SVC4502------------------------------ + DISTRIBUTION_ENV_DOES_NOT_EXIST: { + code: 400 , + message: "Error: Invalid Body : Missing mandatory parameter 'distrEnvName'." , + messageId: "SVC4502" + } +#-----------SVC4503--------------------------- +# %1 - service name + SERVICE_NOT_FOUND: { + code: 404, + message: "Error: Requested '%1' service was not found.", + messageId: "SVC4503" + } + +#---------SVC4504------------------------------ +# %1 - Service/Resource +# %2 - service/resource version + COMPONENT_VERSION_NOT_FOUND: { + code: 404, + message: "Error: %1 version %2 was not found.", + messageId: "SVC4504" + } +#-----------SVC4505--------------------------- + #%1-artifact name + + ARTIFACT_NOT_FOUND: { + code: 404, + message: "Error: Artifact '%1' was not found.", + messageId: "SVC4505" + } +#---------SVC4506------------------------------ + MISSING_ENV_NAME: { + code: 400 , + message: "Error: Invalid Content. Missing mandatory parameter 'distrEnvName'.", + messageId: "SVC4506" + } +#---------SVC4507------------------------------ + COMPONENT_INVALID_TAGS_NO_COMP_NAME: { + code: 400, + message: "Error: Invalid Content. One of the tags should be the component name.", + messageId: "SVC4507" + } + +#---------SVC4508------------------------------ + SERVICE_NAME_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: Service name cannot be changed once the service is certified.", + messageId: "SVC4508" + } + +#---------SVC4509------------------------------ + SERVICE_ICON_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: Icon cannot be changed once the service is certified.", + messageId: "SVC4509" + } +#---------SVC4510------------------------------ +# %1 - icon name max length + SERVICE_ICON_EXCEEDS_LIMIT: { + code: 400, + message: "Error: Invalid Content. Icon name exceeds limit of %1 characters.", + messageId: "SVC4510" + } +#---------SVC4511------------------------------ + DISTRIBUTION_REQUESTED_NOT_FOUND: { + code: 404, + message: "Error: Requested distribution was not found.", + messageId: "SVC4511" + } +#---------SVC4512------------------------------ +# %1 - Distribution ID + DISTRIBUTION_REQUESTED_FAILED: { + code: 403, + message: "Error: Requested distribution '%1' failed.", + messageId: "SVC4512" + } +#---------SVC4513------------------------------ + RESOURCE_CATEGORY_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: Resource category cannot be changed once the resource is certified.", + messageId: "SVC4513" + } +#---------SVC4514------------------------------ + RESOURCE_NAME_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: Resource name cannot be changed once the resource is certified.", + messageId: "SVC4514" + } +#---------SVC4515------------------------------ + RESOURCE_ICON_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: Icon cannot be changed once the resource is certified.", + messageId: "SVC4515" + } +#---------SVC4516------------------------------ + RESOURCE_VENDOR_NAME_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: Vendor name cannot be changed once the resource is certified.", + messageId: "SVC4516" + } +#---------SVC4517------------------------------ + RESOURCE_DERIVED_FROM_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: Derived from resource template cannot be changed once the resource is certified.", + messageId: "SVC4517" + } +#---------SVC4518------------------------------ +# %1 - max length + COMPONENT_SINGLE_TAG_EXCEED_LIMIT: { + code: 400, + message: "Error: Invalid Content. Single tag exceeds limit of %1 characters.", + messageId: "SVC4518" + } +#---------SVC4519------------------------------ + INVALID_DEFAULT_VALUE: { + code: 400, + message: "Error: mismatch in data-type occurred for property %1. data type is %2 and default value found is %3.", + messageId: "SVC4519" + } +#---------SVC4520------------------------------ +# %1 - service or resource + ADDITIONAL_INFORMATION_MAX_NUMBER_REACHED: { + code: 409, + message: "Error: Maximal number of additional %1 parameters was reached.", + messageId: "SVC4520" + } +#---------SVC4521------------------------------ + ADDITIONAL_INFORMATION_EMPTY_STRING_NOT_ALLOWED: { + code: 400, + message: "Error: Invalid Content. The Additional information label and value cannot be empty.", + messageId: "SVC4521" + } +#---------SVC4522------------------------------ +# %1 - label/value +# %2 - Maximal length of %1 + ADDITIONAL_INFORMATION_EXCEEDS_LIMIT: { + code: 400, + message: "Error: Invalid Content. Additional information %1 exceeds limit of %2 characters.", + messageId: "SVC4522" + } +#---------SVC4523------------------------------ + ADDITIONAL_INFORMATION_KEY_NOT_ALLOWED_CHARACTERS: { + code: 400, + message: 'Error: Invalid Content. Additional information label is not allowed to contain characters like <>:"\/|?* and space characters other than regular space.', + messageId: "SVC4523" + } +#---------SVC4524------------------------------ + ADDITIONAL_INFORMATION_NOT_FOUND: { + code: 409, + message: "Error: Requested additional information was not found.", + messageId: "SVC4524" + } +#---------SVC4525------------------------------ + ADDITIONAL_INFORMATION_VALUE_NOT_ALLOWED_CHARACTERS: { + code: 400, + message: 'Error: Invalid Content. Additional information contains non-english characters.', + messageId: "SVC4525" + } +#---------SVC4526------------------------------ + RESOURCE_INSTANCE_NOT_FOUND: { + code: 404, + message: "Error: Requested '%1' resource instance was not found.", + messageId: "SVC4526" + } +#---------SVC4527------------------------------ + ASDC_VERSION_NOT_FOUND: { + code: 500, + message: 'Error: ASDC version cannot be displayed.', + messageId: "SVC4527" + } +#---------SVC4528------------------------------ +# %1-artifact url/artifact label/artifact description/VNF Service Indicator + MISSING_DATA: { + code: 400, + message: "Error: Invalid content. Missing %1.", + messageId: "SVC4528" + } +#---------SVC4529------------------------------ +# %1-artifact url/artifact label/artifact description/artifact name +# %2 - Maximal length of %1 + EXCEEDS_LIMIT: { + code: 400, + message: "Error: Invalid Content. %1 exceeds limit of %2 characters.", + messageId: "SVC4529" + } +#---------SVC4530------------------------------ + ARTIFACT_INVALID_TIMEOUT: { + code: 400, + message: "Error: Invalid Content. Artifact Timeout should be set to valid positive non-zero number of minutes.", + messageId: "SVC4530" + } +#---------SVC4531------------------------------ + SERVICE_IS_VNF_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: VNF Indicator cannot be updated for certified service.", + messageId: "SVC4531" + } + #---------SVC4532------------------------------ + RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE: { + code: 404, + message: "Error: Requested '%1' resource instance was not found on the service '%2.", + messageId: "SVC4532" + } + #---------SVC4533------------------------------ + # %1 - "HEAT"/"HEAT_ENV"/"MURANO_PKG"/"YANG_XML" + WRONG_ARTIFACT_FILE_EXTENSION: { + code: 400, + message: "Error: Invalid file extension for %1 artifact type.", + messageId: "SVC4533" + } + +#---------SVC4534------------------------------ +# %1 - "HEAT"/"HEAT_ENV" + INVALID_YAML: { + code: 400, + message: "Error: Uploaded YAML file for %1 artifact is invalid.", + messageId: "SVC4534" + } + +#---------SVC4535------------------------------ +# %1 - "HEAT" + INVALID_DEPLOYMENT_ARTIFACT_HEAT: { + code: 400, + message: "Error: Invalid %1 artifact.", + messageId: "SVC4535" + } +#---------SVC4536------------------------------ +# %1 - "Resource"/"Service" +# %2 - resource/service name +# %3 - "HEAT"/"HEAT_ENV"/"MURANO_PKG" +# %4 - "HEAT"/"HEAT_ENV"/"MURANO_PKG + DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS: { + code: 400, + message: "Error: %1 '%2' already has a deployment artifact of %3 type .Please delete or update an existing %4 artifact.", + messageId: "SVC4536" + } + +#---------SVC4537------------------------------ + MISSING_HEAT: { + code: 400, + message: "Error: Missing HEAT artifact. HEAT_ENV artifact cannot be uploaded without corresponding HEAT template.", + messageId: "SVC4537" + } +#---------SVC4538------------------------------ + MISMATCH_HEAT_VS_HEAT_ENV: { + code: 400, + message: "Error: Invalid artifact content. Parameter's set in HEAT_ENV '%1' artifact doesn't match the parameters in HEAT '%2' artifact.", + messageId: "SVC4538" + } +#---------SVC4539------------------------------ + INVALID_RESOURCE_PAYLOAD: { + code: 400, + message: "Error: Invalid resource payload.", + messageId: "SVC4539" + } +#---------SVC4540------------------------------ + INVALID_TOSCA_FILE_EXTENSION: { + code: 400, + message: "Error: Invalid file extension for TOSCA template.", + messageId: "SVC4540" + } +#---------SVC4541------------------------------ + INVALID_YAML_FILE: { + code: 400, + message: "Error: Invalid YAML file.", + messageId: "SVC4541" + } +#---------SVC4542------------------------------ + INVALID_TOSCA_TEMPLATE: { + code: 400, + message: "Error: Invalid TOSCA template.", + messageId: "SVC4542" + } +#---------SVC4543------------------------------ + NOT_RESOURCE_TOSCA_TEMPLATE: { + code: 400, + message: "Error: Imported Service TOSCA template.", + messageId: "SVC4543" + } +#---------SVC4544------------------------------ + NOT_SINGLE_RESOURCE: { + code: 400, + message: "Error: Imported TOSCA template should contain one resource definition.", + messageId: "SVC4544" + } +#---------SVC4545------------------------------ + INVALID_RESOURCE_NAMESPACE: { + code: 400, + message: "Error: Invalid resource namespace.", + messageId: "SVC4545" + } +#---------SVC4546------------------------------ + RESOURCE_ALREADY_EXISTS: { + code: 400, + message: "Error: Imported resource already exists in ASDC Catalog.", + messageId: "SVC4546" + } +#---------SVC4549------------------------------ + INVALID_RESOURCE_CHECKSUM: { + code: 400, + message: "Error: Invalid resource checksum.", + messageId: "SVC4549" + } +#---------SVC4550------------------------------ + #%1  -  Consumer salt + INVALID_LENGTH: { + code: 400, + message: "Error: Invalid %1 length.", + messageId: "SVC4550" + } + #---------SVC4551------------------------------ + #%1  -  ECOMP User name + ECOMP_USER_NOT_FOUND: { + code: 404, + message: "Error: ECOMP User '%1' was not found.", + messageId: "SVC4551" + } +#---------SVC4552------------------------------ + CONSUMER_ALREADY_EXISTS: { + code: 409, + message: "Error: ECOMP User already exists.", + messageId: "SVC4552" + } +#---------SVC4553----------------------------- + #%1  -  Consumer name / Consumer password/ Consumer salt + INVALID_CONTENT_PARAM: { + code: 400, + message: "Error: %1 is invalid.", + messageId: "SVC4553" + } + #---------SVC4554------------------------------ +# %1 - "Resource"/"Service" + COMPONENT_ARTIFACT_NOT_FOUND: { + code: 404, + message: "Error: Requested artifact doesn't belong to specified %1.", + messageId: "SVC4554" + } +#---------SVC4554------------------------------ +# %1 - "Service name" + SERVICE_DEPLOYMENT_ARTIFACT_NOT_FOUND: { + code: 403, + message: "Error: Requested '%1' service is not ready for certification. Service has to have at least one deployment artifact.", + messageId: "SVC4554" + } +#---------SVC4555------------------------------ +#%1 - "Resource"/"Service"/"Product" +#%2 - "category" + COMPONENT_ELEMENT_INVALID_NAME_LENGTH: { + code: 400, + message: "Error: Invalid %1 %2 name length.", + messageId: "SVC4555" + } +#---------SVC4556------------------------------ +#%1 - "Resource"/"Service"/"Product" +#%2 - "category" + COMPONENT_ELEMENT_INVALID_NAME_FORMAT: { + code: 400, + message: "Error: Invalid %1 %2 name format.", + messageId: "SVC4556" + } +#---------SVC4557------------------------------ +#%1 - "Resource"/"Service"/"Product" +#%2 - "category name" + COMPONENT_CATEGORY_ALREADY_EXISTS: { + code: 409, + message: "Error: %1 category name '%2' already exists.", + messageId: "SVC4557" + } +#---------SVC4558------------------------------ +# %1 - "service"/"VF" +# %2 - "Resource name" + VALIDATED_RESOURCE_NOT_FOUND: { + code: 403, + message: "Error: Submit for Testing is not permitted as your '%1' includes non-validated '%2' resource.", + messageId: "SVC4558" + } +#---------SVC4559------------------------------ +# %1 - "service"/"VF" +# %2 - "Resource name" + FOUND_ALREADY_VALIDATED_RESOURCE: { + code: 403, + message: "Error: Submit for Testing is not permitted as your '%1' includes non-validated '%2' resource. Please use already available validated resource version.", + messageId: "SVC4559" + } +#---------SVC4560------------------------------ +# %1 - "service"/"VF" +# %2 - "Resource name" + FOUND_LIST_VALIDATED_RESOURCES: { + code: 403, + message: "Error: Submit for Testing is not permitted as your '%1' includes non-validated '%2' resource. Please use one of available validated resource versions.", + messageId: "SVC4560" + } +#---------SVC4561------------------------------ +# %1 - "resource"/"product" +# %2 - "category" +# %3 - "category name" + COMPONENT_CATEGORY_NOT_FOUND: { + code: 404, + message: "Error: Requested %1 %2 '%3' was not found.", + messageId: "SVC4561" + } +#---------SVC4562------------------------------ +# %1 - "Resource"/"Product" +# %2 - "sub-category name" +# %3 - "category name" + COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY: { + code: 409, + message: "Error: %1 sub-category '%2' already exists under '%3' category.", + messageId: "SVC4562" + } +#---------SVC4563------------------------------ +# %1 - "Product" +# %2 - "grouping name" +# %3 - "sub-category name" + COMPONENT_GROUPING_EXISTS_FOR_SUB_CATEGORY: { + code: 409, + message: "Error: %1 grouping '%2' already exists under '%3' sub-category.", + messageId: "SVC4563" + } +#---------SVC4564------------------------------ +# %1 - product name + PRODUCT_NOT_FOUND: { + code: 404, + message: "Error: Requested '%1' product was not found.", + messageId: "SVC4564" + } +#---------SVC4565------------------------------ +# %1 - "HEAT" +# %2 - parameter type ("string" , "boolean" , "number") +# %3 - parameter name + INVALID_HEAT_PARAMETER_VALUE: { + code: 400, + message: "Error: Invalid %1 artifact. Invalid %2 value set for '%3' parameter.", + messageId: "SVC4565" + } +#---------SVC4566------------------------------ +# %1 - "HEAT" +# %2 - parameter type ("string" , "boolean" , "number") + INVALID_HEAT_PARAMETER_TYPE: { + code: 400, + message: "Error: Invalid %1 artifact. Unsupported '%2' parameter type.", + messageId: "SVC4566" + } +#---------SVC4567------------------------------ +# %1 - "YANG_XML" + INVALID_XML: { + code: 400, + message: "Error: Uploaded XML file for %1 artifact is invalid.", + messageId: "SVC4567" + } +#---------SVC4567------------------------------ +# %1 - "User Name and UserId" +# %2 -"checked-out"/"in-certification" + CANNOT_DELETE_USER_WITH_ACTIVE_ELEMENTS: { + code: 409, + message: "Error: User cannot be deleted. User '%1' has %2 projects.", + messageId: "SVC4567" + } +#---------SVC4568------------------------------ +# %1 - "User Name and UserId" +# %2 -"checked-out"/"in-certification" + CANNOT_UPDATE_USER_WITH_ACTIVE_ELEMENTS: { + code: 409, + message: "Error: Role cannot be changed. User '%1' has %2 projects.", + messageId: "SVC4568" + } +#---------SVC4570------------------------------ + UPDATE_USER_ADMIN_CONFLICT: { + code: 409, + message: "Error: An administrator is not allowed to change his/her role.", + messageId: "SVC4570" + } +#---------SVC4571------------------------------ + SERVICE_CANNOT_CONTAIN_SUBCATEGORY: { + code: 400, + message: "Error: Sub category cannot be defined for service", + messageId: "SVC4571" + } +#---------SVC4572------------------------------ +# %1 - "Resource"/"Service" + COMPONENT_TOO_MUCH_CATEGORIES: { + code: 400, + message: "Error: %1 must have only 1 category", + messageId: "SVC4572" + } +#---------SVC4574------------------------------ + RESOURCE_TOO_MUCH_SUBCATEGORIES: { + code: 400, + message: "Error: Resource must have only 1 sub category", + messageId: "SVC4574" + } +#---------SVC4575------------------------------ + COMPONENT_MISSING_SUBCATEGORY: { + code: 400, + message: "Error: Missing sub category", + messageId: "SVC4575" + } + #---------SVC4576------------------------------ +# %1 - "component type" + UNSUPPORTED_ERROR: { + code: 400, + message: "Error : Requested component type %1 is unsupported.", + messageId: "SVC4576" + } + #---------SVC4577------------------------------ +# %1 - "resource type" + RESOURCE_CANNOT_CONTAIN_RESOURCE_INSTANCES: { + code: 409, + message: "Error : Resource of type %1 cannot contain resource instances.", + messageId: "SVC4577" + } +#---------SVC4578------------------------------ +# %1 - "Resource"/"Service" +# %2 - resource/service name +# %3 - "artifact name" + DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS: { + code: 400, + message: "Error: %1 '%2' already has a deployment artifact named '%3'.", + messageId: "SVC4578" + } +#---------SVC4579------------------------------ +# %1 - "Category"/"Sub-Category"/"Group" +# %2 - category/sub-category/grouping name. + INVALID_GROUP_ASSOCIATION: { + code: 400, + message: "Error: Invalid group association. %1 '%2' was not found.", + messageId: "SVC4579" + } +#---------SVC4580------------------------------ + EMPTY_PRODUCT_CONTACTS_LIST: { + code: 400, + message: "Error: Invalid content. At least one Product Contact has to be specified.", + messageId: "SVC4580" + } +#---------SVC4581------------------------------ +# %1 - UserId + INVALID_PRODUCT_CONTACT: { + code: 400, + message: "Error: Invalid content. User '%1' cannot be set as Product Contact.", + messageId: "SVC4581" + } +#---------SVC4582------------------------------ +# %1 - Product +# %2 - "abbreviated"/"full" + MISSING_ONE_OF_COMPONENT_NAMES: { + code: 400, + message: "Error: Invalid content. Missing %1 %2 name.", + messageId: "SVC4582" + } +#---------SVC4583------------------------------ +# %1 - "Icon" +# %2 - "resource"/"service"/"product" + COMPONENT_PARAMETER_CANNOT_BE_CHANGED: { + code: 400, + message: "Error: %1 cannot be changed once the %2 is certified.", + messageId: "SVC4583" + } +#---------SVC4584------------------------------ +# %1 - service/VF name +# %2 - "service" /"VF" +# %3 - resource instance origin type +# %4 - resource instance name +# %5 - requirement/capability +# %6 - requirement/capability name +# %7 - "fulfilled" (for req)/"consumed (for cap)" + REQ_CAP_NOT_SATISFIED_BEFORE_CERTIFICATION: { + code: 403, + message: "Error: Requested '%1' %2 is not ready for certification. %3 '%4' has to have %5 '%6' %7.", + messageId: "SVC4584" + } +#---------SVC4585------------------------------ + INVALID_OCCURRENCES: { + code: 400, + message: "Error: Invalid occurrences format.", + messageId: "SVC4585" + } +#---------SVC4586------------------------------ +#---------SVC4586------------------------------ + INVALID_SERVICE_API_URL: { + code: 400, + message: 'Error: Invalid Service API URL. Please check whether your URL has a valid domain extension and does not contain the following characters - #?&@%+;,=$<>~^`\[]{}|"*!', + messageId: "SVC4586" + } +#---------SVC4587------------------------------ +# %1 - Data type name + DATA_TYPE_ALREADY_EXIST: { + code: 409, + message: 'Error: Data type %1 already exists.', + messageId: "SVC4587" + } +#---------SVC4588------------------------------ +# %1 - Data type name + DATA_TYPE_NOR_PROPERTIES_NEITHER_DERIVED_FROM: { + code: 400, + message: 'Error: Invalid Data type %1. Data type must have either a valid derived from declaration or at least one valid property', + messageId: "SVC4588" + } +#---------SVC4589------------------------------ +# %1 - Data type name + DATA_TYPE_PROPERTIES_CANNOT_BE_EMPTY: { + code: 400, + message: "Error: Invalid Data type %1. 'properties' parameter cannot be empty if provided.", + messageId: "SVC4589" + } +#---------SVC4590------------------------------ +# %1 - Property type name +# %2 - Property name + INVALID_PROPERTY_TYPE: { + code: 400, + message: "Error: Invalid Property type %1 in property %2.", + messageId: "SVC4590" + } +#---------SVC4591------------------------------ +# %1 - Property inner type +# %2 - Property name + INVALID_PROPERTY_INNER_TYPE: { + code: 400, + message: "Error: Invalid property inner type %1, in property %2", + messageId: "SVC4591" + } +#---------SVC4592------------------------------ +# %1 - component instance name +# %2 - "resource instance"/"service instance" + COMPONENT_INSTANCE_NOT_FOUND: { + code: 404, + message: "Error: Requested '%1' %2 was not found.", + messageId: "SVC4592" + } +#---------SVC4593------------------------------ +# %1 - component instance name +# %2 - "resource instance"/"service instance" +# %3 - "resource/"service"/"product" +# %4 - container name + COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER: { + code: 404, + message: "Error: Requested '%1' %2 was not found on the %3 '%4'.", + messageId: "SVC4593" + } +#---------SVC4594------------------------------ +#%1 - requirement / capability +#%2 - requirement name + IMPORT_DUPLICATE_REQ_CAP_NAME: { + code: 400, + message: "Error: Imported TOSCA template contains more than one %1 named '%2'.", + messageId: "SVC4594" + } +#---------SVC4595------------------------------ +#%1 - requirement / capability +#%2 - requirement name +#%3 - parent containing the requirement + IMPORT_REQ_CAP_NAME_EXISTS_IN_DERIVED: { + code: 400, + message: "Error: Imported TOSCA template contains %1 '%2' that is already defined by derived template %3.", + messageId: "SVC4595" + } +#---------SVC4596------------------------------ +# %1 - Data type name + DATA_TYPE_DERIVED_IS_MISSING: { + code: 400, + message: "Error: Invalid Content. The ancestor data type %1 cannot be found in the system.", + messageId: "SVC4596" + } +#---------SVC4597------------------------------ +# %1 - Data type name +# %2 - Property names + DATA_TYPE_PROPERTY_ALREADY_DEFINED_IN_ANCESTOR: { + code: 400, + message: "Error: Invalid Content. The data type %1 contains properties named %2 which are already defined in one of its ancestors.", + messageId: "SVC4597" + } +#---------SVC4598------------------------------ +# %1 - Data type name + DATA_TYPE_DUPLICATE_PROPERTY: { + code: 400, + message: "Error: Invalid Content. The data type %1 contains duplicate property.", + messageId: "SVC4598" + } +#---------SVC4599------------------------------ +# %1 - Data type name +# %2 - Property names + DATA_TYPE_PROEPRTY_CANNOT_HAVE_SAME_TYPE_OF_DATA_TYPE: { + code: 400, + message: "Error: Invalid Content. The data type %1 contains properties %2 which their type is this data type.", + messageId: "SVC4599" + } +#---------SVC4600------------------------------ +# %1 - Data type name + DATA_TYPE_CANNOT_HAVE_PROPERTIES: { + code: 400, + message: "Error: Invalid Content. The data type %1 cannot have properties since it is of type scalar", + messageId: "SVC4600" + } +#---------SVC4601------------------------------ + NOT_TOPOLOGY_TOSCA_TEMPLATE: { + code: 400, + message: "Error: TOSCA yaml file %1 cannot be modeled to VF as it does not contain 'topology_template.", + messageId: "SVC4601" + } +#---------SVC4602-------------------------------- +# %1 - yaml file name +# %2 - node_template label +# %3 - node_template type + INVALID_NODE_TEMPLATE: { + code: 400, + message: "Error: TOSCA yaml file '%1' contains node_template '%2' of type '%3' that does not represent existing VFC/CP/VL", + messageId: "SVC4602" + } +#---------SVC4603------------------------------ +# %1 - component type +# %2 - component name +# %3 - state + ILLEGAL_COMPONENT_STATE: { + code: 403, + message: "Error: Component instance of %1 can not be created because the component '%2' is in an illegal state %3.", + messageId: "SVC4603" + } +#---------SVC4604------------------------------ +# %1 - csar file name + CSAR_INVALID: { + code: 400, + message: "Error: TOSCA CSAR '%1' is invalid. 'TOSCA-Metadata/Tosca.meta' file must be provided.", + messageId: "SVC4604" + } +#---------SVC4605------------------------------ +# %1 - csar file name + CSAR_INVALID_FORMAT: { + code: 400, + message: "Error: TOSCA CSAR '%1' is invalid. Invalid 'TOSCA-Metadata/Tosca.meta' file format.", + messageId: "SVC4605" + } +#---------SVC4606------------------------------ +# %1 - property name +# %2 - property type +# %3 - property innerType +# %4 - default value is + INVALID_COMPLEX_DEFAULT_VALUE: { + code: 400, + message: "Error: Invalid default value of property %1. Data type is %2 with inner type %3 and default value found is %4.", + messageId: "SVC4606" + } +#---------SVC4607------------------------------ +# %1 - csar file name + CSAR_NOT_FOUND: { + code: 400, + message: "Error: TOSCA CSAR '%1' is not found.", + messageId: "SVC4607" + } +#---------SVC4608------------------------------ +# %1 - artifact name +# %2 - component type +# %3 - actual component type + MISMATCH_BETWEEN_ARTIFACT_TYPE_AND_COMPONENT_TYPE: { + code: 400, + message: "Error: Artifact %1 is only compatible with component of type %2, but component type is %3.", + messageId: "SVC4608" + } + +#---------SVC4609------------------------------ +# %1 - "INVALID_JSON" + INVALID_JSON: { + code: 400, + message: "Error: Uploaded JSON file for %1 artifact is invalid.", + messageId: "SVC4609" + } +#---------SVC4610------------------------------ +# %1 - csar file name +# %2 - missing file name + YAML_NOT_FOUND_IN_CSAR: { + code: 400, + message: "Error - TOSCA CSAR %1 is invalid. TOSCA-Metadata/Tosca.meta refers to file %2 that is not provided.", + messageId: "SVC4610" + } +#---------SVC4611------------------------------ +# %1 - group name + GROUP_MEMBER_EMPTY: { + code: 400, + message: "Error: Invalid Content. Group %1 member list was provided but does not have values", + messageId: "SVC4611" + } +#---------SVC4612------------------------------ +# %1 - group name + GROUP_TYPE_ALREADY_EXIST: { + code: 409, + message: 'Error: Group type %1 already exists.', + messageId: "SVC4612" + } +#---------SVC4613------------------------------ +# %1 - group name +# %2 - VF name(component name) +# %3 - actual component type [VF] + GROUP_ALREADY_EXIST: { + code: 409, + message: "Error: Group with name '%1' already exists in %2 %3.", + messageId: "SVC4613" + } +#---------SVC4614------------------------------ +# %1 - group type + GROUP_TYPE_IS_INVALID: { + code: 400, + message: "Error: Invalid content. Group type %1 does not exist", + messageId: "SVC4614" + } +#---------SVC4615------------------------------ +# %1 - group name + GROUP_MISSING_GROUP_TYPE: { + code: 400, + message: "Error: Invalid Content. Missing Group Type for group '%1'", + messageId: "SVC4615" + } +#---------SVC4616------------------------------ +# %1 - member name +# %2 - group name +# %3 - VF name +# %4 - component type [VF ] + GROUP_INVALID_COMPONENT_INSTANCE: { + code: 400, + message: "Error: Member '%1' listed in group '%2' is not part of '%3' %4.", + messageId: "SVC4616" + } +#---------SVC4617------------------------------ +# %1 - member name +# %2 - group name +# %3 - group type + GROUP_INVALID_TOSCA_NAME_OF_COMPONENT_INSTANCE: { + code: 400, + message: "Error: member %1 listed in group %2 is not part of allowed members of group type %3.", + messageId: "SVC4617" + } +#---------SVC4618------------------------------ +# %1 - missing file name +# %2 - csar file name + ARTIFACT_NOT_FOUND_IN_CSAR: { + code: 400, + message: "Error: artifact %1 is defined in CSAR %2 manifest but is not provided", + messageId: "SVC4618" + } +#---------SVC4619------------------------------ +# %1 - artifact name +# %2 - artifact type +# %3 - existing artifact type + ARTIFACT_ALRADY_EXIST_IN_DIFFERENT_TYPE_IN_CSAR: { + code: 400, + message: "Error: artifact %1 in type %2 already exists in type %3.", + messageId: "SVC4619" + } +#---------SVC4620------------------------------ + FAILED_RETRIVE_ARTIFACTS_TYPES: { + code: 400, + message: "Error: Failed to retrieve list of suported artifact types.", + messageId: "SVC4620" + } +#---------SVC4621------------------------------ +# %1 - artifact name +# %2 - master + ARTIFACT_ALRADY_EXIST_IN_MASTER_IN_CSAR: { + code: 400, + message: "Error: artifact %1 already exists in master %2 .", + messageId: "SVC4621" + } +#---------SVC4622------------------------------ +# %1 - artifact name +# %2 - artifact type +# %3 - master name +# %4 - master type + ARTIFACT_NOT_VALID_IN_MASTER: { + code: 400, + message: "Error: artifact %1 in type %2 can not be exists under master %3 in type %4.", + messageId: "SVC4622" + } +#---------SVC4623------------------------------ +# %1 - artifact name +# %2 - artifact type +# %3 - env name +# %4 - existing env + ARTIFACT_NOT_VALID_ENV: { + code: 400, + message: "Error: Artifact %1 in type %2 with env %3 already exists with another env %4", + messageId: "SVC4623" + } +#---------SVC4624------------------------------ +# %1 - groups names +# %2 - VF name +# %3 - component type [VF ] + GROUP_IS_MISSING: { + code: 400, + message: "Error: Invalid Content. The groups '%1' cannot be found under %2 %3.", + messageId: "SVC4624" + } +#---------SVC4625------------------------------ +# %1 - groups name + GROUP_ARTIFACT_ALREADY_ASSOCIATED: { + code: 400, + message: "Error: Invalid Content. Artifact already associated to group '%1'.", + messageId: "SVC4625" + } +#---------SVC4626------------------------------ +# %1 - groups name + GROUP_ARTIFACT_ALREADY_DISSOCIATED: { + code: 400, + message: "Error: Invalid Content. Artifact already dissociated from group '%1'.", + messageId: "SVC4626" + } +#---------SVC4627------------------------------ +# %1 - property name +# %2 - group name +# %3 - group type name + GROUP_PROPERTY_NOT_FOUND: { + code: 400, + message: "Error: property %1 listed in group %2 is not exist in group type %3.", + messageId: "SVC4627" + } +#---------SVC4628------------------------------ +# %1 - csarUUID +# %2 - VF name + VSP_ALREADY_EXISTS: { + code: 400, + message: "Error: The VSP with UUID %1 was already imported for VF %2. Please select another or update the existing VF.", + messageId: "SVC4628" + } +#---------SVC4629------------------------------ +# %1 - VF name + MISSING_CSAR_UUID: { + code: 400, + message: "Error: The Csar UUID or payload name is missing for VF %1.", + messageId: "SVC4629" + } +#---------SVC4630------------------------------ +# %1 - VF name +# %2 - new csarUUID +# %3 - old csarUUID + RESOURCE_LINKED_TO_DIFFERENT_VSP: { + code: 400, + message: "Error: Resource %1 cannot be updated using CsarUUID %2 since the resource is linked to a different VSP with csarUUID %3.", + messageId: "SVC4630" + } +#---------SVC4631------------------------------ +# %1 - policy name + POLICY_TYPE_ALREADY_EXIST: { + code: 409, + message: "Error: Policy type %1 already exists.", + messageId: "SVC4631" + } +#---------SVC4632------------------------------ +# %1 - target name +# %2 - policy type name + TARGETS_NON_VALID: { + code: 400, + message: "Error: target %1 listed in policy type %2 is not a group or resource.", + messageId: "SVC4632" + } +#---------SVC4633------------------------------ +# %1 - policy name + TARGETS_EMPTY: { + code: 400, + message: "Error: Invalid Content. Policy %1 target list was provided but does not have values", + messageId: "SVC4633" + } +#---------SVC4634------------------------------ + DATA_TYPE_CANNOT_BE_EMPTY: { + code: 500, + message: "Error: Data types are empty. Please import the data types.", + messageId: "SVC4634" + } +#---------SVC4635------------------------------ +# %1 - csar uuid + RESOURCE_FROM_CSAR_NOT_FOUND: { + code: 400, + message: "Error: resource from csar uuid %1 not found", + messageId: "SVC4635" + } +#---------SVC4636------------------------------ +# %1 - Data type name + DATA_TYPE_CANNOT_BE_UPDATED_BAD_REQUEST: { + code: 400, + message: 'Error: Data type %1 cannot be upgraded. The new data type does not contain old properties or the type of one of the properties has been changed.', + messageId: "SVC4636" + } +#-----------SVC4637--------------------------- +#%1 - attribute name + ATTRIBUTE_NOT_FOUND: { + code: 404, + message: "Error: Requested '%1' attribute was not found.", + messageId: "SVC4637" + } +#-----------SVC4638--------------------------- +#%1 - attribute name + ATTRIBUTE_ALREADY_EXIST: { + code: 409, + message: "Error: Attribute with '%1' name already exists.", + messageId: "SVC4638" + } +#-----------SVC4639--------------------------- +#%1 - property name + PROPERTY_NAME_ALREADY_EXISTS: { + code: 409, + message: "Error: Property with '%1' name and different type already exists.", + messageId: "SVC4639" + } +#-----------SVC4640--------------------------- +#%1 - property name + INVALID_PROPERTY: { + code: 409, + message: "Error: Invalid property received.", + messageId: "SVC4640" + } +#---------SVC4641----------------------------- +#%1 - invalid filter +#%2 - valid filters + INVALID_FILTER_KEY: { + code: 400, + message: "Error: The filter %1 is not applicable. Please use one of the following filters: %2", + messageId: "SVC4641" + } +#---------SVC4642----------------------------- +#%1 - asset type +#%2 - filter + NO_ASSETS_FOUND: { + code: 404, + message: "No %1 were found to match criteria %2", + messageId: "SVC4642" + } +#---------SVC4643------------------------------ +# %1 - "Resource"/"Product" +# %2 - "sub-category name" +# %3 - "category name" + COMPONENT_SUB_CATEGORY_NOT_FOUND_FOR_CATEGORY: { + code: 404, + message: "Error: %1 sub-category '%2' not found under category '%3'.", + messageId: "SVC4643" + } +#---------SVC4644------------------------------ +# %1 - Format + CORRUPTED_FORMAT: { + code: 400, + message: "Error: %1 format is corrupted.", + messageId: "SVC4644" + } +#---------SVC4645------------------------------ +# %1 - "groupType" + INVALID_VF_MODULE_TYPE: { + code: 400, + message: "Error: Invalid group type '%1' (should be VfModule).", + messageId: "SVC4645" + } +#---------SVC4646------------------------------ +# %1 - "groupName" + INVALID_VF_MODULE_NAME: { + code: 400, + message: "Error: Invalid Content. VF Module name '%1' contains invalid characters", + messageId: "SVC4646" + } + +#---------SVC4647------------------------------ +# %1 - "modifiedName" + INVALID_VF_MODULE_NAME_MODIFICATION: { + code: 400, + message: "Error: Invalid VF Module name modification, can not modify '%1'", + messageId: "SVC4647" + } +#---------SVC4648------------------------------ +# %1 - "inputId" +# %2 - "componentId" + INPUT_IS_NOT_CHILD_OF_COMPONENT: { + code: 400, + message: "Error: Input id: '%1' is not child of component id: '%2'", + messageId: "SVC4648" + } +#---------SVC4649------------------------------ +# %1 - "groupName" + GROUP_HAS_CYCLIC_DEPENDENCY: { + code: 400, + message: "Error: The group '%1' has cyclic dependency", + messageId: "SVC4649" + } +#---------SVC4650------------------------------ +# %1 - "Component Type" +# %2 - +# %3 - error description + AAI_ARTIFACT_GENERATION_FAILED: { + code: 500, + message: "Error: %1 %2 automatic generation of artifacts failed. Description: %3", + messageId: "SVC4650" + } +#---------SVC4651------------------------------ + PARENT_RESOURCE_DOES_NOT_EXTEND: { + code: 400, + message: "Error: Once resource is certified, derived_from can be changed only to a sibling", + messageId: "SVC4651" + } +#---------SVC4652------------------------------ +# %1 - resource/service + COMPONENT_INVALID_SUBCATEGORY: { + code: 400, + message: "Error: Invalid Content. Invalid %1 sub category.", + messageId: "SVC4652" + } +#---------SVC4653------------------------------ +# %1 - group instance uniqueId +# %2 - service uniqueId + GROUP_INSTANCE_NOT_FOUND_ON_COMPONENT_INSTANCE: { + code: 404, + message: "Error: Requested group instance %1 was not found on component %2.", + messageId: "SVC4653" + } +#---------SVC4654------------------------------ +# %1 - group property name +# %2 - valid min limit value +# %3 - valid max limit value + INVALID_GROUP_MIN_MAX_INSTANCES_PROPERTY_VALUE: { + code: 400, + message: "Error: Value of %1 must be not higher than %2, and not lower than %3.", + messageId: "SVC4654" + } +#---------SVC4655------------------------------ +# %1 - group property name +# %2 - valid min limit value +# %3 - valid max limit value + INVALID_GROUP_INITIAL_COUNT_PROPERTY_VALUE: { + code: 400, + message: "Error: Value of %1 must be between %2 and %3.", + messageId: "SVC4655" + } +#---------SVC4656------------------------------ +# %1 - group property name +# %2 - lower/higher +# %3 - valid max/min value + INVALID_GROUP_PROPERTY_VALUE_LOWER_HIGHER: { + code: 400, + message: "Error: Value of %1 must be %2 or equals to %3.", + messageId: "SVC4656" + } +#---------SVC4657------------------------------ +# %1 - certificationRequest / startTesting + RESOURCE_VFCMT_LIFECYCLE_STATE_NOT_VALID: { + code: 400, + message: "Error - Lifecycle state %1 is not valid for resource of type VFCMT", + messageId: "SVC4657" + } +#---------SVC4658------------------------------ +# %1 – asset type [service / resource ] +# %2 – main asset uuid +# %3 – not found asset type [service / resource] +# %4 – not found asset name + ASSET_NOT_FOUND_DURING_CSAR_CREATION: { + code: 400, + message: "Error: CSAR packaging failed for %1 %2. %3 %4 was not found", + messageId: "SVC4658" + } +#---------SVC4659------------------------------ +# %1 – asset type [service / resource ] +# %2 – main asset uuid +# %3 – Artifact name +# %4 – Artifact uuid + ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION: { + code: 400, + message: " Error: CSAR packaging failed for %1 %2. Artifact %3 [%4] was not found", + messageId: "SVC4659" + } +#---------SVC4660------------------------------ +# %1 - assetType +# %2 - matching generic node type name + GENERIC_TYPE_NOT_FOUND: { + code: 404, + message: "Creation of %1 failed. Generic type %2 was not found", + messageId: "SVC4660" + } diff --git a/test-apis-ci/src/test/resources/CI/importTypesTest/categoryTypesTest.yml b/test-apis-ci/src/test/resources/CI/importTypesTest/categoryTypesTest.yml new file mode 100644 index 0000000000..120f33d5f1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/importTypesTest/categoryTypesTest.yml @@ -0,0 +1,23 @@ +services: + Mobility: + name: "Mobility1" + icons: ['mobility'] + Network_L1_3: + name: "Network L1-31" + icons: ['network_l_1-3'] +resources: + NetworkLayer23: + name: "Network Layer 2-31" + subcategories: + Router: + name: "Router" + icons: ['router'] + Gateway: + name: "Gateway" + icons: ['gateway'] + WAN_Connectors: + name: "WAN Connectors" + icons: ['connector'] + LAN_Connectors: + name: "LAN Connectors" + icons: ['connector'] diff --git a/test-apis-ci/src/test/resources/CI/importTypesTest/categoryTypesTest.zip b/test-apis-ci/src/test/resources/CI/importTypesTest/categoryTypesTest.zip new file mode 100644 index 0000000000000000000000000000000000000000..68b7aa91141891ca3284a1cf6c811b0803438750 GIT binary patch literal 333 zcmWIWW@Zs#U|`^2xY(xdQQG|b<3S)#hKYee6i6p0mZYZV7gdH-7Ni!3q!yRxRp#bQ zJ-?B!$v~jt;oapsHW*kkNY5@TSjnTucT6BdZ;9ZoCs8VU_KNbUcqF~K_V4ZS#EJ8~ z7WtMxxPEiWs<3tP^v7go;wF)o#xj4T>EzMb5@ z_-EqW-){_^vZEgD{IOD_YRQbdTYu#VoZph`9ci(KM>C(H{#{a3y9w{Mgku6ahioKy zJOA@Pcye{!3v(X5*&e3bB6rGd`jfH6?Iq7m-ZSwH=UaV){VKzb>WBVWzKX00Q?plh&s15q0z;?#paUA3 zo824t&#U3@6U<|LS}ZqGTRJ5-`3&Ssgdlp!we zKJm#(&8V8ss*Otz9G+S%dHUDnPQ!@6a}`e9uA8@P_f> oFfvFmEdTImzT=gPjMil}I>>Z@H!B-RJ0lP#0cizw%dquCLm=m+{5Km+Zgu&Kqu75V$9L%Wa9RUPp{oms)K75K?ucS=wFV z43~sz+Bc04))V9p7&7@TU~byc5UQfOp@NlX{)tP6erslTrQN@Ce8MKB8WG<|GbT(8 zNOPK@yUVtBtAV|(T27+M#i*T&Vx|Yowg~QY@%Ou!)Z5GQO!d9qi&L9x_Zb_0E8{s= zu}Z8n?eM+5xn}yeuODw;+Bo^sMq&Gef~oJ$qzC(4UKnQFKi527TERR{XVaa%< + + + + Lionel Andres Messi + 1987-06-24T00:00:00-00:00 + + + Cristiano Ronaldo + 1985-02-05T00:00:00-00:00 + + + FC Barcelona + + Lionel Andres Messi + Champions League 2014-2015 + 10 + 43 + + + + Real Madrid + + Cristiano Ronaldo + Champions League 2014-2015 + 7 + 48 + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat 0 2.yaml b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat 0 2.yaml new file mode 100644 index 0000000000..6835485ca1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat 0 2.yaml @@ -0,0 +1,787 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +# availability_zone_smp0: +# type: string +# default: nova +# availability_zone_smp1: +# type: string +# default: nova +# availability_zone_fe0: +# type: string +# default: nova +# availability_zone_fe1: +# type: string +# default: nova +# availability_zone_db0: +# type: string +# default: nova +# availability_zone_db1: +# type: string +# default: nova +# availability_zone_be0: +# type: string +# default: nova +# availability_zone_be1: +# type: string +# default: nova +# availability_zone_be2: +# type: string +# default: nova +# availability_zone_be3: +# type: string +# default: nova +# availability_zone_be4: +# type: string +# default: nova + + vnf_name: + type: string + description: Unique name for this VNF instance + default: This_is_the_SCP_name + vnf_id: + type: string + description: Unique ID for this VNF instance + default: This_is_ths_SCP_id + + flavor_scp_be_id: + type: string + description: flavor type + default: a1.Small + flavor_scp_fe_id: + type: string + description: flavor type + default: a1.Small + flavor_smp_id: + type: string + description: flavor type + default: a1.Small + flavor_db_id: + type: string + description: flavor type + default: a1.Small + image_scp_be_id: + type: string + description: Image use to boot a server + default: asc_base_image_be + image_scp_fe_id: + type: string + description: Image use to boot a server + default: asc_base_image_fe + image_smp_id: + type: string + description: Image use to boot a server + default: asc_base_image_smp + image_db_id: + type: string + description: Image use to boot a server + default: asc_base_image_db + + int_vscp_fe_cluster_net_id: + type: string + description: LAN2 FE Cluster/KA + int_vscp_fe_cluster_cidr: + type: string + description: Private Network2 Address (CIDR notation) + int_vscp_cluster_net_id: + type: string + description: LAN3 Cluster + int_vscp_cluster_cidr: + type: string + description: Private Network3 Address (CIDR notation) + int_vscp_db_network_net_id: + type: string + description: LAN4 DB + int_vscp_db_network_cidr: + type: string + description: Private Network4 Address (CIDR notation) + SIGNET_vrf_A1_direct_net_id: + type: string + description: Network name for SIGTRAN_A + SIGNET_vrf_B1_direct_net_id: + type: string + description: Network name for SIGTRAN_B + Cricket_OCS_protected_net_id: + type: string + description: Network name for CRICKET_OCS + OAM_direct_net_id: + type: string + description: Network name for OAM + be0_Cricket_OCS_protected_ips: + type: string + label: be0 port 5 OAM ip address + description: be0 port 5 OAM ip address + be1_Cricket_OCS_protected_ips: + type: string + label: be1 port 5 OAM ip address + description: be1 port 5 OAM ip address + be2_Cricket_OCS_protected_ips: + type: string + label: be2 port 5 OAM ip address + description: be2 port 5 OAM ip address + be3_Cricket_OCS_protected_ips: + type: string + label: be3 port 5 OAM ip address + description: be3 port 5 OAM ip address + be4_Cricket_OCS_protected_ips: + type: string + label: be4 port 5 OAM ip address + description: be4 port 5 OAM ip address + be0_OAM_direct_ips: + type: string + label: be0 port 7 OAM ip address + description: be0 port 7 OAM ip address + be1_OAM_direct_ips: + type: string + label: be1 port 7 OAM ip address + description: be1 port 7 OAM ip address + be2_OAM_direct_ips: + type: string + label: be2 port 7 OAM ip address + description: be2 port 7 OAM ip address + be3_OAM_direct_ips: + type: string + label: be3 port 7 OAM ip address + description: be3 port 7 OAM ip address + be4_OAM_direct_ips: + type: string + label: be4 port 7 OAM ip address + description: be4 port 7 OAM ip address + fe0_SIGNET_vrf_A1_direct_ips: + type: string + label: fe0 port 0 SIGTRAN ip address + description: fe0 port 0 SIGTRAN ip address + fe0_OAM_direct_ips: + type: string + label: fe0 port 7 OAM ip address + description: fe0 port 7 OAM ip address + fe1_SIGNET_vrf_B1_direct_ips: + type: string + label: fe1 port 1 SIGTRAN ip address + description: fe1 port 1 SIGTRAN ip address + fe1_OAM_direct_ips: + type: string + label: fe1 port 7 OAM ip address + description: fe1 port 7 OAM ip address + smp0_OAM_direct_ips: + type: string + label: smp0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + smp1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: smp1 port 7 OAM ip address + db0_OAM_direct_ips: + type: string + label: db0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + db1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: db1 port 7 OAM ip address + vm_scp_be0_name: + type: string + default: vSCP_BE0 + description: name of VM + vm_scp_be1_name: + type: string + default: vSCP_BE1 + description: name of VM + vm_scp_be2_name: + type: string + default: vSCP_BE2 + description: name of VM + vm_scp_be3_name: + type: string + default: vSCP_BE3 + description: name of VM + vm_scp_be4_name: + type: string + default: vSCP_BE4 + description: name of VM + vm_scp_fe0_name: + type: string + default: vSCP_FE0 + description: name of VM + vm_scp_fe1_name: + type: string + default: vSCP_FE1 + description: name of VM + vm_smp0_name: + type: string + default: vSMP0 + description: name of VM + vm_smp1_name: + type: string + default: vSMP1 + description: name of VM + vm_db0_name: + type: string + default: vDB0 + description: name of VM + vm_db1_name: + type: string + default: vDB1 + description: name of VM + +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat 0 2.zip b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat 0 2.zip new file mode 100644 index 0000000000000000000000000000000000000000..c8a27264212fbd851ba05dc5a100fa5770b237a8 GIT binary patch literal 2420 zcmZ{mdpr{g8^<@fH+Qo4v}40aDq`-k+2&GaE=TUiZC*2%5oVz!VVY|~BBhPu91ae1 zI^y7M%|?caT7Sz ziO3g70stz00D!{5HYhGQfD{r$ft`jK>Lmt|BbR)~>W5CtU$&ox3N(OIJku{2-$61xqrD=jg+2lNm>LEn9C+F0wXR`(&ql_Jy6&xoyO~ zU7OB|eAstd46`Za%L(3$4)7mIDR<;6rFO1iI34yqFO;?5j3c6&{M8E4uQRG#4KA=6 z)P7EbwmCUa!VH!C+JB2HB^_e%og6wo3z8$H7lk|wkyTiObA#u}^4Q~XiX&xwNymIH zrtnsDk{tiZ)RURYsVDsF!oJfO_&LC;vV6Z;*1hz}rz#h~hwt(8rk&fl*S)h~KdF`4 zA%wS5@3`pb2XNrfdw6c3A!a4(-HcqY1OyIJCeHX}*Ys6}SEFAJlt1o*=^aTZ2Gqy9!M7335Z(LjA2WeiZ#`u@<=U%UGhs0QpO>8^PHw+7S1^9f}*H znG`pd#AXL-Z5H<5u`L??Srwa;PJUb2GFE_*i&AUY%O zAX=?gi!ShDDjDh$58%M^m(4{<4?o;zmR<)a;R>5(q9Y0v_b6c=;l%NA(WAIDL&V64 z8g&&vcTM209J5YbRsJH(2uF`1&#PL9I6>!wSCG)iq4!&63PW4kpH!`%Ex7ytwm?dW z!8}u*gjgNzqziZuy@ZJ8KlpyM%cQxNS`e|42tk}{X%EMQr7=-aV?|<1t-T&A^t?Vb zmYqI+sE>!#-@fmnYF8}a7fTWb|l%(Cn=*O=TvLhc^)Qag7TfK;zwvM-&_5%u@RT)bS z`4oovjW_EB`9vF%&z70M9gpIx@L@w$>F>n7rF$cDFT$;bu?p)rZIXxv%=y8KGdI0f zbDNY$c68BCyI5X>w@DCcx7$0JvsxyBl_!;Zn&JRh?lG2Y3F_uLB!kg5bu!1#`$c1$ z{y^g;7e0EII%ezgN7%+uIfEM2yJ9FMF!KEinR#0eo0*(gJX^ckJ7QP>tqXfG-~3^= zMaH}@qlM_^#6DhA`m}F0_>=ejSoW7MH?;4YGrEACG|dbXMi;AtrkSqP#yQQ$suzu_ zh?}b|a}u@`7vGS|6YiTu==bM!SR&c&I$R`_om{h(MDTWIJs@~P(c$N%RSaD=c<`WP zR(?Pt0%*5q7r->rJLMC>i~ZNyMf2|LH|l0F(TQnWz|1!ndKWg?W$QB->wCls*rW59 zHcH9z1+QpoiLNDt>z81%@WAD;j*phKi6-gT2BNC{fxKIy>IT;~9Y{u?};D4x{DJs$DTI5icIdiS6|L!l) z5#49Moltl!iM~vR4)54r>2=+C=>{-WJ>l9w(yfRc{aDA3vdqGY{~CoqnZBProiK`j z87?uelA?z(QF}_SNp1VCu0r3fqu;11BgE8HTir?FRRbc|5pFtF;b8hXV<_Vz@k(@$ z@p{x6uY3RE5-vCd8++NYj_jLRJyrB-3xqMD3#-P=$_*ownjO>@qFKz_L%N3Ti&ku8 zIiHSdlv(ri8Y#+eKc;@Evw%KbZ8jRz|Lkg0Lxg|l7T#1vM8}!-F*DMycHM}-MXW{+pUD6uK@X_`r@BJ%5UF3L8M3@+Dx}z!kHy;UCJ3$c0<5l(1 z^`<=@newFU7^0i9mpd?DRaea082+s7Fs@acq*q^REEh;U^D=z7{Pv^u__0x{@43T! z*DJ1EMecUI=Tl>L;^N6wWxj+f`^i%uU+?)_{hZf%{*|YXgCL$D%)^3w-g23Kk^~`~ zfi8rJ<5R)S2m>AYG^)xT}V(tIH^GiT z0`qgrwa zu|E~_{0sZWFB)fsRnJ)7)djludi2T71kgk5t`D_WSC6MxVell~>GUZmy4$#76D_Zp zyP&CPGuZyjM)8q0T7Fh0Dk;k5gn~`BT{9S6gbQxyA+D!k<5Ru%Q(_LINqiWilJe=@ z&nA`cmWdR3(@tbJaTivca7>c$oF=DhGcB3g67ulc3TXJ5RS8mc?o=FEzSmsBkx_ zYyk+gRLZ5M+i3cu7BvSYJ>={ijb^8112=ypHsg&7+%vo?-mOV&jam&Bh^IVP>O;BU zfFdZs{|i6xgZT5UV1Ld35rw4xQ9u9~AnORAbL0nsn;e_pVif;N7o3>*w}0S42Ose3 JLAC+_{sdzRU}*pV literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat_net 0 2.yaml b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat_net 0 2.yaml new file mode 100644 index 0000000000..6835485ca1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/asc_heat_net 0 2.yaml @@ -0,0 +1,787 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +# availability_zone_smp0: +# type: string +# default: nova +# availability_zone_smp1: +# type: string +# default: nova +# availability_zone_fe0: +# type: string +# default: nova +# availability_zone_fe1: +# type: string +# default: nova +# availability_zone_db0: +# type: string +# default: nova +# availability_zone_db1: +# type: string +# default: nova +# availability_zone_be0: +# type: string +# default: nova +# availability_zone_be1: +# type: string +# default: nova +# availability_zone_be2: +# type: string +# default: nova +# availability_zone_be3: +# type: string +# default: nova +# availability_zone_be4: +# type: string +# default: nova + + vnf_name: + type: string + description: Unique name for this VNF instance + default: This_is_the_SCP_name + vnf_id: + type: string + description: Unique ID for this VNF instance + default: This_is_ths_SCP_id + + flavor_scp_be_id: + type: string + description: flavor type + default: a1.Small + flavor_scp_fe_id: + type: string + description: flavor type + default: a1.Small + flavor_smp_id: + type: string + description: flavor type + default: a1.Small + flavor_db_id: + type: string + description: flavor type + default: a1.Small + image_scp_be_id: + type: string + description: Image use to boot a server + default: asc_base_image_be + image_scp_fe_id: + type: string + description: Image use to boot a server + default: asc_base_image_fe + image_smp_id: + type: string + description: Image use to boot a server + default: asc_base_image_smp + image_db_id: + type: string + description: Image use to boot a server + default: asc_base_image_db + + int_vscp_fe_cluster_net_id: + type: string + description: LAN2 FE Cluster/KA + int_vscp_fe_cluster_cidr: + type: string + description: Private Network2 Address (CIDR notation) + int_vscp_cluster_net_id: + type: string + description: LAN3 Cluster + int_vscp_cluster_cidr: + type: string + description: Private Network3 Address (CIDR notation) + int_vscp_db_network_net_id: + type: string + description: LAN4 DB + int_vscp_db_network_cidr: + type: string + description: Private Network4 Address (CIDR notation) + SIGNET_vrf_A1_direct_net_id: + type: string + description: Network name for SIGTRAN_A + SIGNET_vrf_B1_direct_net_id: + type: string + description: Network name for SIGTRAN_B + Cricket_OCS_protected_net_id: + type: string + description: Network name for CRICKET_OCS + OAM_direct_net_id: + type: string + description: Network name for OAM + be0_Cricket_OCS_protected_ips: + type: string + label: be0 port 5 OAM ip address + description: be0 port 5 OAM ip address + be1_Cricket_OCS_protected_ips: + type: string + label: be1 port 5 OAM ip address + description: be1 port 5 OAM ip address + be2_Cricket_OCS_protected_ips: + type: string + label: be2 port 5 OAM ip address + description: be2 port 5 OAM ip address + be3_Cricket_OCS_protected_ips: + type: string + label: be3 port 5 OAM ip address + description: be3 port 5 OAM ip address + be4_Cricket_OCS_protected_ips: + type: string + label: be4 port 5 OAM ip address + description: be4 port 5 OAM ip address + be0_OAM_direct_ips: + type: string + label: be0 port 7 OAM ip address + description: be0 port 7 OAM ip address + be1_OAM_direct_ips: + type: string + label: be1 port 7 OAM ip address + description: be1 port 7 OAM ip address + be2_OAM_direct_ips: + type: string + label: be2 port 7 OAM ip address + description: be2 port 7 OAM ip address + be3_OAM_direct_ips: + type: string + label: be3 port 7 OAM ip address + description: be3 port 7 OAM ip address + be4_OAM_direct_ips: + type: string + label: be4 port 7 OAM ip address + description: be4 port 7 OAM ip address + fe0_SIGNET_vrf_A1_direct_ips: + type: string + label: fe0 port 0 SIGTRAN ip address + description: fe0 port 0 SIGTRAN ip address + fe0_OAM_direct_ips: + type: string + label: fe0 port 7 OAM ip address + description: fe0 port 7 OAM ip address + fe1_SIGNET_vrf_B1_direct_ips: + type: string + label: fe1 port 1 SIGTRAN ip address + description: fe1 port 1 SIGTRAN ip address + fe1_OAM_direct_ips: + type: string + label: fe1 port 7 OAM ip address + description: fe1 port 7 OAM ip address + smp0_OAM_direct_ips: + type: string + label: smp0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + smp1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: smp1 port 7 OAM ip address + db0_OAM_direct_ips: + type: string + label: db0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + db1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: db1 port 7 OAM ip address + vm_scp_be0_name: + type: string + default: vSCP_BE0 + description: name of VM + vm_scp_be1_name: + type: string + default: vSCP_BE1 + description: name of VM + vm_scp_be2_name: + type: string + default: vSCP_BE2 + description: name of VM + vm_scp_be3_name: + type: string + default: vSCP_BE3 + description: name of VM + vm_scp_be4_name: + type: string + default: vSCP_BE4 + description: name of VM + vm_scp_fe0_name: + type: string + default: vSCP_FE0 + description: name of VM + vm_scp_fe1_name: + type: string + default: vSCP_FE1 + description: name of VM + vm_smp0_name: + type: string + default: vSMP0 + description: name of VM + vm_smp1_name: + type: string + default: vSMP1 + description: name of VM + vm_db0_name: + type: string + default: vDB0 + description: name of VM + vm_db1_name: + type: string + default: vDB1 + description: name of VM + +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heatEnvfile.env b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heatEnvfile.env new file mode 100644 index 0000000000..6835485ca1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heatEnvfile.env @@ -0,0 +1,787 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +# availability_zone_smp0: +# type: string +# default: nova +# availability_zone_smp1: +# type: string +# default: nova +# availability_zone_fe0: +# type: string +# default: nova +# availability_zone_fe1: +# type: string +# default: nova +# availability_zone_db0: +# type: string +# default: nova +# availability_zone_db1: +# type: string +# default: nova +# availability_zone_be0: +# type: string +# default: nova +# availability_zone_be1: +# type: string +# default: nova +# availability_zone_be2: +# type: string +# default: nova +# availability_zone_be3: +# type: string +# default: nova +# availability_zone_be4: +# type: string +# default: nova + + vnf_name: + type: string + description: Unique name for this VNF instance + default: This_is_the_SCP_name + vnf_id: + type: string + description: Unique ID for this VNF instance + default: This_is_ths_SCP_id + + flavor_scp_be_id: + type: string + description: flavor type + default: a1.Small + flavor_scp_fe_id: + type: string + description: flavor type + default: a1.Small + flavor_smp_id: + type: string + description: flavor type + default: a1.Small + flavor_db_id: + type: string + description: flavor type + default: a1.Small + image_scp_be_id: + type: string + description: Image use to boot a server + default: asc_base_image_be + image_scp_fe_id: + type: string + description: Image use to boot a server + default: asc_base_image_fe + image_smp_id: + type: string + description: Image use to boot a server + default: asc_base_image_smp + image_db_id: + type: string + description: Image use to boot a server + default: asc_base_image_db + + int_vscp_fe_cluster_net_id: + type: string + description: LAN2 FE Cluster/KA + int_vscp_fe_cluster_cidr: + type: string + description: Private Network2 Address (CIDR notation) + int_vscp_cluster_net_id: + type: string + description: LAN3 Cluster + int_vscp_cluster_cidr: + type: string + description: Private Network3 Address (CIDR notation) + int_vscp_db_network_net_id: + type: string + description: LAN4 DB + int_vscp_db_network_cidr: + type: string + description: Private Network4 Address (CIDR notation) + SIGNET_vrf_A1_direct_net_id: + type: string + description: Network name for SIGTRAN_A + SIGNET_vrf_B1_direct_net_id: + type: string + description: Network name for SIGTRAN_B + Cricket_OCS_protected_net_id: + type: string + description: Network name for CRICKET_OCS + OAM_direct_net_id: + type: string + description: Network name for OAM + be0_Cricket_OCS_protected_ips: + type: string + label: be0 port 5 OAM ip address + description: be0 port 5 OAM ip address + be1_Cricket_OCS_protected_ips: + type: string + label: be1 port 5 OAM ip address + description: be1 port 5 OAM ip address + be2_Cricket_OCS_protected_ips: + type: string + label: be2 port 5 OAM ip address + description: be2 port 5 OAM ip address + be3_Cricket_OCS_protected_ips: + type: string + label: be3 port 5 OAM ip address + description: be3 port 5 OAM ip address + be4_Cricket_OCS_protected_ips: + type: string + label: be4 port 5 OAM ip address + description: be4 port 5 OAM ip address + be0_OAM_direct_ips: + type: string + label: be0 port 7 OAM ip address + description: be0 port 7 OAM ip address + be1_OAM_direct_ips: + type: string + label: be1 port 7 OAM ip address + description: be1 port 7 OAM ip address + be2_OAM_direct_ips: + type: string + label: be2 port 7 OAM ip address + description: be2 port 7 OAM ip address + be3_OAM_direct_ips: + type: string + label: be3 port 7 OAM ip address + description: be3 port 7 OAM ip address + be4_OAM_direct_ips: + type: string + label: be4 port 7 OAM ip address + description: be4 port 7 OAM ip address + fe0_SIGNET_vrf_A1_direct_ips: + type: string + label: fe0 port 0 SIGTRAN ip address + description: fe0 port 0 SIGTRAN ip address + fe0_OAM_direct_ips: + type: string + label: fe0 port 7 OAM ip address + description: fe0 port 7 OAM ip address + fe1_SIGNET_vrf_B1_direct_ips: + type: string + label: fe1 port 1 SIGTRAN ip address + description: fe1 port 1 SIGTRAN ip address + fe1_OAM_direct_ips: + type: string + label: fe1 port 7 OAM ip address + description: fe1 port 7 OAM ip address + smp0_OAM_direct_ips: + type: string + label: smp0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + smp1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: smp1 port 7 OAM ip address + db0_OAM_direct_ips: + type: string + label: db0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + db1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: db1 port 7 OAM ip address + vm_scp_be0_name: + type: string + default: vSCP_BE0 + description: name of VM + vm_scp_be1_name: + type: string + default: vSCP_BE1 + description: name of VM + vm_scp_be2_name: + type: string + default: vSCP_BE2 + description: name of VM + vm_scp_be3_name: + type: string + default: vSCP_BE3 + description: name of VM + vm_scp_be4_name: + type: string + default: vSCP_BE4 + description: name of VM + vm_scp_fe0_name: + type: string + default: vSCP_FE0 + description: name of VM + vm_scp_fe1_name: + type: string + default: vSCP_FE1 + description: name of VM + vm_smp0_name: + type: string + default: vSMP0 + description: name of VM + vm_smp1_name: + type: string + default: vSMP1 + description: name of VM + vm_db0_name: + type: string + default: vDB0 + description: name of VM + vm_db1_name: + type: string + default: vDB1 + description: name of VM + +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heatInvalidFormat.yaml b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heatInvalidFormat.yaml new file mode 100644 index 0000000000..b70d5a4b0a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heatInvalidFormat.yaml @@ -0,0 +1,9 @@ +heat_template_version: 2013-05-23 + +parameters: + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heat_mini.yaml b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heat_mini.yaml new file mode 100644 index 0000000000..a545569129 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/heat_mini.yaml @@ -0,0 +1,13 @@ +heat_template_version: 2013-05-23 + +parameters: + vnf_name: + type: string + description: Unique name for this VNF instance + default: This_is_the_SCP_name + +resources: + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidJson.json b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidJson.json new file mode 100644 index 0000000000..48a3e89deb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidJson.json @@ -0,0 +1,11 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidYamlFormat.yaml b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidYamlFormat.yaml new file mode 100644 index 0000000000..5c51039931 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidYamlFormat.yaml @@ -0,0 +1,787 @@ + heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +# availability_zone_smp0: +# type: string +# default: nova +# availability_zone_smp1: +# type: string +# default: nova +# availability_zone_fe0: +# type: string +# default: nova +# availability_zone_fe1: +# type: string +# default: nova +# availability_zone_db0: +# type: string +# default: nova +# availability_zone_db1: +# type: string +# default: nova +# availability_zone_be0: +# type: string +# default: nova +# availability_zone_be1: +# type: string +# default: nova +# availability_zone_be2: +# type: string +# default: nova +# availability_zone_be3: +# type: string +# default: nova +# availability_zone_be4: +# type: string +# default: nova + + vnf_name: + type: string + description: Unique name for this VNF instance + default: This_is_the_SCP_name + vnf_id: + type: string + description: Unique ID for this VNF instance + default: This_is_ths_SCP_id + + flavor_scp_be_id: + type: string + description: flavor type + default: a1.Small + flavor_scp_fe_id: + type: string + description: flavor type + default: a1.Small + flavor_smp_id: + type: string + description: flavor type + default: a1.Small + flavor_db_id: + type: string + description: flavor type + default: a1.Small + image_scp_be_id: + type: string + description: Image use to boot a server + default: asc_base_image_be + image_scp_fe_id: + type: string + description: Image use to boot a server + default: asc_base_image_fe + image_smp_id: + type: string + description: Image use to boot a server + default: asc_base_image_smp + image_db_id: + type: string + description: Image use to boot a server + default: asc_base_image_db + + int_vscp_fe_cluster_net_id: + type: string + description: LAN2 FE Cluster/KA + int_vscp_fe_cluster_cidr: + type: string + description: Private Network2 Address (CIDR notation) + int_vscp_cluster_net_id: + type: string + description: LAN3 Cluster + int_vscp_cluster_cidr: + type: string + description: Private Network3 Address (CIDR notation) + int_vscp_db_network_net_id: + type: string + description: LAN4 DB + int_vscp_db_network_cidr: + type: string + description: Private Network4 Address (CIDR notation) + SIGNET_vrf_A1_direct_net_id: + type: string + description: Network name for SIGTRAN_A + SIGNET_vrf_B1_direct_net_id: + type: string + description: Network name for SIGTRAN_B + Cricket_OCS_protected_net_id: + type: string + description: Network name for CRICKET_OCS + OAM_direct_net_id: + type: string + description: Network name for OAM + be0_Cricket_OCS_protected_ips: + type: string + label: be0 port 5 OAM ip address + description: be0 port 5 OAM ip address + be1_Cricket_OCS_protected_ips: + type: string + label: be1 port 5 OAM ip address + description: be1 port 5 OAM ip address + be2_Cricket_OCS_protected_ips: + type: string + label: be2 port 5 OAM ip address + description: be2 port 5 OAM ip address + be3_Cricket_OCS_protected_ips: + type: string + label: be3 port 5 OAM ip address + description: be3 port 5 OAM ip address + be4_Cricket_OCS_protected_ips: + type: string + label: be4 port 5 OAM ip address + description: be4 port 5 OAM ip address + be0_OAM_direct_ips: + type: string + label: be0 port 7 OAM ip address + description: be0 port 7 OAM ip address + be1_OAM_direct_ips: + type: string + label: be1 port 7 OAM ip address + description: be1 port 7 OAM ip address + be2_OAM_direct_ips: + type: string + label: be2 port 7 OAM ip address + description: be2 port 7 OAM ip address + be3_OAM_direct_ips: + type: string + label: be3 port 7 OAM ip address + description: be3 port 7 OAM ip address + be4_OAM_direct_ips: + type: string + label: be4 port 7 OAM ip address + description: be4 port 7 OAM ip address + fe0_SIGNET_vrf_A1_direct_ips: + type: string + label: fe0 port 0 SIGTRAN ip address + description: fe0 port 0 SIGTRAN ip address + fe0_OAM_direct_ips: + type: string + label: fe0 port 7 OAM ip address + description: fe0 port 7 OAM ip address + fe1_SIGNET_vrf_B1_direct_ips: + type: string + label: fe1 port 1 SIGTRAN ip address + description: fe1 port 1 SIGTRAN ip address + fe1_OAM_direct_ips: + type: string + label: fe1 port 7 OAM ip address + description: fe1 port 7 OAM ip address + smp0_OAM_direct_ips: + type: string + label: smp0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + smp1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: smp1 port 7 OAM ip address + db0_OAM_direct_ips: + type: string + label: db0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + db1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: db1 port 7 OAM ip address + vm_scp_be0_name: + type: string + default: vSCP_BE0 + description: name of VM + vm_scp_be1_name: + type: string + default: vSCP_BE1 + description: name of VM + vm_scp_be2_name: + type: string + default: vSCP_BE2 + description: name of VM + vm_scp_be3_name: + type: string + default: vSCP_BE3 + description: name of VM + vm_scp_be4_name: + type: string + default: vSCP_BE4 + description: name of VM + vm_scp_fe0_name: + type: string + default: vSCP_FE0 + description: name of VM + vm_scp_fe1_name: + type: string + default: vSCP_FE1 + description: name of VM + vm_smp0_name: + type: string + default: vSMP0 + description: name of VM + vm_smp1_name: + type: string + default: vSMP1 + description: name of VM + vm_db0_name: + type: string + default: vDB0 + description: name of VM + vm_db1_name: + type: string + default: vDB1 + description: name of VM + +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidYangXml.xml b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidYangXml.xml new file mode 100644 index 0000000000..8978e0d5ed --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/invalidYangXml.xml @@ -0,0 +1,35 @@ + + + + + Lionel Andr�s Messi + 1987-06-24T00:00:00-00:00 + + + Cristiano Ronaldo + 1985-02-05T00:00:00-00:00 + + + FC Barcelona + + Lionel Andr�s Messi + Champions League 2014/2015 + 10 + 43 + + + + Real Madrid + + Cristiano Ronaldo + Champions League 2014/2015 + 7 + 48 + + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/jsonArtifact.json b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/jsonArtifact.json new file mode 100644 index 0000000000..d5ca56d195 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/jsonArtifact.json @@ -0,0 +1,22 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/other.txt b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/other.txt new file mode 100644 index 0000000000..5f8f77ca2c --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/HeatDeploymentArtifacts/other.txt @@ -0,0 +1,3 @@ +cmd1 +cmd2 +cmd3 \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/bluePrintSampleArtifact.xml b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/bluePrintSampleArtifact.xml new file mode 100644 index 0000000000..10c46b7269 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/bluePrintSampleArtifact.xml @@ -0,0 +1,3 @@ + + dfsfsdfsdf + \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/docSampleArtifact.docx b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/docSampleArtifact.docx new file mode 100644 index 0000000000000000000000000000000000000000..c281f532f83c59ef24ad8125f611ca5ab44acb07 GIT binary patch literal 11307 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 literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/emfSampleArtifact.emf b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/emfSampleArtifact.emf new file mode 100644 index 0000000000..9c478f6ce1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/emfSampleArtifact.emf @@ -0,0 +1,2 @@ +This is sample EMF file +We currently not checking the file content. \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/emfSampleArtifact.xml b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/emfSampleArtifact.xml new file mode 100644 index 0000000000..10c46b7269 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/emfSampleArtifact.xml @@ -0,0 +1,3 @@ + + dfsfsdfsdf + \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/eventSampleArtifact.xml b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/eventSampleArtifact.xml new file mode 100644 index 0000000000..10c46b7269 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/eventSampleArtifact.xml @@ -0,0 +1,3 @@ + + dfsfsdfsdf + \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/jsonSampleArtifact.json b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/jsonSampleArtifact.json new file mode 100644 index 0000000000..b749a9e89c --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/jsonSampleArtifact.json @@ -0,0 +1,3 @@ +{ + "test": "This is test" +} diff --git a/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/toscaSampleArtifact.yml b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/toscaSampleArtifact.yml new file mode 100644 index 0000000000..10ccf71d51 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/ResourceInstanceArtifacts/toscaSampleArtifact.yml @@ -0,0 +1,5 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 + +node_types: + org.openecomp.resource.cp.CP: + derived_from: org.openecomp.resource.cp.root \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/addHeatArtifactToServiceAndSertify/asc_heat 0 2.yaml b/test-apis-ci/src/test/resources/CI/tests/addHeatArtifactToServiceAndSertify/asc_heat 0 2.yaml new file mode 100644 index 0000000000..6835485ca1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/addHeatArtifactToServiceAndSertify/asc_heat 0 2.yaml @@ -0,0 +1,787 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +# availability_zone_smp0: +# type: string +# default: nova +# availability_zone_smp1: +# type: string +# default: nova +# availability_zone_fe0: +# type: string +# default: nova +# availability_zone_fe1: +# type: string +# default: nova +# availability_zone_db0: +# type: string +# default: nova +# availability_zone_db1: +# type: string +# default: nova +# availability_zone_be0: +# type: string +# default: nova +# availability_zone_be1: +# type: string +# default: nova +# availability_zone_be2: +# type: string +# default: nova +# availability_zone_be3: +# type: string +# default: nova +# availability_zone_be4: +# type: string +# default: nova + + vnf_name: + type: string + description: Unique name for this VNF instance + default: This_is_the_SCP_name + vnf_id: + type: string + description: Unique ID for this VNF instance + default: This_is_ths_SCP_id + + flavor_scp_be_id: + type: string + description: flavor type + default: a1.Small + flavor_scp_fe_id: + type: string + description: flavor type + default: a1.Small + flavor_smp_id: + type: string + description: flavor type + default: a1.Small + flavor_db_id: + type: string + description: flavor type + default: a1.Small + image_scp_be_id: + type: string + description: Image use to boot a server + default: asc_base_image_be + image_scp_fe_id: + type: string + description: Image use to boot a server + default: asc_base_image_fe + image_smp_id: + type: string + description: Image use to boot a server + default: asc_base_image_smp + image_db_id: + type: string + description: Image use to boot a server + default: asc_base_image_db + + int_vscp_fe_cluster_net_id: + type: string + description: LAN2 FE Cluster/KA + int_vscp_fe_cluster_cidr: + type: string + description: Private Network2 Address (CIDR notation) + int_vscp_cluster_net_id: + type: string + description: LAN3 Cluster + int_vscp_cluster_cidr: + type: string + description: Private Network3 Address (CIDR notation) + int_vscp_db_network_net_id: + type: string + description: LAN4 DB + int_vscp_db_network_cidr: + type: string + description: Private Network4 Address (CIDR notation) + SIGNET_vrf_A1_direct_net_id: + type: string + description: Network name for SIGTRAN_A + SIGNET_vrf_B1_direct_net_id: + type: string + description: Network name for SIGTRAN_B + Cricket_OCS_protected_net_id: + type: string + description: Network name for CRICKET_OCS + OAM_direct_net_id: + type: string + description: Network name for OAM + be0_Cricket_OCS_protected_ips: + type: string + label: be0 port 5 OAM ip address + description: be0 port 5 OAM ip address + be1_Cricket_OCS_protected_ips: + type: string + label: be1 port 5 OAM ip address + description: be1 port 5 OAM ip address + be2_Cricket_OCS_protected_ips: + type: string + label: be2 port 5 OAM ip address + description: be2 port 5 OAM ip address + be3_Cricket_OCS_protected_ips: + type: string + label: be3 port 5 OAM ip address + description: be3 port 5 OAM ip address + be4_Cricket_OCS_protected_ips: + type: string + label: be4 port 5 OAM ip address + description: be4 port 5 OAM ip address + be0_OAM_direct_ips: + type: string + label: be0 port 7 OAM ip address + description: be0 port 7 OAM ip address + be1_OAM_direct_ips: + type: string + label: be1 port 7 OAM ip address + description: be1 port 7 OAM ip address + be2_OAM_direct_ips: + type: string + label: be2 port 7 OAM ip address + description: be2 port 7 OAM ip address + be3_OAM_direct_ips: + type: string + label: be3 port 7 OAM ip address + description: be3 port 7 OAM ip address + be4_OAM_direct_ips: + type: string + label: be4 port 7 OAM ip address + description: be4 port 7 OAM ip address + fe0_SIGNET_vrf_A1_direct_ips: + type: string + label: fe0 port 0 SIGTRAN ip address + description: fe0 port 0 SIGTRAN ip address + fe0_OAM_direct_ips: + type: string + label: fe0 port 7 OAM ip address + description: fe0 port 7 OAM ip address + fe1_SIGNET_vrf_B1_direct_ips: + type: string + label: fe1 port 1 SIGTRAN ip address + description: fe1 port 1 SIGTRAN ip address + fe1_OAM_direct_ips: + type: string + label: fe1 port 7 OAM ip address + description: fe1 port 7 OAM ip address + smp0_OAM_direct_ips: + type: string + label: smp0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + smp1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: smp1 port 7 OAM ip address + db0_OAM_direct_ips: + type: string + label: db0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + db1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: db1 port 7 OAM ip address + vm_scp_be0_name: + type: string + default: vSCP_BE0 + description: name of VM + vm_scp_be1_name: + type: string + default: vSCP_BE1 + description: name of VM + vm_scp_be2_name: + type: string + default: vSCP_BE2 + description: name of VM + vm_scp_be3_name: + type: string + default: vSCP_BE3 + description: name of VM + vm_scp_be4_name: + type: string + default: vSCP_BE4 + description: name of VM + vm_scp_fe0_name: + type: string + default: vSCP_FE0 + description: name of VM + vm_scp_fe1_name: + type: string + default: vSCP_FE1 + description: name of VM + vm_smp0_name: + type: string + default: vSMP0 + description: name of VM + vm_smp1_name: + type: string + default: vSMP1 + description: name of VM + vm_db0_name: + type: string + default: vDB0 + description: name of VM + vm_db1_name: + type: string + default: vDB1 + description: name of VM + +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/downloadResourceArtifactSuccess/org.openstack.Rally.zip b/test-apis-ci/src/test/resources/CI/tests/downloadResourceArtifactSuccess/org.openstack.Rally.zip new file mode 100644 index 0000000000000000000000000000000000000000..0951d5cef87985641c441520529cafd8253b7cbf GIT binary patch literal 11590 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/mysql.yml new file mode 100644 index 0000000000..f512f8071e --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getResourceArtifactFileContentTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getResourceArtifactFileContentTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/scripts/install_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/scripts/install_mysql.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/scripts/install_mysql.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/scripts/start_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/scripts/start_mysql.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactFileContentTest/scripts/start_mysql.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListNoContentTest/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListNoContentTest/mysql.yml new file mode 100644 index 0000000000..180e247ea2 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListNoContentTest/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getResourceArtifactListNoContentTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getResourceArtifactListNoContentTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/mysql.yml new file mode 100644 index 0000000000..b8f9bbdc69 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-GetResourceArtifactListTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-GetResourceArtifactListTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/scripts/install_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/scripts/install_mysql.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/scripts/install_mysql.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/scripts/start_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/scripts/start_mysql.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactListTest/scripts/start_mysql.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataNoContentTest/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataNoContentTest/mysql.yml new file mode 100644 index 0000000000..72ff4f37e0 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataNoContentTest/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getResourceArtifactMetadataNoContentTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getResourceArtifactMetadataNoContentTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/mysql.yml new file mode 100644 index 0000000000..527e4a0081 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getResourceArtifactMetadataTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getResourceArtifactMetadataTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/scripts/install_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/scripts/install_mysql.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/scripts/install_mysql.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/scripts/start_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/scripts/start_mysql.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactMetadataTest/scripts/start_mysql.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactPayloadNoContentTest/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactPayloadNoContentTest/mysql.yml new file mode 100644 index 0000000000..7177a65387 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getResourceArtifactPayloadNoContentTest/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getResourceArtifactPayloadNoContentTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getResourceArtifactPayloadNoContentTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/mysql.yml new file mode 100644 index 0000000000..e0a0c6458e --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListTest + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListTest: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListTest: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/scripts/install_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/scripts/install_mysql.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/scripts/install_mysql.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/scripts/start_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/scripts/start_mysql.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource1/scripts/start_mysql.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/mysql.yml new file mode 100644 index 0000000000..dc5ff158c8 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListTest2 +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListTest2: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListTest2 + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListTest2: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListTest2: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/scripts/install_mysql2.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/scripts/install_mysql2.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/scripts/install_mysql2.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/scripts/start_mysql2.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/scripts/start_mysql2.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/resource2/scripts/start_mysql2.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/topology.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/topology.txt new file mode 100644 index 0000000000..cb3c3e8546 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/topology.txt @@ -0,0 +1 @@ +{"id":"6a4b2f9d-7fe1-482d-af11-97f483dff5b7","delegateId":"9c063349-2259-40fe-97f1-7c40e659e1b0","delegateType":"topologytemplate","dependencies":[{"name":"tosca-normative-types-DBMS","version":"1.0.0.wd03-SNAPSHOT"},{"name":"mysql-getServiceArtifactListTest2","version":"1.1.1-SNAPSHOT"},{"name":"tosca-normative-types-softwareComponent","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-compute","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-root","version":"1.0.0.wd03-SNAPSHOT"},{"name":"mysql-getServiceArtifactListTest","version":"1.1.1-SNAPSHOT"},{"name":"tosca-normative-types-database","version":"1.0.0.wd03-SNAPSHOT"}],"nodeTemplates":[{"key":"Mysql-getServiceArtifactListTest","value":{"type":"alien.nodes.Mysql-getServiceArtifactListTest","name":null,"properties":{"bind_address":"true","storage_path":"/mountedStorage","db_port":"3306","db_name":"wordpress","db_user":"pass","db_password":"pass"},"attributes":{"tosca_id":null,"tosca_name":null},"relationships":{"hostedOnCompute":{"type":"tosca.relationships.HostedOn","target":"Compute","requirementName":"host","requirementType":"tosca.nodes.Compute","targetedCapabilityName":"host"}},"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"host":{"type":"tosca.nodes.Compute","properties":null}},"capabilities":{"database_endpoint":{"type":"tosca.capabilities.DatabaseEndpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"host":{"type":"alien.capabilities.MysqlDatabase-getServiceArtifactListTest","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null}},"artifacts":{"scripts":{"artifactType":"tosca.artifacts.File","artifactRef":"scripts","artifactName":"scripts","artifactRepository":null}}}},{"key":"Compute","value":{"type":"tosca.nodes.Compute","name":null,"properties":{"disk_size":null,"num_cpus":null,"os_distribution":null,"os_arch":null,"mem_size":null,"os_type":null,"os_version":null},"attributes":{"ip_address":null,"tosca_id":null,"tosca_name":null},"relationships":null,"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"network":{"type":"tosca.capabilities.Connectivity","properties":null}},"capabilities":{"host":{"type":"tosca.capabilities.Container","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null},"attach":{"type":"tosca.capabilities.Attachment","properties":null},"scalable":{"type":"tosca.capabilities.Scalable","properties":{"max_intances":{"value":"1","definition":false},"default_instances":{"value":"1","definition":false},"min_intances":{"value":"1","definition":false}}}},"artifacts":null}},{"key":"Mysql-getServiceArtifactListTest2","value":{"type":"alien.nodes.Mysql-getServiceArtifactListTest2","name":null,"properties":{"bind_address":"true","storage_path":"/mountedStorage","db_port":"3306","db_name":"wordpress","db_user":"pass","db_password":"pass"},"attributes":{"tosca_id":null,"tosca_name":null},"relationships":{"hostedOnCompute":{"type":"tosca.relationships.HostedOn","target":"Compute","requirementName":"host","requirementType":"tosca.nodes.Compute","targetedCapabilityName":"host"}},"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"host":{"type":"tosca.nodes.Compute","properties":null}},"capabilities":{"database_endpoint":{"type":"tosca.capabilities.DatabaseEndpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"host":{"type":"alien.capabilities.MysqlDatabase-getServiceArtifactListTest2","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null}},"artifacts":{"scripts":{"artifactType":"tosca.artifacts.File","artifactRef":"scripts","artifactName":"scripts","artifactRepository":null}}}}]} \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/topologyTemplate.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/topologyTemplate.txt new file mode 100644 index 0000000000..f0d0849db8 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListInvalidVersionNotFoundTest/topologyTemplate.txt @@ -0,0 +1,2 @@ +{"id":"9c063349-2259-40fe-97f1-7c40e659e1b0","name":"Andrey","description":null,"topologyId":"6a4b2f9d-7fe1-482d-af11-97f483dff5b7"} + diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource1/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource1/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource1/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource1/mysql.yml new file mode 100644 index 0000000000..4ee2c8ca88 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource1/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListNoContentTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListNoContentTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListNoContentTest: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource2/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource2/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource2/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource2/mysql.yml new file mode 100644 index 0000000000..b564dd0c4e --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/resource2/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListNoContentTest2 +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListNoContentTest2: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest2 + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest2: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListNoContentTest2: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/topology.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/topology.txt new file mode 100644 index 0000000000..279351879a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/topology.txt @@ -0,0 +1 @@ +{"id":"3293c9c8-a162-43fc-b8d1-431399f89cb7","delegateId":"25845cce-05c8-4502-b5fe-abfd6bd6f28e","delegateType":"topologytemplate","dependencies":[{"name":"tosca-normative-types-DBMS","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-softwareComponent","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-compute","version":"1.0.0.wd03-SNAPSHOT"},{"name":"mysql-getServiceArtifactListNoContentTest2","version":"1.1.1-SNAPSHOT"},{"name":"tosca-normative-types-root","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-database","version":"1.0.0.wd03-SNAPSHOT"}],"nodeTemplates":[{"key":"Mysql-getServiceArtifactListNoContentTest2","value":{"type":"alien.nodes.Mysql-getServiceArtifactListNoContentTest2","name":null,"properties":{"bind_address":"true","storage_path":"/mountedStorage","db_port":"3306","db_name":"wordpress","db_user":"pass","db_password":"pass"},"attributes":{"tosca_id":null,"tosca_name":null},"relationships":null,"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"host":{"type":"tosca.nodes.Compute","properties":null}},"capabilities":{"database_endpoint":{"type":"tosca.capabilities.DatabaseEndpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"host":{"type":"alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest2","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null}},"artifacts":{"scripts":{"artifactType":"tosca.artifacts.File","artifactRef":"scripts","artifactName":"scripts","artifactRepository":null}}}},{"key":"Compute","value":{"type":"tosca.nodes.Compute","name":null,"properties":{"disk_size":null,"num_cpus":null,"os_distribution":null,"os_arch":null,"mem_size":null,"os_type":null,"os_version":null},"attributes":{"ip_address":null,"tosca_id":null,"tosca_name":null},"relationships":{"dependsOnMysql-getServiceArtifactListNoContentTest2":{"type":"tosca.relationships.DependsOn","target":"Mysql-getServiceArtifactListNoContentTest2","requirementName":"dependency","requirementType":"tosca.capabilities.Root","targetedCapabilityName":"root"}},"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"network":{"type":"tosca.capabilities.Connectivity","properties":null}},"capabilities":{"host":{"type":"tosca.capabilities.Container","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null},"attach":{"type":"tosca.capabilities.Attachment","properties":null},"scalable":{"type":"tosca.capabilities.Scalable","properties":{"max_intances":{"value":"1","definition":false},"default_instances":{"value":"1","definition":false},"min_intances":{"value":"1","definition":false}}}},"artifacts":null}}]} \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/topologyTemplate.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/topologyTemplate.txt new file mode 100644 index 0000000000..3c342f6cd1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListNoContentTest/topologyTemplate.txt @@ -0,0 +1,2 @@ +{"id":"25845cce-05c8-4502-b5fe-abfd6bd6f28e","name":"ServiceArtListNoContent","description":null,"topologyId":"3293c9c8-a162-43fc-b8d1-431399f89cb7"} + diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/mysql.yml new file mode 100644 index 0000000000..e0a0c6458e --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListTest + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListTest: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListTest: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/scripts/install_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/scripts/install_mysql.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/scripts/install_mysql.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/scripts/start_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/scripts/start_mysql.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource1/scripts/start_mysql.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 zcmZ^Kby$?$^Y=-AgQu3J6GdH!CeIEz-4gcPy}^bi?oF`M&?Y zdtH06?0wFeIddjHXJ$4`MM)YLiv$Y<0^!QaNT`88NTW}03^d@IMs4W~;17zMxU2>S z@bbkl{|@|*=`5q`1_EI>KE0pqpWmDUU%mlL>VVaqEWw^8t`;CqPfu1GM>{t&6K4xn zCs(WVLqQT?(95Sm8a7~i3y`@9*u>Pt&4S7S;^u7sMd!5+@SO1JxtKfH+Q}6pZeaqp zpprLnb2f3s>y(xN9uq%3{^SZguyJyv(y(!`0Li)AL#RHmv-2|hh#vw&)czad{Ox>TRu&7%D%!%3C*jZ3ngTc=HY;0!#t>$52=H%euw>;Clw{%|7 zTJbw5lB44@My{a@RRV#`4sC+7+v&*gup;~0M;cKKf~am%q>aZ=+y&TbF4_kT#i6S+9IeYbb`M#jDopa44pUhE;r#?Suuk-++Yf2n{| zdU}cG{O>`aDDwZl2zoj=;Dr=f`M(b!46gru`2S7)sbp{koc|v(qnl(Aa6Ey#>lDlP z$+#Et9rCdzKKu1l=LU*NIg1ntg9Me>buS|t;C@wwEi992%nJ_@0p5{+D4u}=$8#`) z_=!L&J}q~Z{)_L4GfOabUxc}9N|-k54cs~))}}~PKXSKgY((503+xiu zM_?qR+xW3om(`m=*FX5hGA-tGYc&7neT6ypD{rmRy~1~$7hOw9&vy#b#m#3cZV_PZ z^=xlP*)sJ_Z+>^5{kEC?(drTw3Y|S- zqhi7pywl$ee4!eJVAjG`2vUtK5ffeYx8`qR3Pq|CE-waeZ#EWg0!~wBMpl2K|92i# z$dwN(BHPb~O3lQX6JFDYorGMu7Pcr4>PTW5k_U_GtLMmGE>GSPnVPZ$>wW)b4^3Ek zSRf^Gz5qRO6Iimz9pDoXZ?GR@kds2V)M@cU5+p-fq)dcPMy{8Wd)fC-uD6`g_r3Z>DqsH-lLlYF8UEuE74fZkqmkU;`S|mS z3fCYQm^mvR&ZwIem3*&O()!cpKVtR+dm;}^Q2QOekEyhLsuwDP z8-j1SDMm&eia6pbGWKI1xkJ%n%Uvt0sPvN+OA%xw3*svi|hA)2LRv1y%d}!kGIG**Zswgy*mue4gHUZ z#dGUcGZ(ESD~2(77WhpVTe~}moAf^_VRy&$6b979Y%x|lnblRTvK3DKEGz^&1DLf* z?*iVr2>2VX-(w|G=#QGF*;kzz@^+m>pa=|`i^e0-G6skNFR@91b-c&=^nn6OM^GbWG<5+ zIVk9v4s5GLTOcA?5uXjdY@9HuX^j0k2p=MHBn*NbLvZ{8H9Dr_HuVj|znder7M?>m zv4UXAITQGmH77~CnMtGpr<2;tAA`~epES0PemMJXn01bT&O0TWUfxcQu!I_eU`OKU zS5eZKmy>$daLhz8i=!Jq+#$4#mz%}N^!dw(y%voIv&Zg3 zM8SkO>3!LakIuZK%9}=jN?^GKTXkX~#vpL2O zI#2%dOeu$^KK>>;>eh-Ijz=otd6ztPKr*2MqvD0A!N--Iz_0m)YL$z(Lh zoo+UrwA9Nybzed1%lqjMYv)n*x+qB%3D;8?dVS)9Efv0O{4O}-&v03@c&;^GTKH1h z;2YtW4CbM+4{7amnAl*sCk@!tre3(I@JV7E7>N zjw*2wm)H z!L+|5gx0SlNr~5FT7FVk#4caT=svc|lT;4EsT$;|8{(707Vz8`UbW*s*5R2jPP}Ct z&sF*MrJA`Sl-l;q0)-*}1=l^bVnk@wg>;^L9+{$+UZ%(qSgnLW zAh~N6ZlITE^?N{4fOW3pw|VGaj>ae!vlEs)@kgB>Qf6=8GEa^DTj$4Al}E~iee>-U zNgAZ=yY)Zc*M7ulop>VmliBI|F`z+=!G@?Z9GWtbB;f3h1(tI<$zxD2VW98GeSYpp zKh;QH-Ie4k@V1x0?DNa1uPnj*1UT^`1Vw?&{*8z6@=14`6^6b4<}6KwFK=$_6wK|YOVu)A~}?wz|buNf%{m3O7#NKv*PTyE$Ti!jY#?r$+y zMa!9#fNL6vm+6+=Kg`C_3jAi6k==&n>ChMOzfaD!eYIom>)MIz%57Ex$Lzk?+0^B@4qxMWxtID7n}ARyV|kJh!*`ME?NATZ z7O3t=4xc3bidNLLBWxyJ4;7vM>iQI<$hESUxbCdB=BgF(U-rXU-uCB^tSL|jNmk*- z&Je$g=K1LemFLE;TQ#zMUQQIG)Ch|qrHJgWy;^&C^zNl4BYz^&$2$CYGHMil{-K8V zNP$R60K0Y|@Oh-{he1~c66{VH!DzD>(%nqC6f=3~Jep{EXX~_Fk)K#2PFyb~O*YR< z`Qcu~Iqw}k93qG(mtRzp9$e2@e?9TUv^ zA|9@y_7Nwv7Ve$2=@so-#!F=N8yS>>jc;TgdvTSt$^ZHXb9n7{6mwbZ`(MeT^p(P_ zkB@l<_ppx2c0$g#NPu&j8p?jy>ulbPg^k~#={Ak)qc>yJ?iwaJIJ2`3E10#)6G7iE z)(j!vfk27DR;E8>-D8LZpQRaNsIb3G@I*;ez&7fk|6Y|UO8;O5c}Oz2AMbE#ImO&} z0mPD{S8%N!%{4G^KUH0A<33DQ`cAj&WEKm%~MB-5@eXNP{XQr>%^%m;@B%eLAoO zu$nFBo^Or9bVC@upd61?#$mz_z{2_0e9;LA(Xvqf7xiC7>C=Uw9nHxRFA>7~hJXihZ`;8&mqok}UY|AAM;1bp_Q0Gk|PVo-IEhq|@Q5w;~KgMJ}J3%Jfuo zI;+dEC3w|C65wb&bzD6KZ)`R}AgQ(Y!RWLw*tNB-ZPu2h6~l|O(l8@t=F$GrjT0e1 zMb>ukmHv@%ln~aFGm*~F9_&W9fRui}{1_iqrYD)x`J8dsB$5pFjjLJ1n-7%a6Q$A` z+4Ayuu_Gf&MW6XwN8aZ*83?lw3vchNB04DJ&S?*wS5<{5{mhhL@Rg8S0p*`86u_0p zy@h2%?DGwLCA3vnmC;DoZhJipJ-kr5(_^M|7Ip1B^&uo zJ$d&5V?=^}vJ4zC&IFc7aq4X-eW7Tt@9it>&MsfuSw%A)MbkJ<*1wQcFA#Sq|5BJP zvqGmYM&4+Z&#h-jJGxCBR%#d7t!)NIDZk%1R!!!E3z*l_@y-nklIQ1wplMX#$R0#fimZsNU0suk z=;`1tl(i+I^jffi#|PDl`|Vh#cKSde3_$vuY%oFge`eJ!Y4p>BjQy_&tYH~%$v9-K zZ4=~)(H;{GeiZJb6~0E_aLv%cA8;qy`pi%d6Z-Rqte**E&y{<_d(yXzBg|vW z6LKX>6@}+C$6HwrpYa4a*C!{*6crT4_s@pZ?rm^`lok`5eh4!Sw#&s*bQ&Q8nvfKB zy3xSsLU)Xm|H`QmMUOE(VJpPDA~J zeHm2Bs0Z7r6V)MT+mcGbY-55;kV`JB5yFHCMrv<4wrITD96M^+M!I+%DEc*Rd*t!p zxLGFy{@jZbu6vwhki#dKU%^T=^21~97tO71OuPhNRn)SXitW`q&r|~*xyFi61JYoh zB57%Q8*}Rvq=!IF6n+=#ciL?%$&?~DnU@qD%SZ&)D*EGhbG?nUx5(kawg%<;7Fsen z+=;<~qz2}&K9o>(=MfH?H?xWrn#$ap^8^N&up!pboj%@3yy#-F-$VpEo9)h&5oc9L zEtk*tSpe_AO*Nvt$Wq$ov$@N9?_Ga~bl}WCX&-oA9n{SnDDSM({iT;JLYYOV`WFrL zB9cbF0S^z4O2qp}+suZb*MbbmoDdxRsPWCN1i21t03s~<>O4FW_qN?GLw`X5=%qn^ zbhS^o0AJ6B$6lDW>eVeG4Ob;C|%!`l91nQQc756#xLtn%9a zEr7LpdWs4Z@F({7TVA2?A3x5(*Ykm8+r-FP0kzp@gFQY-lp5S6mMt&SC%dQm-!O%W zmiAK@us0i2sXo+Uh3eBt@TrRDvg2uiT>s=!3@a9^4L4+R-weJoHjl=OF3qy3oY9sA zIQ}<~o*l#V=ylh8bh`c>mB9M5w9A$wN!H!BPHrveG!*{I8rmtw+Mr+9SyBk2ewdru zJBNO+mR^yliZ9ATgClhJI<&Be94$K)`<>sx^aYnZ>={O^2@ zzODjL{#T@+F*R{^5?soUjWt@-O}QqW-o|-K>O0y<0gu3TBysc$%Zvq(23l0Eqn%yR zMLnG+?_EC8YRkd>eJ2-#JUc;2f+&5x2;<;wp@c{j^$XFQAPdNLyT}|9aR6KCuLhNq z{UD2%JG0+#I9xn0ym^1PRaw0navYDEyK` ztos$pVpM5`SnnmhH8lOhK z-U1D*GGnpxhnPQTmN+WiF#?-Ac{-`6L=nov$*Jr|jBaCZ|KXxk=Ndp&Yg7jTaZHpV z$M=^$&M3gzKWhb7-V$fOQ;4+EN+sLInlRf35KYcLg`qtG;I7nt59W(LuLuyuE|I$k3vL`X*Hd`J;WH&HVbs`b4lhRa^x{*eEUI zIN?V8OZjEhj{phWMuZ`K`{RQRnFXNNa^7A*~MApk(437a5{YL?- z+Pu{O?f)N2lD zP1yO$8wc?Bva4C-aZ(s!?yFvLsAIH{!Zvz`U66Ly6~X~KJr$-MVulF@VS+$9&nlD~ ztrB-x3`8%aG~|M|1fgUlCduI$oEAUiO)OouYJuGG zXX)Rac@5A=tuwHSeyPx3!C6hTTj`y}Ir+^~^ntgdLm79SN5bcw`2Me?ae+9YaB}yq z@k&`&tIMu54zqURO**I>kJHHo=d^2*EK=5HE5$N{4HRhmh10ui$3gppL+F`ThIE>n zOt!#`bgt;nNu-rED}%kC#^G&Ke6(9}&V-9gjdT}pL z#t1?(+&j6WR5oU{3v(KvUVTpsSm(OmV*-@$B#Rv~V9S zV;k7Q05cnOHX)-xK&v}fKXx6YvMfO$84H(xYvFjiyVh0vxBJapGW5z>P#In|Ily;& zsytk-Pl(*CvPTgBPK6QTzja=X^;^553A~G|j-m&5+cL6(a{FWg$L{PEM+e<<5d~6n z&v=czhj&@^>hdPyTE~U6v!lrQ6gSM&3yG{BDwQ7sk`s0|ct22$=6u||Ms_`xg^=WxVh66|u#5_`}1(r!Y)KYWcMnjj{>8f&ji4`ozI672o z0J%m`-gkfEeGjbF1W!fB_U9e;QY5q{vP|A}uh$xppd!f2jb$XE$kaks2C~^H$jXz| zTH#=5_g?{|AS!YZ?+~ewUU|mRmcOkWP6;pW9msG23}Df6DU#*V-+D*sdagKFf*y~; zKelI2Yq`y*fCBwTyekxbWPPKfwQLM|4AT#g|t zlzDo`9S_CKgoHYOqPkil1xV#5Tec6owQPLm^Ny)NdSzXJaqR2k|r+AH5g@W-s=1H4>QTU%%t0Hhn z@8S(s{-EGSD;56&HVT>!vEpB>b+PF7DVXz7%H&nv9yw2x%SoL$=`pnOzso(HJp~W~ zKBUcv)t^<~(?b?!oYUCbIF5`;9m{Zzuk@1))`ABV9gO}lhobgeB}){hE0@`sZ)UQN&1_%;E4+|J2rETt>F2TZ{F-u zBt861@eZ)ugYyrr2(Y@kU-xq7&=8r>?b-8_TO?q$hY{*QrUHq_7d~W2xMd6@#@-in zkctPn!(l12ID3N}rc{fs(aIFBy=*>beCc5K0BR;0Z!&HiH*S{0EepLZBTrHi) z9klrE9OThu^{Na-@VLLbjpM{Cwih@>Tg->LczSc)_Il}Hyd+Wz9j}uszHqw5KEa@^ zM=AJYgIt*KS0UUWw8X@1k47(@B%zxR1}UPa%xa0>Juj}mfNvIK(!>aW%F)5!lNR^W z_pg>!9eaAA){mUhn)USYsA-6JI1%I6{p=uMLC+z}#%v=!#(h%@aU-LqsA){)uDt@M z9K7sY#ecbD;(#L*{Q`?3ny+`q<(_OFyzvyGU=up;GC5)P8X~gZN@zJ=tP#2X_xj?O zpUW!KFP6)qz8YEWJ9yGIYIHUpnXoc3YovG1XY+M;VhB$dLe zX^JnrDnhaiFRGQfKI4DN5qkq!Nxo<|W;L?fvUBZ|;)ADJT#K*#jI&C5DvXKZ!>$7^ z{<4z`x(2n_AhzUW{rt$6oF}FxM^)mud}jJj`1TENzYyT1A3v}iwd)>MuMB7=8*N>R zi}R8xLBoAmiEG@9UhVBOnMqk_wG z9(tAb0kUb%LFc0h>$8uUL-muR+vr`j?Ly%414*8=;Bw}AwBdxM$OT-}6tLE02om8*ZX);pHfH0e(S=5* zx1HkPjXz5ZKlGo@b}^Ildp|n?B1=x0!7e3q19~%+bFNlxvFAPSf4!x~JEvXWc19RE z8xLqP%F*LVke}v5W+0N{l z@;0Fpjp|!xp6}{1GHat<*1H$C<3~(1-#QVlNnBQzyf0MOhvq&48W$+H;UQo%6Lmhh zJZ;ca&qkKJa=(Rn;_Yks&6#GEi*iKhaw1wVyw%!p6xqR0m}XE|-J`lwRSoiFimU%n z`#6C`1_`hvcm7q$a~b??MCWBb*|k#~8Ojyst6%iP7w4lIrJ@veK6;kL0IwYOVi7JT zr_Hc%wzUkxBjbzKMFng}2QN|X{Ej^{u~4J^x2H$_L{z5!kpJAE4*Dy@SfIMgo1-&qVu;9;+SFHM6Yaultgkj}YCgJyWAnNNt>6NB% zk<_}lb73~GyOM1_l1Ni0VA3yKAf~<7*I=}^{s|rQG_<@JZ1Wpjy0q`i`YQUB`H2{i z(kfM)tBM*w6FmK)EFER6rpp6x32N?`2ykOWP5)R~I9*S~X&fgoDIC>`7KAo;jjkL1 z(fH7hRdNSS`G@P~tRzX%V6kT#8zt}|eYDBr4=byUR1^oj}(y=KS6IksDleGUw+(d~nx{m~a)LZ=Bo zrK64Cv8hb~`}z5fm$Ub*toLkYsnx1^E>qXjq4740W!8+qI;IQ#Q0Nb}!{aDf&_^Ed zSLmj&M|JcTvG1%ZK&Au>M&sUs;$ZOU6S-milE#XKu@C*lYZQ`#6K~yc3U`(8WveK{ zbjFS;K4A1`)GKYR!?3Nw)PI5E@$?^j27v>z>7f8*M*A@IgLq8g&@U@33)-q)M<(Y^%RChLyfF4zz!!Jm1G7i#M-*DIib=; ziX&eE?+TiYeMUI(+oP68UEVGt)!}0BS18pekSlR|=||^sf%^dYIs5m>+!=*08(10C zvxhr+w*Q6Ep==PIbC|_i;$+Xhcd*oSO-t$2Yg9tU>WlhnBPkEAYt-MQkS1th?<)oO zf7*fQkDv}ry|F3F0Xuh(TD4DR)Yq*=3ZyU_Auo!s+p1)MX3t?Bs@_1&1WnLK&S`95 z&QG)=E5VmIAwR2fD|TjV9c*HdmS|>*hP-`z-U4Ozw0BvLjn+XP{MXRj^%Z4?m${6( zvcNPDRpN0!-+XNw)GNr*HGaZS+Wq|eCC=5bmz}ohk!X%xWO+3g(d|1&XlDY&&RQ|w z#Q6Esv?&zj<5qVwr?JWnFmG{VW7rl6$(l>^(NE#)jH7R@Tsi*C3yS44ggCte_g?(K9~tDnf)n4fTnwn<17f z>*0Z@JY#6_vZPXSx`884@Ta2MR-dO{13goVF{JWX#^VvUQ{nw5v`U3tQ(exLKV0r6 zAnVpN^m6CbtN<`BZ>J#cJzp~>Ckcxe(k$r{D^d01KR#+>*7}lr`UwHY@lDzE!z&Cf z6#h!`ZFYKOX@(#DPyQv)9_5pX`uySzKUA-2Pl5Cn{l9jA(+&iUo2zIj_5T*r3W`b@ z--)1GV3hi7A(2DceN4iqLPTp)L>A}oILe)>lOKa-E%{~Mz-Hf3tNtE1(Dw+2)! zRV)RAzB6ifmMgkXj_XKcw^6le04s@xCN2#Z)ixSEj-M^z0UIPqpsW-rL!a(z;u!8d6NGjYcZ=Xne`r+?ES!w6$abg>T00NU^Kf+db@;ROea$K23{;v}XtkYg? zc&}!MMpz>Z^e#O|GlZ}%o+2B9Sp?4UA^rtt~&Y9HtT zxEok3?zg=kk9&Oz=iExy4>osX|0{qwEX-PZi8hsQX^JUPJ~K&1yVedlsSty=0Qvz9 z4Qo59tPxv|iqr?P)rO1W)DFMN_!p~w*lilIP&}sSGqZvHr1&(YK6;4i^UR{!s#uwC zH&R>w3dM7RG5ax$==0)s`-v`Z`*Fgr9TM0DAv*z|FraUu{1{b+P)dSNB2khCINmO8ovp zRXD5ujD=pax5sBGcpw^ZBjmWDZ+TxxuFPpGHCNxJuSHdQ+zlwvPezhm!?W9wB@;cL z0eBc;{*@_k=_?^?;x(I}`j9-cSQRm^INc`$gw&y(W(t+lhHq)@Tayzr@%ZG0OwvEm-Io`=Fl#uWvc zieVPZ?qh>aOG@|oZs7ep-nP$xz%`})GUJyYZf}3~Z$bztgg%rd-3hR|I%-hv1XaAd z%f%3K^O&zq@Gvk?>sh%Tu(MvcVfF0*CYE3+XF)J z2}oH?{N$V8zkeyk+T#Xkq)TVHGa{i{?mQdvfOdYi(=lDSsV?0~8`Mr;Hp<$~&NU-0 z`bYaICuoUxnn(J6!)T(2N-+VJgmyE?vna9T5P1~`P@GK?X|ux@x*Rw!YKSM>zq=2G ztziSY((L+JL%sWAVV}v4qWG?gXIa8w`22q}qO?UGT@y_P_Ag=wkMMBEXKP3PH2?V} z4kRpSs5$+;ch6q(!6`mAm+6m*Q{HZnYT5(WZqR4q!!`(0>+S_PtqrLa(cRf8J?onM z6Q$EXLC;AtF%vf5`|LI0-TX}0;cp-`ews6QdS~~sWHeH(Hta6qDEUZ4_Te*%G2lRE zGo2+y8z^@3tu<08w!1AxwkU3lotnb*(s%z^080IfnXTD^wDt7WZ6AD8Zk*!b?pPk| z;ry|kCzt{7K)+bcYM$N9O?1*Wu5VRa*|GVZ7&cIMKS8a*H4na>*2>1DW!FmzSAKw5 z^bx$_ab-$2Dlqc(K9F6V7xZ_Hi@F?6&D#E;I(=3|x9_=Pn z#D}7Fbv}~T?h&a2!*9*1m+`$Tm>yd^niF8Y=)_tVtNd!Z(~park|wk$v4Cr;8Bw|H zMc8_QDsbHWWR(mH)9&N#E!%kWjaAL&2U&E3$%i6h@ih-anf;h9(-=Z9Kp}{~#4;@X z&etC(k8cUWxWB#MR>&@7Z~UD>(u$~H+A(wT!kd~gaefP^|B2h}6zODT9ut4M-1M@` zb9i!V)?E`@aR_y12X`#Nt)0DFz&$WKSF;404d$fk~-$}@LS0)G*SwAXB`HVu;mL{y|BU+8hc6> z0j{C?YNuqF{A_Wlm1_@IHca?a?stZ{KjN$lGoIty59>-zrt+tB5b^gI%HUyTFChT- ztw{5Jr+*^;Wt3E+;L*~g7}NY7Vj=phIJ-p-QfPGKF^+ERQ;vnuSy=dz2^{gCm%Nfo z*==ApzhmllY5nQiUL!|eM9RGLDjUn> zmkw>q)uBg0ZiL{ai{-fXNITE6g39};2!ytXWc;h{8ImG?#Bht|pZt&NUqjWMN?QKhbNLW9cV== zN%suTDzp#t1u7S09xv^b$5S6{_8EYsL)LV*J?}a+&%(DIne?q!8#`=n_Sl3aI#kvs zz@6!UyDd7&SRK8#*|jguukR@|6ydEB#dV}F-(yt%-dz#7bT$>eBx&rk%IkOBMlGo+ z2druPHT|-zF#2KaytcZ=_e~aB?=~X9|G{(fIP^npeIABQ&ngwb@Utp)J~CRsJJ2k( zSp^T6HF^aL36`GlRvy~2js(#^PNy5Uq#ypa6uMv1&MrW<>iHD`EY6&tUuYCr2pKz1 zAGq=CwQ4zA3wXp;9JzI$S1+e>*)noFlhQ_iEujOqKGB#OSDN8-`i^Iqp?fhq@s*Q{ zy-H>JviI07`!Pa5vr^pcE2#jGTln*it;vMY@6yRw&jTV%ztDN%J zrBU#61ug+lo_naI!g8w0^)!py;&B0=d>5+hdyjd7-Wft+tP}kK{A6d)DZP*Ciu_CX z1}R0uOr$?sInLQ%r(TqF1UK`5RWqA?)m=|(OCQf*+r`dNBX_G*C zYDIK6Be)wJ*z9ie^`z#w{LhJ{ciR0SlPcksv67i?w1_}q!0QKh@on_r2=%Xh&-p}5 zhbS7ISs|k&x zJQ3dxCGY#AgEAT3Y&L=-pSA~HA#blgtE(caDX*zPz*frGU}X0hOjw;8_!Cv~@wJ}n z4QU#*siF+xp)lpqdUx{L>ipvU?1O2hnekztnNehAqXHnc#*UlFCky~{QJb}X6{G7# zhqJ9@12MyL+*c6%&Uoyz8DsD7tau}73q(Le(64u<*O;ZW#;dk-m4WexS?4H-%|AE? z^P`RXxvFn>G#+ciBbHmL9a7DcNuoO2_W05@4|gbq!AWi471gwiQt&hna415VcERMK{t;$5SxIDJneDs!}#>oXrtAI#1UjI-5p=>T&m8+K2w%=3Kc(5&@w^ORgc zSMI$}JremO5^!gbTkg2#+3{q zo|?=?kv4WE`JU~rl&u$0gNVUP^4x4;4~lody^3ga_kd}q-1A5k$KR1ebXvwH*<;TR6ESzVrA>tfQMP+4bd!oT#Lb zaR0XYEq?Ef2#+yRqu=rVZaK!?vXp`mg5v;ERBBovL1;EOf5&2L2Ia5=gf` zEr|-pVOI!|_E>QlM$=RphzN8N@(O>rMMS*Bk#_k7=ylj^V^un^Gd%B(I?^e&6s@(H z5kT`FuS7d^Kb{;T4B{)TAu=C<1diG}oa`CY4vubVKIyZhEDOT&0#5z|&968OWr%{T zdMSBdp=76>ymrWG6u+*rG%G!fp62eV9NUhILH(?1Ekz`n+W~X!QDNF8S&N5Y)AcVvgd@$)7<15+pc=+ zz;9Z<3kJd?+2$4Tg%_lOU_?XS&Krgd1bVDMbeHzK>A@ZDhNGNBLq&kjBDU|!hSkpU zEzk=}$(qU4`=Hlx@?*yeu+}shD_-@8Mx?A`l%3x%H!?|^`fNVGdvyqhXAgd?w1p;S z4kukZURiY$Fa45Dq~502$l$_uf6FKO43smy+A>_(Y8ILXD$Ip>-~2g!<-04OJT|6g zHQN{0%V!l@8z>04Huw)+`8lfUqN>4U1ZsQQiO*$-<0oAnUiIF&4jYo}^KlD1eirSy z!?|(lL6);NZ68D%J?ki2R*TFwnw7KQGmz*DLD5^(8G8+K{M-8SUzzQ z&-5xY!Gjk~k%*qFke_rlL* zhl9?l!ZAg*W=QG#46`%ffX42XjdCXLCwO;2prj%IWhlD3CMRqG(97YpjZbhxTR9sF z*mVM(RatT`X?!qSGypH~W1kg#H|32D5` zu^CEU1t9n(z0_3g3Z1|hBLn_7s?!&O0dKZ;v1F-iW-RcV9NaQb5-3m-@Xp}uXszgFRT@p=CVx+puac)KhP+Y3 z^?_U2&S&1*!m2clb(-~G-?>1=Tn^S{PR4JpV)L8W&QG>UQr{GjK||lH{99!QPRf0z z$8nprRO7pAtjssQ*?(%gi1-9HU@gUDfy}=G3jj60?vXz6!}o~(!PY*j(4u})jIpA` zgA?Uf54}2lY>}`o$)-&2!UVgtR$B`H=H`#?r6={thnmOB(G+jg#P2tcpL3^?fj}qa z+8&PkS|)EA_6 z-u1ViA5UZWz7Sr>JFtmYI2ygBjieQJ`Hpp!mg1b!cU2~xSYPB# zJ5J6LS&w}r6DmFE2AOhLm^$b-X4E_0WgZUElS;XrFBkkaV zx8~8wbRD_v`vcpr)Nk-I-xS>z@KOp2l{sn~m(!||Zng+h**_KQ9mexcpf)SB%q&-5 zYu(+Uh&WQ5;Nk##y>8jdTAtD&a@_O7lKF13)2q8uo}YjJjpT%mL^9=W8SR=8)3Fcp zf{20x3{6ei^oWcq;)#2wa4y*&FaAj0T$@2{tWEt@i%NF~a#YYmIDzPM-mN?6%54zV zWN!KQdmK%_mJ^{Ilq90C#~G zkRwUYC_{x-mF`~|Q{Z^rjq^UiEZmIU3JDQ?n73~U*JNX&jAsK+{KVSN`Hfr{Jg1a5 zL@kMDsZKxG(|{~hed0&o`CQPa0F>@1IFNUlJ8?6k!u(Gs?hSNZkyx zljW|1;5<@k?9VKhd+kRxPkqih?uCF+6V~6v_Je62nnvKxqV5B;2_wcyj$+H)tq)vP zftW_1J~1D+`#hSXS*l=NR-Ov`nkflo%Ma`yrK8E(B%;ZhBsMsg)As#Yz$4gaT7cXo zl}uyd3iZDjT)%h3p5|9S-vz)(VI=0}KKX>3ktQ!%vwAooZG#uY{y;=KHX|Z z+~6YUUIz8%XPr_9`&%c8e=kPk9@stHl9b(g>VpK}4EJNJ!pQATRi~d?#_i7fDEL4w zXY>Q9dj%URrT~!d!J>EBB4p=yRPCX#ipXeWt|yi*((G=5xYKh_CO*V$$}02#U60~P zP5kuk4Rs8;Th7sX-!_Ubi*<%yF|LdSugyso3sVmkj`3|m(KIE2-*n*q+xUe&RnsC| zZ|_jjnM~MAi7}zxi>~2xT6Jnx0zs|#j6t9Z&usU4!_kch9X5C0_7aOzQLimW9 zht(62KLeXCBi_@l9YcdPv{k!v9PvZrkq5*2uy;OLN$;pK4&N%{7QZoB8{X=38}P%( z0W{A}#_d8EvpgWrbp&nXBQHm@Xu7s%ahTdbST7}2CG*#fiOK2390@?xi%ZZciQZ91 zm}Z6~!_zFhe{_4Z*8d=enc<2SuNqe*(8%*y${IC%Np_Hn^AVuxm*Sfc$t}1JGrO-{ z#eApKK*cicX>X$P8-NQ5dtB4i#sqdB%a9;wo$<*%8cN&eO!LJR`>h>cwgiPWy#iHy z+~UKN9m|6{Lc2$4;NCuW^#3ee5AeIYy^FWgoZOr)&RQs2_5X|>*EK;UWsgH%$+z~A zYPl-A60S`$|5)pX&<;lre)xD0#Ff4?#Y+R+no8(x)#RGs9I%T@ARGwUj;@5mh@Rql z1(t%tAY-cKmQV?ACSGF4SM0&sK}45}wT3^*BKSIlRdamJYp-8dByz;t#m2 zjB{!F?}sIc$n)1=4QE=KOL{BbzC?K720OiFGK!D5-1)e-LiKe$I$@sz-y{=Z-}1yQ&~s!+>Otr z^1g)7ZE0kjM4dA+tGavN`D=#I7Zt{Fta0e@wL+fH`9Z6IKWoBZvU|GTS{-1&y?no*~p+hLHkWr^FaCs`>J$9J>Lre0k z^f^|jjjM;ztI*nzq$0E_&f!8>p>N`koOrMQeN7%W?yDnrI$7qaI!R@pm~4d`L=Hs4LQd@jcvr&< zj~z1e=j+eDpBhn)T@?(lWyT^A zH>HlazIV18Og8?`nIYaG#0W+#{wdhCv2>vz%dS)G73Z#p=6!bQ!2{Yr77SLj2DyJN zm6B)W1fsv~L3mom14KQ(V~@_#PyR6SX2Dz%B;8r31=yyyuaypB+Q5K{^O2 zZKj`fuV(F@Vm)N~M7Yl3-KggD)C;U&8@gK28f=c-t=VZQ#>rt>@yHl_AUTMDP-Y%P z_kUo6tkzPUu`d8Wsh$M#xFt#@Q#NID`UR4S4K!;q-?oG(G`%Q~C0G^Jev<0`gjb6Z zp?@O@Ecpz!H43Yav()9i^sD|R)?`mN03Q%Qab#TI%@5)I|jwLN+X)?9MfMwRc= zN=mtH?SE>wPAW!5+J+@SK(ia`0nYYGFq|K3a;Ggk1nu}M%9;mzIO}E4S$_cjU6|f= znqs?)9phG}_UCa@h)Da)k+y}arPKi*-s$I5pydLJ)@T&^3m^0zHq@d#d@>`#uSkpr z-ML#WAW_Lk@kM^2nfMCa)2u=bu+%+CDN$UTUG^0kEd(1L|->fHTYtz@r2 zV}_|wN|_t9)rmmwrQ5do>??(J%8dKt|2VqFz`D96dc!Za&BnHE+qP}Hv2ELG+}O6; z*lEKiY0`J{ekXU|bB1eX*6cgCP=sMMhfmblzA&s`dJwk>3&f+RyE@8?-?TX5U*GMI zc6Py9NFS1Z0-{2-)GU;8#cKpxwSs#) zGnXb{L!vxgx3$~3InOS1%%5zy+OuaD1`Ld2zIVLwjvl$0ewvkA zQ0$P62<=?Wv{bf6#Aa>(TGCd*9bBX+1Zsu*O?^k_NQdrBb(0MHttwz9{9e^BKv1LY z&*0FV{%Ha%$8_7aL8Wga=~@w9c4`SfOCQOxcgPoWT%tmNShc-u0o#sTbfw@p76v(v z1OW2i;j4XO=0Uvrw$gupp4H0D49xCgnU!~M?ubmLLPU;3(cTGF*>W|TW0 zwL<|8-K+A3*l7<_*e>Yf@7OSlBQw2d$I-Zn7Ydq}s%Zg($|)pNz$OlsZOv!)dBe+c zTRqP5Rjw^z%a%YAwd|_JgNqQY@t(+SF?iIcD^9@l>K*rO=Fb1~A*|>PB979a_kL#w zRuLz85;4r@OW6J1MFK=3X~OO_BR2K)5Thu7w>^@dEg948K;P`IWDYcG--l9S#!;8J zML8K>IhTiNSBr?IXzV#GxemA1qWtL`eo~HcU)0BwsKkKYX*OCp!h-^L3CB7n0jg~q z=Q+j&6pJ~LXTsXUecCPAA(-cdNvoj{I*W#>DZw=#BONoSDX_-U&D2ue5iv5c?2&_^@Y2&Dzw${n=`5m0Mq+WaQ1W)o2?v&61Yg zPXD4qzoi(ZR(^IkX_lApM>WRd;OU@y8P$(o=u7{Nvo#EAN;o+x9Hf}-6F-slxZFV6 z?ns9)b2Cvz@Xk%<+vshg!(o;gQkV2?I=T!W0#7Q~CsBaKWsSOrU#k@Q2bEsZwz`wTh#xJ!#z?=USAHj<@t!rMrJ$GL<+t3tTp+?T%6|u@1PBb1 zE~fbVg&(oOhR7~!Z(vnp6j{;AnuVvBuw*F!?-bt^U;WqQ~=Y%SglRd7^6`~$>H+RfY~ZK?|m}b!>fQ zpYs5;_Lgmbw6qCOw;{Ls$7_^X@##!i`nkS*GgWafwI!BHy-jSay-qIs_T!K0C_L3D z98;v|$gGBvBO5H^mu=wso{f^veW#D;8cfs%liOu}xLTHcsCn=gh&}Ih2YLPow6!c3 zNpv#2Od~_BZT0!9rH;|JLu}sYqzG%(%sNB*M(GUuigcNW4) zJg_h2cHc^qsWk>&5*_y}W(fw;h_-BA2g4i;X)HSN00{HIe}j_#1BU63@YeW-V8fr} zEA3j7slC0DO<-6)omU$Q$7@h)ye9e}oOuufH$Vvv3eG;rYps@01Biba%|&^E>WDev zyp;g`8aS&JpJk;BNKPK_)kCcq0>CveAX=L5xZ8RvKiob$QDOydlC~RvD1ci}UdVvn z5~xNA6w(mwrZasr>nXVZbDomh^7BK&{q?9vpLyyS{2P`yHCz}lWLIv6#`fU=L3Z=b z9exwBdtD!=3C({s7xC=%mxPg`VHyNJhq1;MJP_*hN5c5Xs*L^u4P3~kLTKk!07l0-%U8H`RhE8bHm z4*(>RRmv*P5mvaMPlf=c%N*$Qjp!9_>hMbpyM59TX{aWDJS2a4DZO>LX~*Ol&uI${pZLd-{0| zx8F?RQ&9OI5IGfU#m86W^R(L~AQtRR;>PoV=rn>o%yXo%RlquqR8V#5#;Q_|C^pmsyrYF5lH6vcWZBCVt8K4B5(Qok{fPD(4j>}mvw)34kV(gX~^+S|v^bUrKZ zf+1W!X^#4u;Ls{m*s7?nJ;>K9aQMC;hWr+d4RU}_D z1Tet;^5RxK8&2}1DV20M*eJ*Sqz8Ux!T7BPL!p9@a4@NlAS)z793*F!gcdE9aa3hl&P`3T#1b*5P3S)}$?0 z@Hi*QVCB^IK5v|ChEcpIk9#8TD~e0?MJC^1p|`v1jL1#>0B|f{7e)2CDmMW243#M) zlxQ?_z$Q~n`qEt9&BU0nQfg$J$Y)%5zr&7q0C1oXtr#Sm)`uKl*&wtUO6r~NP%gR zv8Y+zZx-+mpe39k=oI1d(o!#+N^Sd^Y1(Rvff<`8^TCn7KI4vP{wwi_O8_AJ2B$=` z0r=!C+O1tiRTjBTI)+^F)paI^o>GDnJ3ZoqAxYCu=@L?HY6%NaIxB* zL%5p)53rp6y`Rc^PHiKynLrfAOf*}hx1HUEUSjSvju2UwadK`t0R9qDs_)bDfg(}* zIo1%ps2C1laKY)BpP;uxf6+9FUR%0akJ~Wr(_bo?u#4YGp?5`ilJoobfjr%iC09g4Q`|xR=MRla?bKmwe}F zZ1aBUxzSL0A8Dcc=peNpS?jgFy2XDq|kP)_(eLFV>x z-0RoSDigq2y&5Oi;Zi)8w1Q$l3gjqa9@k*Y3m2>^Z(vA>H?movQxbuaU9MrCw8QUr zh&WDi%EBXCF_4y-cB#Nt@bF#q9}!@oVTg4TyPoEbsf+(U&4n+v9WR-T)HPhG%znA> zJH>O6pow&oni1dlcS#j*w75`F9&u7OTp$@t^cYNSiHhX_`tU`{kHXf7<%I z!|hdK;&QJTuo@Gm=DE~kSig^-Z-A)Ka^A-JhD7w;JqYFpAQ?6Ma{rr8-O1cd_8b3; z4KDYNuqe?HM{pNRT*vk_Noj(2+vECwIFZ@XGZ~2^{p>G0ZO-slM+!K|!kFQ*ww38+ z4^gl_t6pw9HV-+Pqm*{D^r&4(Fm(RG!)?p*@2uv@ZABuR$fq`b;@mp77| zt9zHrx2yi(A*E__X2(w0HQGQEWz~0nE825GWc!TEUD{I{A-CWF2B@9OsY1kzfn#Nd zV=AqSDQ}9JS@w+mYtE6|boxtODzN69u|@glZXN;li=w0sSN!ziflJ7J6T>aH}-9< zLag^q=Qt(Saw~* zg(LbtML4z%%)g{5`~5Cy?jh?$f5`CLceuk_n)Q9^1Mp8xJGx-4?(P8Sccd!^MdEAu z-pW=ESpF))0NZ;3baJD;RaLs%V*JKDqA*VvJHOKS z{QN>5m9$}yceRQuZ&lZ%1R=v?n~euuz22rM(tqL*>Je_AM#xuD2 zTxwn6yQq1x19_{IP1>;l#qI=^R2%6gqwJ2v+&Xwsn*1!(*<`61JO9tsJ|TkWr7M4B z%#17E%rMRdn{o!b?dr~2R3nmLe&A^8as&9OWq1coT+9OSsy_?JDu4D-$12|Dx*Nrz zQ91GE<8uhqzxpVB4SaGgOffHo99H37=BkyID+O574r=A?T}Va%p9~yv2JLi7XcP^6 z)~D!ja9Uy%!;b73AyN)`^?AV*`gqiWyYN>^$%lHnfi#%k?_YyIdyjbXp^UyJVJc#n}PlOF#_CwB-FGMLkJNHSk1OArHe1~I=m)S4UD(9ZGTEa*k zASnqP@%&rfQ3Pi|h_>l4)N(V8amx)9F~L&bprC6Wj|~;10+sjv*bOo@-Sq677Rg<2 zTgut9#H?XqBQEOy3AMUx-$uk8U=zuRFt>=A>9PD2Pk6N8905bWCR$no;HkF@_jV4N zSkwjIzS$g>&6U~>)yiv5>XJ_zPjM@DGurZ-pgMKi<0F~_lbu+}D+Di=p6ZD7rRqC) znpMwSahoX#*loZBNNA<-Vs7q%#tEW7cSwo8e|)oE@7lV*vJ0I zc<@g-I?R=s^<1yR;qYQD&IFsT8}B@l4!C{pW}_y2%Nh{8zR(}_fs175A~Xl)S2ElG z9)#D+TByMaE?%m2RD>@8LG`K+^gs8`sE&QjXl!%E-X=o-kxtF=bO4SUzUFK~stZT;=K^C@QZ0qZQk<$B+!9$d23gF~S z=^f>4Pzb%u@JY2T_!MY%--fmHM#;Aa+Rn6B@C}oLMwb@5`K|6pfBJ0om9yQhUtHUl zVej`Q&mqk$6|12i!H2U6dODIyBl8DF=PAbTs2&(Fjvuf#&n-uJwR2U;=;Glgp&?^v z{|16e6_E>;?&Fi_mwE9l?aB1a&4rOKG<4?zJ2`>7*;d+-#UkOcg~fkF!q1YS(=9!e zQe(^to*6CHadPjf>+rAZBOZ~Q4AvF#HQSdKTT|WdhS()q_5VtciDtm4FqioK>k8Ru z0oDlU%8H(=mc$hht;s?Z+hdB!LEu39e2y$LNAuCj%N4=Bq2Q+}`g^&RE2F-&#GD^{ zK9}Ly{&Eme#T|5dh}w*RpDDk^c4?H<`6!nY^&bu%$=4b}fwu0>XretK`9bBfs^_!E zh%>Ux;ti4!OPUpY&CbO!4u=)(#1k|O)gJr+P!s;dkcx(8y~S)@vC3l{8kUa$XMqb@ zL4X)VrvE?d1PZ*(JKd^lONs;O-X!U1deeu|86{|NVaJfYh5kC<1H-daY^#{SYhW7p zFoeIZ7CYIB=36FT$Sov;%zm=WwkKc>ayPwdT?GSprH8_Oj(wjz;rhz!(zKj zYwHpj`~B5n*28_B0bgScsg+9YXLtDV3oOmzfd60c{9a}YY9Wp)(>5|_m=d%GxL>*I zm=kWCHVtdh8V{^fm>3ZG6@4!VL^Ihx$))65iq}_O{JVCGnnc2z`IKA3mRznI4Ds-u zl__ZI31iRDr6kW^*6SJiMcjDRFS=*#wl%i+BL8Iw;gANA5ExCNA*g*5278j(6!I}i z0fNlJ9wD8zf)c!^{cL+rx-aV|Q_KiQD+tPRO?@xhmF)DM67C&;)0Ho?MReY3>Mkv@ z4mGdVD%A48kf8(dAJo9TaHaSp6Cnm{i4#=btIzGrGf zhB13)5kRD7K!w~sokk#wT&%u1w!a;@-SVvTI<{lbUKhTW!mO!a!J zk%ankIM$vqH$`9>P%H}?By+kUr)Bw6ny9!`)pG=wb`%u6jc?*L>ZgH*s?MHMB;Wt; z$z4_3ET_PWb3wd0U-oOzhDpAI1)KebKfJ+FK&==-F(NIo=~CD8{?QGwQgr zl#V`nCWgRh<$-+Y*k!xga!pYBciZZ}))RL|>|Mfm_g&1|v(Zlb3OdG16`m3|7Qy54 zeZhceMu1*RRcfM`Zuu49D4D5}g-*76i)vhd{<^}20Yq^}%r@@FjF zFzg!mRth5`PmNb_)YImX=SSlT5%P1GWIs=u5N&gMF6DDMmI-Y8tzO$ZBRnRv9X@P? zfZchAZ7jAg5XJsEq6MN~&3uPMdY8%!L+UWjgtN4S;w0u+LCG^-1e~8>A>T95*!HN5 z^fL#{CkWc&WGla~n`M4{PGRw^Y+X0LoL{7);Wmk^PlmxQ!c%_s^~`JjVX>?KJWXW2 zC?`h~%mt`3Z8J{osRni_d0WLTlWr_XhqLc^VtXOI&yO>xisv%OdEfgO{-K=T(mWcJ z3ApPda$I;CpI^wVDb4p-a&S~AWY3P@kpJgnDROzNd$MsYu>3R9rA8=3aRRbtI z3@i0kpu{-5@10WopOkB*CSswynx zdQhBpm41$wswQJSm7!st>|Sa$#(&p7wJeMHBgLczL** z>k7`X74+K~6;)ye#XfswSI#;-#BRN_*^XovLpV#;vSkImoG-cv5*nIs?eUSYTMjrzc1k_Vr4e zSTK@jOTYY0;`1sN<(T#*Jmyvk_SjMnA9`X>WuJIB>#vLS8Vr>f6g+T=50S&qqr)KB zc|!&xR(EJiZ2>?yT~J)jo34>pdtnxvc5^%$;$be@Sik4KX(OvQ6$`E+&IApVwtS^B zKl@DPr!2O8giVUwIXD-m8TacA`Lf@|-f0=T)!W)vmh0DlrTuWgB_0lgN6y13b_>AK zw=OMRQEttte!*n61z^T6kL!cpnRcIu+^*9#;khI5Bi_POctW#PB|@sZ-OK9V)RUW% zaY$s4-w*1}Y}F}o3$#ZM;W7W_==F4;Kh5f?b-2Kc7bg#<1Y%V#i}-of6$S8VB~NE} zO&(tnL@6bhI{*ACBEOlN13^#gJo(gb zYHn&S_LT~k?7boycmsx>|Gou%1Zn+fAId`Th87lkvab?FmvCD*bI^p-qB1e(WX)Gm zfNyX|Px+;XOSfh0J4#!L46%t#TD7;utDawWq>HF&-M}~A5xsV%`Ut6adBzU=1^?EZOc|fIo*4% zZirM@DpALwp0P^^@yVP4o*-Sg>#swWB*~k#K6p{1;yUy~Z{&Wbhu@|j#C5)hU&Y)L zs85!1W!INNW_)f&g)vi#vgr+{jU`eVu@htkVmJ45#F{F#J%hG76;-qNGNcNWX&@G5PZ|uGQlf@SP6_fP!`2N1aLN8*5YoB@SC?LRG3$L3EYWnvEv!+~VH5gDlPcs}_*Ia#Ax;H=br0{%QMHQ|* zT4Ovu=Fz#%I=ED{M7VBVnMUGwZP2E?YTyF8TXGKe)-ETzsF3$G*w*IudXv?mBLP7P z-}W)7uP2Krb|XV6*#=r6l$lgUFBs4u!E?3N^WtTqdGD_FFd?lq5y{Vhic!zkl6a1j zh9{Og{ALQWrzZ=yZ!GTDWa*Nv_Le`(F4tCAe}n@kq!o5A9mU3Q{d)5A=7^o8RWdaK zv1Rj*8KIjP$a(?`QQPw3GSZX&5~4oB+oP$RHg6hKo#8#xo!WJlMZLo>xrc-t7ENEp}R4Qi$zk!xW%D~xUd|nGSy8j z8!>;1x*YWUI1#nN=jNmG5F2UFPePhO2ngY(PCLnOJOc3>%$WHGrpVN=4vS_>MStp~ zV~TKXmzL!P(Qb~uB!;SwSQ6su_Nu4=W_6z%kEGiDjcm{?dc%%SEx-8v$Ia0T4~yu3 z=4#Gs_$d&(j3B%ga`~S51Nz7yp{(CrBaHRcm;NuW79lP;K4fld=Q*DZS_za@7$qX8O z>-WTD5p2w^Uw+cZh&*b9^?`U-bY2bH^t;Oo_xj6Dc1HxHHm+g;}Qx^*G<_kpu$TK9E~#CJ`qNR<3J(n${vHXTLs7SnP_^yd}rj zGO^^(#YkeM$Zz;2L34mZ6g%`V-yS1wP~s+Yn(?it_2)cDEhia>S9yZ7-QPb{-bIpB z+TA`CfU9Q=cmfX+se@lk!mTNJh%auhg1a9EQkd4n=!4{JG@S9RbH-9^H4q1iR$fK03 zzt;X|9WMxDwwf#ACxzKYm;F6E+K~c99r=3Ou&?RnYE?t)P1G$O!E>nt^;{yNcYxc^ zN5%a-*j|YF&`T7=zVb)1#$>>_%!e<$5V!Vgf(R>??sdin{y23oYbqkDl|O26hT~dN zW2blujyYL)US07A=SBU5{KT^FfUC>q<9xrDl~8*p6vgxCflW6rrYKZ13wMtL0+7ZO zR@-)0tg{=;j{kDE^`P28{7U&Jo0^vv{vXXdy~kxEQY|lA3a$QI8bat*2_Ld%51W22 z?6U2~t|NlK%Fho2J@aR!*@i`3?hrUrbmvGNa1dfwG{x@22Hp+<#s10_L_J|%{hzJ0 zLw&n>@vnI_N!#o@`(Gm4>28s~D&`rvzPCPmcE+%j9Ct^$WoA-mPM4;vnC);_+b`yX zV1WyZX>u9Ua3O}&Xx8@h;b5>@I^pF~@^aWFJUH4M3d!iz1}3IBth zJY^sr!qPloKR-C4&F!|33R-P-qRpOKD38WeN1>y%_FAP5f)L;W;>&-WvVUF6pywQI z`z5T?XA8*Q{zAvYMPj3_4a{i#&1?RO;u_*Dp0NG&pw;*9UG1K|lfdn<^}oM{TkZ8q zp8s}CvozNZswm^QN1)o_N6_l#;p4yg93PwOhM4LxqX_Zt_WW))`vv9$MWde@S!p03B=`-$-SGJ0! zZ+mP(+g82)h0cko|D3MaW3i;bPuYN8Mq3=FOOIS{>-yHbo+Z%+X zGvmsukIM;V?bBvyu)M_=@FLR6u+Hf^kSt+3m~9#}POXvQ@%_U??pFK~5CBDTd0U*| zueTTV9zPyL(=^vo8v>sMw%;aiQ;DX`qS+ZDOshz+;z~m`c_lj$fLJ1U@33T*0j9<9 zSO5H`7|%|JQQ(^-jux5UtjRNbeI~sZRY*}q@L8W;6~|evuTa6nx7V)sgV3SC&G*zM zQ7-cbi585{#8)wmpxXYU1#Q7LY!xyCvpM5Yx2c^`w>P944OVN0Az9WdWfoBdxJ_;1 z5|hG!XG!OIT%3sTBE>)%C%)X;0uz;IhR_4@(2Ne;6;xCV&1GE7DeA64>!dotUPalE zAE`Y(wQjYA9dF$|dZE1{KW?ERq{MY6mc-UZR6i%avAcNidV2Ey(y>Ui`ObE4S4DsV zM9R3()*r0OOXy1qG^-vw)VXJk^r&_^LNIjbovstSMXW3QQ^z<8a~V`BKQ+($Z!#*p zKSDk{7xTqrYcFAAsMx9~6bVL10OVHxD54BzCDKsNyNOZ%V@DrpdTDMtozqO?n*}Q| zoy2+Ec?;50)sfU+RujO^2&661vHXEp-NTpgv|&K^%UPY zA-o>lhYld@LjR)gQAz??VK>+t^VavaKcv=GWG(W(8D~p`Kc4NAPS|vFs^t&)`B#-z zPZ`@+>2>%SX~!rt7D`F5IH)gta9&{mr+{5|!puo{XFyvGN=ST17_{x$7L(`@(ZplZ z^>gQD_<37)5NHjHUqU>U9Xj9PpDmo^Mzt81p^1JRrdLe9!@0DnevD%OTgAvJ_o&~V zQ7Lv>y3TadJ5CV;gvg^FD$je1=xm9fKyZ^QZat4)6~LS!c9T1e8LzJ=XxX+jB>tWX zF{%SWmpBx{Opt`%hNl=EtX-2F;%S@w8`iV+8>X(J^I?-MLCv8L3J9-;T&L%Oi~P%Y zj6A7jtL%)mgCw*AmZ9dkZ!w#66xs+ri~sj6gf5L(%r&cqd@}O zZCHv$Lo2*BYs_VEXW?KA%B9WPn+0{YE}jrtPTc%Xj5W(S=OYhoYpRoqS)Aly$$pFY zElBSiN1htpPLO{M@d&M*bW>U$uoDxJ1(sz?j|zl+9~d%v-=uF&M}*5AJT zG5rfoqPhIg_&BYLr+{+orB*~nDNs0q?r8F-mDlk*|e_Wl|+Mo&XUJ-vP=(h zvuQ(xaqU0Rs##Wl_WCckUw8P=LTfX1MQTZ=dcHK6TIQr!2- zQZ~xIfEtkaDyf_c^iRYzCK?c2Dw%Ip0qA?doS=b({~m*Gp{hWOAoJDeHH=ZvU`<>}HbHw?|FB{h!$ z$#F!Ekc{;di^jL^P>LU&E-HFbzUI@WCOop$?pP7#EZnt)2w+8|(C-DuM0m%2y%b0gm2as=W}Wr*OpeVqT05Zgec zsO^Y$94rxlG?2KphS&~car76y(#6l;$sOBr5#S{57aMbE`f>UQYUZhvpp&j3#EdL! z+&+2?29&DnN%@&S&oW6;r_L59xg+!6LDbtC!F?8-p7w*Y8=CEW788s(Y1-el;H{@2 zxKh31GNQ>Hj#^28U!3CA>_ch51{na=9=@FXQVs zL>^Ib)s4xMdVG6%uXoQ9eAEW2VHggGVfCrg(WWou_2hjmZ7NMU5z(u`Ka@dmGJrpC_dpgS z0#XEYb|PxyfOVR(>xgGm_BBg`3CG+O9-1S#u7BHvbq(U%0bHNT2wj zt()ma3dDA3;Fe+~N^}iQZS3ZhWY}OGlXKZFZ8;F)q0WEt6leoJGLsVFuMmO4NeomA z#~_D1`8yxU`94;Pb&t7Dbdf=7^PJX^CR$Ja>FRsT;lc{b*Ba{X zL~D$>%gBptu_`%P49Lfv0>myB*+6N9M|76P1P}P}e^%jp{|SpBW{^BaDmNF>ce93&Hkp`|TYu;Mvc2srp_y85P7v8E5tV>T?% z!o&X!Do3w`GTh+r(vHy$}Nl9kV@4b;AO;mbOWIf-H$Nt;x-rwie)= z0hjC;llg+Y;b{L&e!hhtp3Gqawcec9MKd*3N-UT-)V{7@4h#0zDp4e3TR|D!@@2~# zlR`sx$5ltdL{yuePCVupOk8#5_#gCK9jt`Th+sgG+Gg}p7wTB}dn%+jS$)&u>#Vi{ zBWC+f7|kM=G^Hp^6`pH|Z%-&1sD2kbKm)9x>rcs0I)@iy&84+daY2KoPR|I2f3Y1= zCS*#a9sMuh5jjJwQmJMe&c3nVn#;mNx2IO<@YhW0=?wiBu2Jy|8beH>=w?n>Lmajq zl+VPD#=wY|+0cVc(U~w+`E014piGe?PMMl*Jkd9gF{VXN1PQz}$STbGinS@_D(*<1 zMtaDg8+v9n*FhO^nxhgo^M$uOweil|V4LzGNeV?BKH@_`3d*_^FuBl97j1#B- z%%mxV`;@9nYfNfuPGQ6FJGWy?D-TT-6D@s~X#1*LimR0=>{tip2Q2U#j$)_X*2(rQ z-?Wb;#Jk59Uzep#pPo-0vE~a3iA@(*W!({^5J@ej13A~L{XF+g|C?)5Mw26#r0OR9 zm!-ZEOa$5>2HfS2A&EF9GVyg}9+aY<8Zh5Lo-d4OX=)S&8ME5lybFr|c|L3O1zGsk zgHmto$@#gy-(2fqBu0;@x}R^65%TfKq%PB?$y%wr05I~%)m!t|owJ~l93MR0iQ1xk z?~=*!Ot|@OHo6YapVlP>KSfCx*Z9AJN*esuH;&C1DabteEB&d?^<5(ouG)L3p8gyME`|)Y^wq6E4mE zP5uEL4y|&Kp*uAlMM~hF+14y;5DS8hQM&N!TPq(1tNjb>r^9VT9*x`J&ry5L?S(hI zz40B1&nn86F2!jj%@_vX_@z#nW;vA5u-uz~ggYr<=-{xw7=Ue-@;jLl`+x;E2svHh zM)_X3kftaw{+$PCt|^r0b$Dp?jkm&BQVz{eb~(FuWKvmdE-lMK^wn#iA1!BQ7#I}< z7G{n``kf_gcP#x3Gh-KAl5?mBQ#f_?7Bm9cIHoIBure}`cAnfvfEH%I&%#}6_1W}P z{a(kYs1NKP9BZHo*_JmYCy%8t;LHup(cO;ZtHnaEVDsr_Z~p?eprZhqZ4a_)XL?w& z)sK5vq_=glLtPFe7UWixf)nm@s7vJCS`8>4PKM0yV-|~bj3sB7NSp*u!Uxi3ufufP zis@eZiQ~`~uHHbk=Hr$xBb6C!rXZH3B@C~-9LH5be~T#HCD$&jH-QG?x3~GExC_Jn_wt!D@@|JyoTJdUbje6x@qHVf-*^3jtz^2T%ea}0-&cgk z{@?F@hHcgt^E_Y4ocy~D(`fr|#?}jd62(hbNT1PG*tN5C4 z7IAQM?O6HV8Mol@Hf|#qRC(mWA2WHhf@YAfU1ZOBdgd~o#z70Xg{?6;r?HObeq)0C zn~7{JLoB?z{LiYK zeqrvqQM>(EDCFUW1T%WZG}N2<&<$B&xV3zd#9i_-+gq)0fk*y>?NlMT|>1aC`D=@=*4^iXf@2 zyGQqYE#PoveVMdNC|Mqx#5b};K z#kq!MRq6!MOw>fv7PmKH6MTxoMm&LUQ2(Yz_!$`ZxGdRy7fw=;B^KnvqWOMmohvX9 z<{0nogwwvKmOsHh(njeLLxt*>d=!xM-88u98Y-z$)P3I---IzmH`Wv$Q#53NAdJ-JqYKKOpn(;z23@jz79Q8hPmHbV;!U2D>1%2F)2 zRH18@B#dG%?{D(+-78Mb$cqJie-b`6ZSqK&8Sm)%&3Zk7bgMu8O)`_|2t#bwK(8sN z*E-Yk^)t3Ytit`c(qut=!&FgC=Hg()TCvV(@ZUzEU!VEy%EBGIfTAAz4Szg9YRuZb zDJXIgT(m|hdIp(Igyp$c!vlc;W;{am3<7A zZgy|Kb)oiR=x-vmjk9d1hi|};F2q5*su*nOOdGw9RjtAJO7;;h=s%Gp7Q&sr2*)0a zBt|3T#T9)Vs1h{@y>1)-x`8W!n>iMjfDl(sMQw6woH8ik*0(SI)S)L~-|^9{*NYj> zeR=x~vW;Il$%tPSmjhO|xZuxrNGIs8aV{$|f-?;Tg_H)dh#k%y#EPxY5pmIn!99Ts ztC?|%%vl4>jA+wQcX>J-@LROZX)L{|fJPb~&?dZ-2`TzoEMGALdFf<-{{flaW8ym? z6)6i6;ar~({?A8%+|>Wf&xyEn?nziJ1HwodH@1?xKw7N@H2C6Q;L4-$=Yc-QUIp%)zc#)m)EP}LEdXhUKYp{Vlh zrSidSMq#I9kAp3Km-7#P=*+rt5I&&*v;6q{+;S~aqAJOc50lIuow|lm8xMgmp{<*! zGMbu0B@x|yeXE8Gb*On@^MI(Euk62J!W|8b(AGt|QXJ1EX%J4EGf`|bQA5^FqlA)3 z{H}`t!s8MhHrDyspvj%jPUqjRV)we-ip8s0e=>D248Jll+B+eqbdnwA@BT;X-UwK6 z19Sa3vlpky7sfej0<%mbgV7R)8AV44k6@Cjgo|^8rFuW;5uC;Uyc~)%uuhQ&2vV>! z$uV?eRVZ@W5ORF#&gSMc7cX`e_hdt*Hvag(g|+Gv#|Pqp5H~@2t60!*cwozekPL$S z%bNO}-va^&o0RP~gTIkZVA(o7F8>S&WA8yJ-@74c@8sF0dL2sl(M6`3!JUH)(FN}x z8W}R$03RIy8{l62ao(>Z6LbQjmZZG763&ww9NWQ&7$MFC#!(zHUD<|V+8x5+6DJa8XT zSds~%%MvY)%o&WEZpe*|Ud!0rX3bG%q3vTiD*-W-q-yV=0Y~qZ*W%f#g(t^I->IQl z`_SdA3m7;U;L~}Hs5;w@(*E!j?#uWG8byKR(bAK86Nhij!^#{o)$XyxiOmk~|AbiJ z3l#efqOYb{2CZuf>r^c13e&5XUdt$uA|?KU$k$seMcy+bM=4n%3#&g6Vle;=%_u?3 zFy!1bn$1F}N5f`&tWnFgD{i!{Fs(C83KRNJQ`?#@8RcvKeE*dYyK%-&*ZGY75D{Jd z)jom+7f5Q#hkh&q?iXaSwOzeP;gKX0S!0sE)tx;Czq2-9G`jsg3R*VvT8TA70-^rq zth0+^AVm$Q{%EOopvWk(rl)DxL;BOVg7pv^q(EYy`mE!|rN3!kF!URtoDJA$aa&nE zDgC%1k&);N#e@hY(PJ(rSt!U4bN4Y#)?7Dj8IK@`<#h|p0Uoe=U_g$=H*Fc({9zo> zd^2H|+fDi~snWmh7Tui;v55L#T#xoA~JFu8&1tCSALe2;; zQ1YjbZEQWu7jC7jFSQ47@V6#^*oV1djsuBlEpkbD?&SoR|s{cjppXd11(O>sI_ z-=X_#5S_xyvudO+z0XbGX6nP<2Jwa9?Ipu)MWw%xx!u>jKC@s;%K-LDv?0c1`Q=eM zx0Us6k<#G+Q*HkB_{loQW2CRp!aaJM?yA3_LOmP?JVB?{^b-G`HgI*d6IR^wmBGpe z9{)h)Wa*T14Ok|A1K+9suv8jgRoeHz@KvA*Xq*uraVV;c*n8{PZF8tn=o@D|-&ow% zr3zwH7_T@YUfWYEndOIV*=fK-yy`8&&4*`QxVeJH{Mr3{`EV{xz)`1MO-HHPf%8+R^~W~3E}(e^s3y`Gw}(EfZ&!?ety0C^(&eM>(n!W zZv2ujx8kr^AN#_-#Xsm`N(P7btXIi6kl{_RHK>hl)aonopUYD`xVd=av-U^s_sgI> zjQ8BxrEIxas4T?=rM_zvpZB>|UH|K7Sl^R$sO5&vwu};`pcnA>rERa}4~P65zd(`u zDv*tal4;5leL$>dogkxbdT|N#vetRSW8?D8pV%X-IcjXA+HF?sk?X+`E%=E`8sUdP z-!FfL-5H%T6;GQ_&=coeF8f(>vUIV=!6;oi6S6lkVtM+6jRC{m zo#Hy&p=fc3;_iCOcYim1lXFh;B*&#qr4sh$@wPSRV)S!3jFa=zg+no*u*zfmVbxN| zj)daWwD!&ca5LB$cO9T)phhw)yODk^QU<@<`T`e~Fn6ioNoGA|piOmr^iAXv^lrV7 zfsG~BE@mRPpBTKmUp8^7c)5ewf$qspF+sN6_N?g*Swc00AJ-%ZUgBwEIhVT}o6FR| zR9wTh>oR+!2oFPJk;t zLhUzoTaY?OW^&CVcZQ(9Vbs3b%Zl2|^{GaDV&xm3o#`5@=+J!)5{L8$fcH^CtQswe zw6k6KgHngtvl;MZe>Fa=sfC?dSyZxv`q_Seta2?<`%M@CXJWChfwAC)I2wMQ(y)n7 z&eoQ*&<*{(rOeO+;Z;(oX^LxieTl;61RsE~}(qppxp}!Z;-5)t_hZ+r1m}IrGLx!apwmxcJt(C=^%RE-J1P8PK%XNY# zqrlTz`cEpzP8BD#G|@9B&;~OAfGK`7wJ%)D9O{2KXRti zZpLtoHoi-bTH$A@DbX7Vhfsg^bNLB3qj23q+$So5kydoDbq}$h13(=~xY&J*9J1XjgS8ni6^&o;uV%MhV z!Hgonat{`@qCXqWph5}~!@WYbew!EY4qp-Oux#4tRv`LEESZ@2rhRVmSc?^JWAJRS z86kRqeTwE$Qgi5%|L^%slG>06-;ZDaevK16tAO}P^FUWM zZiOWdR^Ty6p3grqXpWEOJ@B%P_ny>=Hhf9Ho9U{T>YhhmNES1UC%Oy6f01B7tSrE~ zn@|M~ybl8MU){J(PP+UhPJ+nr|5H~UXN?TBhm3@byc3#@K+i7?&RuEuEe~DCQ6VHTuMT^8D&=T2P>OO zd8&D$g%klzR~k27&p$C9?Fkix&-esGCu-;I$)-(K$pU|lPsZ3Ler*w4mh?0fiB_%_ zHnGs;EGKIKR{~JUBi_Vads;bFh21~2SUFp#Cu(>78HYOhLgFDL){rq143r~+k}3K& z`#reIdq;D2p6rSow0&3^3H;v0-pm_Ve-G&Grv-Jfh+OCVxN*80^(eP9yWj{_)i(pvHkN>$&VLna(l)o{ta;B z9z119dN+323=95IVv85@dZ+f>z-WDLj;vqPjFpi0mh?*jY~NclEvKd+X&tWOg8FCP)^h|zOwyT&c5>+K(lp&AVvN8V*Gs}ZnQQe~KxsAU$tjIj=YW=TsqVxJ#P@_LRNm{yGb;3<3LFgX4GS(QGt% z2W$=VJ6^M`h?h+nD&QQC(&xcXJ6Pnfay4FUJbVi(!u7bzr?ET5oecCOJ*pnjL4bL+ zhUbH;?HotA9C&a{D70jhl?2Dlm_;(V+J416v>rG)=hX1*!bCVy&Fxz66$2e-jWF51 zw8>)ljOuZf^=n@ByWOXyOPi9#WwHYym$%)}cJN&;ux`em9hWIPA;acD?TLW3J~Y(y zIOBgzU-CCX}p{Cg?}YFn1h-pN1KNHLkF%h zflEr%=vH^T~Wv0IAq1kLaQ z^a^b2K=a8gm=;Z)Cf?c(7)g5WkpE%Hu=`lf;ZalG)3U2}W`JWI_V@uxugyDISkUWb zrDlh^W^FlVNAKpNu+#hA6Pe9Ig>P=uo#Mi771YamD&Sbutd*~OyqXLJw5?u2nfiqXp{~Km6k1e+-9=XcR;{ z;I+SR(=hH$TTnX;1g@B4HsvvWB9AZqnh|Wy0%xV)2`Xl%MA2rfs@Vl!YukcV8jh)Q zw8!=u7-@t>;C7x8AYA!l-ZytezE3TzbHcnzfOy1!Z4U z9kp4GRtm&xDPmEdhC)J`m!UT*9IAYU9Uw{ytK8+ybSux8UCJo8)c3z&$^n`SkpRn6 zN@?P6)sHt?f4n|nmcAZyx9@;%ZZS}<6B@-!@tAVmSfYJd3l5oLnakmb$jl~ckrJQE zcqSilz0cRg@KSLsJ?1N#r~u4&Cdn438m-i@lUt6QF99NV;0igfC~IaQKqEZA*bA@dt}=RI)#Anfe_b3^`#tlC=$0qCj1L7o{5Cj><& zC3iYWdlK=|!3jZ=tmw8**#4e6uUWR~Ipr0ye~Bpsw_tc`XBlGaiQMXp$Zmz;L8er8 zp40nNvoYj>EI1O?*wr&mg!)o>jEoUE<)C>H+_ZTxK7~k-N$V&U9rPos02QEd@5iE> zzfWEzg_u?M4@3uQ_7&s!yBY`!`Ae8360*}=XA`bh^(cJ)OcW0~s3omom)*TXr{>}) zerSc6r;gj);IP3a%>uXX-O!j2;~W~{hYR4zrSasqLsn#$&v#goV?O}p2DYMIaaXed zcsxV)AJtP@=*p#@Bjz+#1=~Ljcqf?jvT6K|BaU6YyiXd$suq7gc<&II5g+^D;?Q1K zA=WK92Ugs)C)SsXS?v1aj5hqBe#7r<%67}RcTn)BAwEJeKI#Tl_w8qNV_dq{<&chL z!kg=Gh!M73zN$$u?SMkKs#OPqu66AsVPZ^FNKmj+9RCz=enAyL~cPuXQ17%mWt@a60 z%-|f|{CkSmc(}V}I#KrxKMT>#)uhtm5zn%_&XQ@nzwa+R^T}P7X&wQHFJeJw^{n40 z_50>MLjm9ig|{U~0Q|GMd19+_^Rd!K{gS3tX#RUt*d$4#J9|A|7rC^gbz(FN%Zj4u z@Ih(CWelHHj_=UQ8yq}FL>nx$_YzMDF7NNeb3KfoWbS|d#05W}=IYF$Noqy6N3ir5*R@aqf4mUdT1n%2UZK zeeZll0(+QZv{^rXUR{1*N;zs@{B^UM)NT~GCtjGD;VDjK@Zu53gJg~We$#S0S|)5q zzgCI=c5jOU4jA9*nrrEJ^&P4Q7~|9Ou?@sIp6$40$5)&RLBH^)4>-=_q+R8mmER0L zA`LUhDr-o{Sh(`JoXd!vFzvUG@eQpQL1=S0LOYebSd#gj>{lIo zVTtN;nbxkQ$9ffhA|1;|5G{tBo0%zBeCTM4vz%eaLtJ&7J4YH9LmrjNo99VEv!5E& z0tg47MOX^)-*%5-8gOpIU{9` z-h91%fzPog&uF4GH?e!(<4=Fi-GpsbzX^JO+jG6_3lV1lQhE7iQ zWHM#$4ihZAH`|1Za+h@o1YCJPu+vVLUTe`Td%Pq`C}s@S0okl$+|oitStxw^U ziLxy9-Zc2*89F*Sl-zY!2del^Rn9S5d)MIk~ z%jEHPyOG%YcIn`)i+Au=Q@C|OVY5Mtz4oqiY*a2fbP}L*=OlRvJ{GU3%vcR$)1Z3| z$ZkEjBO($hdSICAa$!4cmm-&@GYLiVd}>}6w>fC=V;Snd(lLADaEFv%OP@LbO=i4z z#JX=#oB6~%{HazuTru718+OG`=H|WLjok9zJR`&pn}ZL&%lWWITn@xKf)&sl3beN|6J0Em5tIA<@m6^fmu5*oq9)1^rum zxJpl>{5_Tn#H$rpe`SM`lH4+H$~t?PJPr>?3OC4QL))D6Xs{~F z==QpPJj+BrK6tW8K_s!K_f}{M?q(4~$Bq=3GH=VYlq%GlSX!Uyd5(LxAUil;C8X%Frl(Ja8<=aE)eJFxSIq~l76pZu495?_GJw3*T-`(e~W*@m)drC zWc1{o3XI@te1TNlX-hiAiTj1!rix#wh5`om-|HW{aArlrWZg33KU?nok@_s$?gl(eCf{Gv&{syZuoH!s>lXl$Wl0n(Q=d*#16n1H{+*%4+0#ug47%1*ubD9Yf$e4)_L zk+K1lQZ+|bEW$MKZ2636!@*665mxWs!ie|G!#J5zTGx8AG!GJQSQIt`Ra4yCxHkOO z;AiJyIi~eJo>{q`muP?Ar&yU)D_$@80D9Rvh9UCHEUX%&64oPLS^s_zJy-&W1)riFS9G^Im+=3a8({FCE{&2y@Pn= zq4E4i6jy%j_8v4>K$NsecdYcJ&)aA&i73C5u+x*yidqzYAZ&)79DKeM4jnhVj-Fbz zze7B$d~>9fS#VSFOzpOnPeL6F;F$WXWz2l>11u>>gy}jrWwz_z@A|pa0at_%ZfrKH zDf*FjnT!=Fkgxn5?`55)n!u3$$0@k+V~^ir-rxQ{id7!x_?#(CU{FN^b}#cSq%-|G zg7FJ4fw$N*Kkig9Hj9F%lXbJo&tQv!MNY+NKbeJ|*atl7+KiXOY&M5Sg&cNwNXn?! zWI_Rra04g$PnFY|r5PW^@m@-f4`f8zQfL>$aXo1CbC#Q2i@-Sl_Jv}rEFYNk?-yWM zp4xD=JtW!Nbq|(?N`79BXR;~X+3)8za=RZ;+%i2j9^b({7~ap*BHQQp0p}}%vvl+- z&JlW#)cYs1j%=Am3gDlL2S|cz!ecUfY*QU7?Y@(6gq~KTmDKa}Tl@~+cdF9^eD`i- z0<3a3*a=?1FDA`PE``|_KCY3-;m?jdiEZi#zx61qSfZfMy-@pDQN8PpJSMS=mAFaJL4r#F1oYKyYCxJ`D z&k)k)aV_H98wPR78}m%ntJP3eTRlyBz^J*^sMC>vlY2AK!r9NS=4Ipc*~ z=AUhmb!W~b80L6z_=Xcd3GXGu@J}WrwlHoSalo~@!-6Ae?u~u?qfIj$nmMkqmv8XC z$$M+x#`8KQNQ^hM%1>28eLYkScJufO0`M1lwe|oS0rKMVnYkJ(Ej?_km#Vc+ZGXX% zocnn^$Y93(&bR#gM$+r^BOjO)Dp|zGcWwI-qsC>fAXo=g!T$BC&NFb`OW-ybL?ZHV zTTMWJYNY90B8svBU+n!Zw+4x%p&hD$j_qgO5C~aT=L+${Bo!WstCp62K`tM6LJ50a zfV-fzweFGbBQeZMI?y$1TT3t!AC}xw#Z5S;0Bx=X9Ql;JB<%q#13)_uq$38o{N>Ns zZ9ku7ktQ1(^pW;z@xHQ-47rSAz@JwG4HqW`Ukq#aCw7DqnU+@h^;V_Dsa{++;|mbz zSAY3vEir3iB>*z1_b@LpFG<@>Hru%`AzeNea$72(7peZa^h@gT)k%sUCq%2met|}& z9?JrjNlwvXI}cU2CyI8segYS(6bNH{ITGCev~X`{u{M{`hW>H~NO|x`=zsI0uOaPW zGycSg7LmB8{NTZTcD4JB0hUrVap^lZIc^PeMNjzYQ|f;aKf6~;VgCo6ng8qjk@ag! zf|K6TlCAv^5gg|f5}RBWpy9D~7qMKE<-7f*0#tv`>Nb^r1(|?^bhc)o%4nnN1$Y|f zmhL+80=K;G^ZVMuxcXb*_(F-V2;EsN=9H*+gs4v1zbSkwd?TjEfWR*`-5Wl`cEizt zwW`r8`f-oF{3Yc;fAB?5v|nn#!Mz`5eKw%9d`wHX*q-kNte?3I9$p+@DBGr1LIucx zT;rjS?Jv8HSDCO9MZQK*KBkUw>5l7MVXMZ$5Wr<(jiL(TwCx`0^;6P^ewTM$eJ_S3gIx!U zA@T3*NIHe&ZhSKGiDp-I%o}_y9cYRO37UV38vGAFpchG*I!b{+}b9cIXAgs*KCTtE|-3d9GzNwp8CfdOJ3QIGfm-vlAp)8%MGIwvrzRq7o(FxqC{ILhyW*l7W8x^z69L%FiH@{@(jzhqJL}#R;#7~8hXNk$f63SUAPg{%b-?Fe9h~3O^Ay(^9woQm(2jR%Da>=wNk>9 zs0%@jFtc*H?mI6h_uek;Zt`8*++5Vq-P?IDjmj3Y+DM1xWoSEke>x)YrrpSUD__R@ zJb_37aDmjM!Q_bAHg}@|Y<^(NL0-VJ5YWMSq#s4X1qWw`4Gh;*FmoU8oU0F0V5~h( zg@Q1&x;-)dL~k)K{a$dv!oP7R*qWw_(&)T@wYa;#Xq4gmxAQ2ofV#3^jJ2h_ zPov!>ZJW_Pz2RgW85yN}dM*7edxqk*NeJ*aErP)MyIuQA@|=cc;ZKpaOhV3H>Fi1} zy>>s=brNZzjE6J@rRg^lGcmBb+^31DZQ&u^vnh^$Gxq)XMVBww7l;CW;mFYBr~lkE z-4!j|4>QA^Xa-;!o>A2ta##4=gfBwoe0INGliCj(XRklHkq;`Xap?2?+3FqKP!k%f zMg*z~D4Oi&BwffA1s}!_6mzbk5RClLDKYNBu5*P07ZA8k_;q8^Y=!FN9&k3{6QYy- z)NWjP+)uByZ;bqsmRV@aeb9_Ah;!300ZU=s&Cm}k*`(zE?m4o{zsmdBk=d?wt?R4| zZSo?Uus2>XqR{1!(gmB!o>F^jAEzI0TyZN?-OIg{!Q-PPF|KIR>6PjTM0@U@>G&YO zC?K$4A$HPbn0@AULF?zkwUI-M_R@lDHi8mOZs(;YIkO#NGWz+L)6tQOM`T9>-y}5TlZb;zoC*mxti7?HR&SHj<%3rs~Y#zr766p zFX&uQl2tQ{euw8la~Hx$hT#~FGmBrImA5${Q3?1=?VSr9-F4!V@{RV8bB?t>khZVU z*&_m+tOjs@l8ddfkBNL-^+N{ni>0gAzTE{$J)9fi^EE6suwL|uhYzgfziN@$UozBg zm#Hes63>G9Ox+PS<5aSLQPQr${37Pb6Ft^NuS*;>;)PIpJgOrzu7&XL(2_1;$+$+} zKVZhE%#N#@u!6}WHsEZAg{Q9Q1$w-C*Mvxj<*AvG3UdYLOL&)K>=R|C=4G}3Rpwo- zSsRADkXN}fW)VK#5LT?K-5n2!OE()Nx1VTC`P1JmpObc`C)3%C$`$8VAzyHw*YMEf z5yqc<#x`l?UwiJM{H^hhm4r`4m<}Vrb*r+u-v@uSpy3lWm-)nY=GAEZ&7^B*!)FK; zm0R;U1a9vnw74Ffnn3VxtOh2XL!XgW(Ugt7VS8HsLGBWFg$93bQQQ8#NJ^iM2?8F| zqisrkqUa6Us5)->q~?N*JaL}H`n)@4l2wF#{>KACL&0kd5~eTZK(-DI?Q~06Qxojf z=E=F1KzZa zzI8^-+Rz@Rt6ElwO*G&9M%i$vHVG^>X#dDz3JWZSOgXE#Oa*(`OmL!q1JvLdH=yhj zSyk~D`8!&~lROT6%b#4qQ9u?}g1HWHptA5OgPq0QJ#3vzGiJ)@ALueunGz$Hda}Qc zH?$|1W>DX&tg9Rt9S$rmE^cNPeyLZ8t!*DBwislaCCg6jnl2anRhssp_))*!pcvtt zs6vwoXAJsT$p6{^KKriT%fI>54lqAz=2b8A+}!SFRJG`2TQ}46Cedbb_~%$^Q0NU3 z<`^gPEM|J!H%m2AOmjJG{XIBISh0$92QS_yznc?v1uI_Q^8tZzK27A4rirRdEvz#6 zX1@kQQ+)~b=AStCFNROkMMI{uf^{T;_6+~Uv$wBF!Tu%4? z11rZsc&AGqg6`xnUD+M|sJR?54le-_W5oCpW|>WGud5O%WhXok&DC5rg?Ju{k#cdA z)3J9a5YpNmIwl_H^>c;f$jU$8KaSpNQ2s^XC% zIpOR;NuBgnqthf|FzSwjmNbYN==b(*=)@EYbqa2fLhrJG*y_ataK@2!>_XKcWyLsf zw{r;#14Q<3{`u4n^CLZpZVnYZ7-gCN5NCls4GtDfR@<18!yzVQvAe{!3=6r_^OamD zX$}bcQb!tju@rAyU>yC(Za;4H$)uSq<0$&v9mTBknrlaH8e#;A14qf1)T zZT;=glOHD&bHA{hMPkNQqkB%x4cPxXAkvEyiH$)z4piHkQ83J{)+}N;XK6;LNUFlH zGO?d4e0`mx`Zgp(Ju6Ju{}-{}CQn*=(Z1}Aw>ou+xAC<_%Gq&_8}5FJKHwaCWH5`a zphmMg<-iLIPEWf$F5~;$a)|-WFn9bj;rHS?og|bFBiP$VaVV@JPpmW1 zC(KYqR4^8AgL_Qvl(4b*m*pe>M<+x{)uT1m_p^U@>l~aH|Gkrn)R`ztj$~n-fCHeZ zYiq;*UA-?c5vnbv2!WT3vzSB~OAM(&6hX|QKxsDL;KUxU$lWUFMAN};GET)rK546q zMG(V%_YM}njV%BQjVW?~-z+g}6y`9yK4?nc>RSHIAd zG;9bm#b*hIA6G42dD!1E8NUA&Hl*D%l*4u^>lzlkB=xG1xuk*6{GjidY(~ z>5F2(LyKnfA;W6$Goy}=S#&K*>eXF+l75cUoV{AM8kpZJRE^q=9E>$+{h&&LF6GtF zo~#)ykH|BH0ailjOZJ`R^Ut zW`j4kpwaWrgWC_JMGK;JMUzn_|2Z$~LbP}quTP2zXYWi`bv_LIgy)nURE)e+%Zwoj z^NqR_yr=7C=1)8yJtt(|;YJT!uz<6d`^M+4Lfq4&=FmrkiuUQsZUQzEZ(78_(8I}{ z9ar$;${cRCsS0fa@zNe(Dwr!jpsEGpLNdF1?5>Sx_=&779`3+$4;{+*S8fNxFLRNGJ1q|pX03w~zDpggVqJNT8ly!c4o zKu{V156FQ@JgZ^MMT*%`C#|m5TyifIY0$51!}xU+(o7&+6yZOzOI<|Z9FCSq(dAf( zP17##wgY)kH5t!;)RTvL-DS6PB{YCBjK<7_2e1k3<@KJQD&NmEL|I} zfB(@x5;qxMf}Zj{3x?8Xr)7A96{pl9S+I~{+JO;g2sjHP3|)KBot-j@^D76pWhW6P zS>BkmB~ihYi?>+-6;vvv@Kfdr4*<7Z{D|idc}0EWwiHlsi8E= zz2fd~3Y+l8c*K^3UtS&z2ak znLOqwk)a2holW%)n3 zN42g*ulmi)VgV4%sw8?z!3FRNyLIcB!stZVX;#oYF#~3ZPeuVZ6)9)U5>-??AnwYJmnn6)XRr5+FcVgW z74vBo$Ftm6xH@hAhj2_@ZDMrdz^fmF7ZD=_; zS51H07fA)Qaax+Nhh6E@`NA??_uNv097IhhVF6mZycd7Jinz@Gk(#e!S8TSFum46A zWGTZK#_=CS5%p3ZeVuL3*GYlAR` zd)@$M)Y3hsV9iWdC?D^!#~G+F{JLBF(cS&V*-|gYYfsp?QOioX;L#s6LA}@a&ID&P zRUcd7J^L$J(|PB2e!ZV56xLXauz$Z3ihLQ0XdmwlD8!f7IOfb$HUz$*6~@U)Zx07+ zeJi_ao|x&i zLN?T{!isw{aTmyJfg=IfATdB0h&c;z$CnUBh`OSTm+w_R3m!}8F--z)(qh}E$(yGYlYAxL8VJI+K$d0PR+l8sSRTSy4Pw4T@`!S* zGH8ka7EF^W>inD1K?%t9Nq7QvVHQT`Gke?RGQ$Y-A9a@MRhHE_U3417@7ydSWyz|` z_8+(qzQ2-6+t3Yy9B7bDvUm&!bFX?XK_6uo92{_!dNy~!u6%CHLawIyV-ibND2Nge zxbb>av+{nCo9K@AjNt-?QAX0^zG|;^E*4-fYSO(xl71S|V-smdyF@Y8<9}cGh+t4U zyL(Ler#rdE8t?cvest;9;~g>osNee}gMg(z3A-V;qr;a&(m+1WwDfXj6%k6VUW`$W zG?r>9RNt>xuJIq9O9EZ@=(v!>Wvzr^>m9H^_Y|SL?qZKKw?y;8q^NqLI;;hjTKbaWSr$Z#YFIcptXVLX!popNNm} zf+jzR*`ffbb0VzCZb&V-l50G=4i0uYRmAvPF3*!P_=hNQknQ1Wf1VzG_^Z|0*PVH{ zrqN_)*;m#jpU|L>ar^i3gI>0$#nCVw!^Hrl{HL8)w5Ft|w(r(AHB|q=SH9ND*?bWa zoN98==(!bbhpY<8QL?*>WKA0T)!Wx5TN6*P#7~I|#t+#?V*yR_aus{}`&sWOS|+@? z31K%>9q3-rl&UpC=bBC*e9MLUDmuzD0T>iD2)%K<8j!QuDKHgjNhKKs`RYy*#<2c! znp471C^z!lVsQ)Ik`3a6TVT$p=O#U9+KF8C-en0%v|J$MO<;S0J04npllOqc`$+Uv zToI4|6>4iho;ie>tA$e5dYw&=%pz}e^ABXrMV0O*NkP2KNfG|S?N08avT=4oJi@*A zho1vi7!8Djs@E|*uIIy~f9~D~{MD3Q!Z1v}&Fig%BuKY35|JOn>WoRo8TR^Rw22wp zuPL1;``_hsszaiI%=R{0*cEe2#R0WsAM`EKQ6wP2g@YO5+Pm#Lmmx{*R+gPkxW$uB zu1g5Z8)m#upL3?`PCv2e=)B(d^EerZuwve=T$?H0U$N`Hb0-bM@Q*)+UE33>VAGtOOXMl`%#)v^9IjG|MZcpqnBev^b`*_IJ|%{0#CL)RMI#tKk={R-_PMpetuNKg&PYW;^2vxA&I&pe;}_35n6;3w1-d{(h%| zcO`sa1*+mA-Vbc;4M*R5{tS5rGmgKy626iq^`_W}u`q#R1%Xg@#z@u#wE}lVSYI_6 z)wa&Q&9@yL`Bo;gylK`q&RcT%Q+qYW2Chw%AzD%eu3zkqw`h_F80&!#PAOOO6L9vl zdFk)Vz)7*<*Zr1Bnj*>;ABP|C+ly53@~U);s`cmpa&kX6QRh9q(y&io3DFOP2HM@u zz!V`3vNsvJO!2B#f}gzNQQHiJt_RKsE7R%`GgbYT#NfbJ=GMYNRTGfd$I$@sA4_4NNLUaAn8J{$Bhow2#|pXlH%w^@!?Xjhp@zdXe3cu>Gg|1FBTOx`6_@ z-}iNo;UtD>C63-1P^Ncw0Y$ngq z=b_h~5KbnU8`Tvw)(O{nWlbE>hX2^oYI48VY*$Z^dY@rkHBTy$A+G{#vu;*5?u{oX zmjyTLsWGmWAv*q=f3Aw5so8bp}Ey#tg+^bg=> z=z-EP2st8O^fdC7LnFbY$2HYt*3uxDzfV9wTNd(}PNTNH-a%}->d|KRusgGkOrZPz zkUp?N`cq73>+>~0{F33$z;gERJR*Ns!_O7jS0>KVf*W{&U%s^Kd;UR+M+N>r{iiOx z#rD?E|EgM{_dGXbt#Me^qCoPvrt>MIT$KxWWLAAQWs8v}!RKShq60HR3{EIv8Xp4N)|Dp=A=$d) zNGsS4j}ZsCaVuCW;)qbDVbV=+f{NXoFt6=RG$Ox;!hr8h$<*egW3LF=mnMd=6HFw1Tv_�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/mysql.yml new file mode 100644 index 0000000000..dc5ff158c8 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListTest2 +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListTest2: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListTest2 + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListTest2: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListTest2: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/scripts/install_mysql2.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/scripts/install_mysql2.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/scripts/install_mysql2.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/scripts/start_mysql2.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/scripts/start_mysql2.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/resource2/scripts/start_mysql2.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/topology.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/topology.txt new file mode 100644 index 0000000000..cb3c3e8546 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/topology.txt @@ -0,0 +1 @@ +{"id":"6a4b2f9d-7fe1-482d-af11-97f483dff5b7","delegateId":"9c063349-2259-40fe-97f1-7c40e659e1b0","delegateType":"topologytemplate","dependencies":[{"name":"tosca-normative-types-DBMS","version":"1.0.0.wd03-SNAPSHOT"},{"name":"mysql-getServiceArtifactListTest2","version":"1.1.1-SNAPSHOT"},{"name":"tosca-normative-types-softwareComponent","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-compute","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-root","version":"1.0.0.wd03-SNAPSHOT"},{"name":"mysql-getServiceArtifactListTest","version":"1.1.1-SNAPSHOT"},{"name":"tosca-normative-types-database","version":"1.0.0.wd03-SNAPSHOT"}],"nodeTemplates":[{"key":"Mysql-getServiceArtifactListTest","value":{"type":"alien.nodes.Mysql-getServiceArtifactListTest","name":null,"properties":{"bind_address":"true","storage_path":"/mountedStorage","db_port":"3306","db_name":"wordpress","db_user":"pass","db_password":"pass"},"attributes":{"tosca_id":null,"tosca_name":null},"relationships":{"hostedOnCompute":{"type":"tosca.relationships.HostedOn","target":"Compute","requirementName":"host","requirementType":"tosca.nodes.Compute","targetedCapabilityName":"host"}},"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"host":{"type":"tosca.nodes.Compute","properties":null}},"capabilities":{"database_endpoint":{"type":"tosca.capabilities.DatabaseEndpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"host":{"type":"alien.capabilities.MysqlDatabase-getServiceArtifactListTest","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null}},"artifacts":{"scripts":{"artifactType":"tosca.artifacts.File","artifactRef":"scripts","artifactName":"scripts","artifactRepository":null}}}},{"key":"Compute","value":{"type":"tosca.nodes.Compute","name":null,"properties":{"disk_size":null,"num_cpus":null,"os_distribution":null,"os_arch":null,"mem_size":null,"os_type":null,"os_version":null},"attributes":{"ip_address":null,"tosca_id":null,"tosca_name":null},"relationships":null,"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"network":{"type":"tosca.capabilities.Connectivity","properties":null}},"capabilities":{"host":{"type":"tosca.capabilities.Container","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null},"attach":{"type":"tosca.capabilities.Attachment","properties":null},"scalable":{"type":"tosca.capabilities.Scalable","properties":{"max_intances":{"value":"1","definition":false},"default_instances":{"value":"1","definition":false},"min_intances":{"value":"1","definition":false}}}},"artifacts":null}},{"key":"Mysql-getServiceArtifactListTest2","value":{"type":"alien.nodes.Mysql-getServiceArtifactListTest2","name":null,"properties":{"bind_address":"true","storage_path":"/mountedStorage","db_port":"3306","db_name":"wordpress","db_user":"pass","db_password":"pass"},"attributes":{"tosca_id":null,"tosca_name":null},"relationships":{"hostedOnCompute":{"type":"tosca.relationships.HostedOn","target":"Compute","requirementName":"host","requirementType":"tosca.nodes.Compute","targetedCapabilityName":"host"}},"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"host":{"type":"tosca.nodes.Compute","properties":null}},"capabilities":{"database_endpoint":{"type":"tosca.capabilities.DatabaseEndpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"host":{"type":"alien.capabilities.MysqlDatabase-getServiceArtifactListTest2","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null}},"artifacts":{"scripts":{"artifactType":"tosca.artifacts.File","artifactRef":"scripts","artifactName":"scripts","artifactRepository":null}}}}]} \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/topologyTemplate.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/topologyTemplate.txt new file mode 100644 index 0000000000..f0d0849db8 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceArtifactListTest/topologyTemplate.txt @@ -0,0 +1,2 @@ +{"id":"9c063349-2259-40fe-97f1-7c40e659e1b0","name":"Andrey","description":null,"topologyId":"6a4b2f9d-7fe1-482d-af11-97f483dff5b7"} + diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/mysql.yml new file mode 100644 index 0000000000..e0a0c6458e --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListTest + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListTest: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListTest: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/scripts/install_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/scripts/install_mysql.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/scripts/install_mysql.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/scripts/start_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/scripts/start_mysql.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource1/scripts/start_mysql.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/mysql.yml new file mode 100644 index 0000000000..dc5ff158c8 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListTest2 +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListTest2: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListTest2 + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListTest2: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListTest2: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/scripts/install_mysql2.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/scripts/install_mysql2.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/scripts/install_mysql2.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/scripts/start_mysql2.sh b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/scripts/start_mysql2.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/resource2/scripts/start_mysql2.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/topology.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/topology.txt new file mode 100644 index 0000000000..cb3c3e8546 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/topology.txt @@ -0,0 +1 @@ +{"id":"6a4b2f9d-7fe1-482d-af11-97f483dff5b7","delegateId":"9c063349-2259-40fe-97f1-7c40e659e1b0","delegateType":"topologytemplate","dependencies":[{"name":"tosca-normative-types-DBMS","version":"1.0.0.wd03-SNAPSHOT"},{"name":"mysql-getServiceArtifactListTest2","version":"1.1.1-SNAPSHOT"},{"name":"tosca-normative-types-softwareComponent","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-compute","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-root","version":"1.0.0.wd03-SNAPSHOT"},{"name":"mysql-getServiceArtifactListTest","version":"1.1.1-SNAPSHOT"},{"name":"tosca-normative-types-database","version":"1.0.0.wd03-SNAPSHOT"}],"nodeTemplates":[{"key":"Mysql-getServiceArtifactListTest","value":{"type":"alien.nodes.Mysql-getServiceArtifactListTest","name":null,"properties":{"bind_address":"true","storage_path":"/mountedStorage","db_port":"3306","db_name":"wordpress","db_user":"pass","db_password":"pass"},"attributes":{"tosca_id":null,"tosca_name":null},"relationships":{"hostedOnCompute":{"type":"tosca.relationships.HostedOn","target":"Compute","requirementName":"host","requirementType":"tosca.nodes.Compute","targetedCapabilityName":"host"}},"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"host":{"type":"tosca.nodes.Compute","properties":null}},"capabilities":{"database_endpoint":{"type":"tosca.capabilities.DatabaseEndpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"host":{"type":"alien.capabilities.MysqlDatabase-getServiceArtifactListTest","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null}},"artifacts":{"scripts":{"artifactType":"tosca.artifacts.File","artifactRef":"scripts","artifactName":"scripts","artifactRepository":null}}}},{"key":"Compute","value":{"type":"tosca.nodes.Compute","name":null,"properties":{"disk_size":null,"num_cpus":null,"os_distribution":null,"os_arch":null,"mem_size":null,"os_type":null,"os_version":null},"attributes":{"ip_address":null,"tosca_id":null,"tosca_name":null},"relationships":null,"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"network":{"type":"tosca.capabilities.Connectivity","properties":null}},"capabilities":{"host":{"type":"tosca.capabilities.Container","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null},"attach":{"type":"tosca.capabilities.Attachment","properties":null},"scalable":{"type":"tosca.capabilities.Scalable","properties":{"max_intances":{"value":"1","definition":false},"default_instances":{"value":"1","definition":false},"min_intances":{"value":"1","definition":false}}}},"artifacts":null}},{"key":"Mysql-getServiceArtifactListTest2","value":{"type":"alien.nodes.Mysql-getServiceArtifactListTest2","name":null,"properties":{"bind_address":"true","storage_path":"/mountedStorage","db_port":"3306","db_name":"wordpress","db_user":"pass","db_password":"pass"},"attributes":{"tosca_id":null,"tosca_name":null},"relationships":{"hostedOnCompute":{"type":"tosca.relationships.HostedOn","target":"Compute","requirementName":"host","requirementType":"tosca.nodes.Compute","targetedCapabilityName":"host"}},"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"host":{"type":"tosca.nodes.Compute","properties":null}},"capabilities":{"database_endpoint":{"type":"tosca.capabilities.DatabaseEndpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"host":{"type":"alien.capabilities.MysqlDatabase-getServiceArtifactListTest2","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null}},"artifacts":{"scripts":{"artifactType":"tosca.artifacts.File","artifactRef":"scripts","artifactName":"scripts","artifactRepository":null}}}}]} \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/topologyTemplate.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/topologyTemplate.txt new file mode 100644 index 0000000000..f0d0849db8 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service1/topologyTemplate.txt @@ -0,0 +1,2 @@ +{"id":"9c063349-2259-40fe-97f1-7c40e659e1b0","name":"Andrey","description":null,"topologyId":"6a4b2f9d-7fe1-482d-af11-97f483dff5b7"} + diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource1/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource1/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource1/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource1/mysql.yml new file mode 100644 index 0000000000..4ee2c8ca88 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource1/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListNoContentTest +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListNoContentTest: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListNoContentTest: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource2/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource2/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource2/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource2/mysql.yml new file mode 100644 index 0000000000..b564dd0c4e --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/resource2/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-getServiceArtifactListNoContentTest2 +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-getServiceArtifactListNoContentTest2: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest2 + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest2: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript-getServiceArtifactListNoContentTest2: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/topology.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/topology.txt new file mode 100644 index 0000000000..279351879a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/topology.txt @@ -0,0 +1 @@ +{"id":"3293c9c8-a162-43fc-b8d1-431399f89cb7","delegateId":"25845cce-05c8-4502-b5fe-abfd6bd6f28e","delegateType":"topologytemplate","dependencies":[{"name":"tosca-normative-types-DBMS","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-softwareComponent","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-compute","version":"1.0.0.wd03-SNAPSHOT"},{"name":"mysql-getServiceArtifactListNoContentTest2","version":"1.1.1-SNAPSHOT"},{"name":"tosca-normative-types-root","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-database","version":"1.0.0.wd03-SNAPSHOT"}],"nodeTemplates":[{"key":"Mysql-getServiceArtifactListNoContentTest2","value":{"type":"alien.nodes.Mysql-getServiceArtifactListNoContentTest2","name":null,"properties":{"bind_address":"true","storage_path":"/mountedStorage","db_port":"3306","db_name":"wordpress","db_user":"pass","db_password":"pass"},"attributes":{"tosca_id":null,"tosca_name":null},"relationships":null,"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"host":{"type":"tosca.nodes.Compute","properties":null}},"capabilities":{"database_endpoint":{"type":"tosca.capabilities.DatabaseEndpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"host":{"type":"alien.capabilities.MysqlDatabase-getServiceArtifactListNoContentTest2","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null}},"artifacts":{"scripts":{"artifactType":"tosca.artifacts.File","artifactRef":"scripts","artifactName":"scripts","artifactRepository":null}}}},{"key":"Compute","value":{"type":"tosca.nodes.Compute","name":null,"properties":{"disk_size":null,"num_cpus":null,"os_distribution":null,"os_arch":null,"mem_size":null,"os_type":null,"os_version":null},"attributes":{"ip_address":null,"tosca_id":null,"tosca_name":null},"relationships":{"dependsOnMysql-getServiceArtifactListNoContentTest2":{"type":"tosca.relationships.DependsOn","target":"Mysql-getServiceArtifactListNoContentTest2","requirementName":"dependency","requirementType":"tosca.capabilities.Root","targetedCapabilityName":"root"}},"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"network":{"type":"tosca.capabilities.Connectivity","properties":null}},"capabilities":{"host":{"type":"tosca.capabilities.Container","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null},"attach":{"type":"tosca.capabilities.Attachment","properties":null},"scalable":{"type":"tosca.capabilities.Scalable","properties":{"max_intances":{"value":"1","definition":false},"default_instances":{"value":"1","definition":false},"min_intances":{"value":"1","definition":false}}}},"artifacts":null}}]} \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/topologyTemplate.txt b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/topologyTemplate.txt new file mode 100644 index 0000000000..3c342f6cd1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/getServiceListTest/Service2/topologyTemplate.txt @@ -0,0 +1,2 @@ +{"id":"25845cce-05c8-4502-b5fe-abfd6bd6f28e","name":"ServiceArtListNoContent","description":null,"topologyId":"3293c9c8-a162-43fc-b8d1-431399f89cb7"} + diff --git a/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingDefault.yaml b/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingDefault.yaml new file mode 100644 index 0000000000..6aad589bdb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingDefault.yaml @@ -0,0 +1,603 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +# availability_zone_smp0: +# type: string +# default: nova +# availability_zone_smp1: +# type: string +# default: nova +# availability_zone_fe0: +# type: string +# default: nova +# availability_zone_fe1: +# type: string +# default: nova +# availability_zone_db0: +# type: string +# default: nova +# availability_zone_db1: +# type: string +# default: nova +# availability_zone_be0: +# type: string +# default: nova +# availability_zone_be1: +# type: string +# default: nova +# availability_zone_be2: +# type: string +# default: nova +# availability_zone_be3: +# type: string +# default: nova +# availability_zone_be4: +# type: string +# default: nova + + vnf_missing_default: + type: string + description: Unique name for this VNF instance + label: be4 port 5 OAM ip address + +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingDesc.yaml b/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingDesc.yaml new file mode 100644 index 0000000000..d51a20d77f --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingDesc.yaml @@ -0,0 +1,603 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +# availability_zone_smp0: +# type: string +# default: nova +# availability_zone_smp1: +# type: string +# default: nova +# availability_zone_fe0: +# type: string +# default: nova +# availability_zone_fe1: +# type: string +# default: nova +# availability_zone_db0: +# type: string +# default: nova +# availability_zone_db1: +# type: string +# default: nova +# availability_zone_be0: +# type: string +# default: nova +# availability_zone_be1: +# type: string +# default: nova +# availability_zone_be2: +# type: string +# default: nova +# availability_zone_be3: +# type: string +# default: nova +# availability_zone_be4: +# type: string +# default: nova + + vnf_missing_desc: + type: string + default: This_is_the_SCP_name + label: be4 port 5 OAM ip address + +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingType.yaml b/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingType.yaml new file mode 100644 index 0000000000..29527495f7 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithParamsMissingType.yaml @@ -0,0 +1,603 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +# availability_zone_smp0: +# type: string +# default: nova +# availability_zone_smp1: +# type: string +# default: nova +# availability_zone_fe0: +# type: string +# default: nova +# availability_zone_fe1: +# type: string +# default: nova +# availability_zone_db0: +# type: string +# default: nova +# availability_zone_db1: +# type: string +# default: nova +# availability_zone_be0: +# type: string +# default: nova +# availability_zone_be1: +# type: string +# default: nova +# availability_zone_be2: +# type: string +# default: nova +# availability_zone_be3: +# type: string +# default: nova +# availability_zone_be4: +# type: string +# default: nova + + vnf_missing_desc: + description: Unique name for this VNF instance + default: This_is_the_SCP_name + label: be4 port 5 OAM ip address + +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithValidParams.yaml b/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithValidParams.yaml new file mode 100644 index 0000000000..6835485ca1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/heatArtifactParameters/heatWithValidParams.yaml @@ -0,0 +1,787 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +# availability_zone_smp0: +# type: string +# default: nova +# availability_zone_smp1: +# type: string +# default: nova +# availability_zone_fe0: +# type: string +# default: nova +# availability_zone_fe1: +# type: string +# default: nova +# availability_zone_db0: +# type: string +# default: nova +# availability_zone_db1: +# type: string +# default: nova +# availability_zone_be0: +# type: string +# default: nova +# availability_zone_be1: +# type: string +# default: nova +# availability_zone_be2: +# type: string +# default: nova +# availability_zone_be3: +# type: string +# default: nova +# availability_zone_be4: +# type: string +# default: nova + + vnf_name: + type: string + description: Unique name for this VNF instance + default: This_is_the_SCP_name + vnf_id: + type: string + description: Unique ID for this VNF instance + default: This_is_ths_SCP_id + + flavor_scp_be_id: + type: string + description: flavor type + default: a1.Small + flavor_scp_fe_id: + type: string + description: flavor type + default: a1.Small + flavor_smp_id: + type: string + description: flavor type + default: a1.Small + flavor_db_id: + type: string + description: flavor type + default: a1.Small + image_scp_be_id: + type: string + description: Image use to boot a server + default: asc_base_image_be + image_scp_fe_id: + type: string + description: Image use to boot a server + default: asc_base_image_fe + image_smp_id: + type: string + description: Image use to boot a server + default: asc_base_image_smp + image_db_id: + type: string + description: Image use to boot a server + default: asc_base_image_db + + int_vscp_fe_cluster_net_id: + type: string + description: LAN2 FE Cluster/KA + int_vscp_fe_cluster_cidr: + type: string + description: Private Network2 Address (CIDR notation) + int_vscp_cluster_net_id: + type: string + description: LAN3 Cluster + int_vscp_cluster_cidr: + type: string + description: Private Network3 Address (CIDR notation) + int_vscp_db_network_net_id: + type: string + description: LAN4 DB + int_vscp_db_network_cidr: + type: string + description: Private Network4 Address (CIDR notation) + SIGNET_vrf_A1_direct_net_id: + type: string + description: Network name for SIGTRAN_A + SIGNET_vrf_B1_direct_net_id: + type: string + description: Network name for SIGTRAN_B + Cricket_OCS_protected_net_id: + type: string + description: Network name for CRICKET_OCS + OAM_direct_net_id: + type: string + description: Network name for OAM + be0_Cricket_OCS_protected_ips: + type: string + label: be0 port 5 OAM ip address + description: be0 port 5 OAM ip address + be1_Cricket_OCS_protected_ips: + type: string + label: be1 port 5 OAM ip address + description: be1 port 5 OAM ip address + be2_Cricket_OCS_protected_ips: + type: string + label: be2 port 5 OAM ip address + description: be2 port 5 OAM ip address + be3_Cricket_OCS_protected_ips: + type: string + label: be3 port 5 OAM ip address + description: be3 port 5 OAM ip address + be4_Cricket_OCS_protected_ips: + type: string + label: be4 port 5 OAM ip address + description: be4 port 5 OAM ip address + be0_OAM_direct_ips: + type: string + label: be0 port 7 OAM ip address + description: be0 port 7 OAM ip address + be1_OAM_direct_ips: + type: string + label: be1 port 7 OAM ip address + description: be1 port 7 OAM ip address + be2_OAM_direct_ips: + type: string + label: be2 port 7 OAM ip address + description: be2 port 7 OAM ip address + be3_OAM_direct_ips: + type: string + label: be3 port 7 OAM ip address + description: be3 port 7 OAM ip address + be4_OAM_direct_ips: + type: string + label: be4 port 7 OAM ip address + description: be4 port 7 OAM ip address + fe0_SIGNET_vrf_A1_direct_ips: + type: string + label: fe0 port 0 SIGTRAN ip address + description: fe0 port 0 SIGTRAN ip address + fe0_OAM_direct_ips: + type: string + label: fe0 port 7 OAM ip address + description: fe0 port 7 OAM ip address + fe1_SIGNET_vrf_B1_direct_ips: + type: string + label: fe1 port 1 SIGTRAN ip address + description: fe1 port 1 SIGTRAN ip address + fe1_OAM_direct_ips: + type: string + label: fe1 port 7 OAM ip address + description: fe1 port 7 OAM ip address + smp0_OAM_direct_ips: + type: string + label: smp0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + smp1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: smp1 port 7 OAM ip address + db0_OAM_direct_ips: + type: string + label: db0 port 7 OAM ip address + description: smp0 port 7 OAM ip address + db1_OAM_direct_ips: + type: string + label: smp1 port 7 OAM ip address + description: db1 port 7 OAM ip address + vm_scp_be0_name: + type: string + default: vSCP_BE0 + description: name of VM + vm_scp_be1_name: + type: string + default: vSCP_BE1 + description: name of VM + vm_scp_be2_name: + type: string + default: vSCP_BE2 + description: name of VM + vm_scp_be3_name: + type: string + default: vSCP_BE3 + description: name of VM + vm_scp_be4_name: + type: string + default: vSCP_BE4 + description: name of VM + vm_scp_fe0_name: + type: string + default: vSCP_FE0 + description: name of VM + vm_scp_fe1_name: + type: string + default: vSCP_FE1 + description: name of VM + vm_smp0_name: + type: string + default: vSMP0 + description: name of VM + vm_smp1_name: + type: string + default: vSMP1 + description: name of VM + vm_db0_name: + type: string + default: vDB0 + description: name of VM + vm_db1_name: + type: string + default: vDB1 + description: name of VM + +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/heatEnv/artifact_1.yaml b/test-apis-ci/src/test/resources/CI/tests/heatEnv/artifact_1.yaml new file mode 100644 index 0000000000..7d4a85c2b6 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/heatEnv/artifact_1.yaml @@ -0,0 +1,144 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: string + description: city name + default: Hulon + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 + private_building: + type: boolean + description: home_number + default: true +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/heatEnv/artifact_2.yaml b/test-apis-ci/src/test/resources/CI/tests/heatEnv/artifact_2.yaml new file mode 100644 index 0000000000..2c404f0721 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/heatEnv/artifact_2.yaml @@ -0,0 +1,469 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: +parameters: + city_name: + type: string + description: city name + default: Hulon + address: + type: string + description: address + default: Narkis + home_number: + type: number + description: home_number + default: 14 + private_building: + type: boolean + description: home_number + default: true +resources: + be0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be0_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be0_Cricket_OCS_protected_ips}}] + + be0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be0_OAM_direct_ips}}] + + server_scp_be1: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be1_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be1 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be1_port_3 } + - port: { get_resource: be1_port_4 } + - port: { get_resource: be1_port_5 } + - port: { get_resource: be1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be1_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be1_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be1_Cricket_OCS_protected_ips}}] + + be1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be1_OAM_direct_ips}}] + + server_scp_be2: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be2_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be2 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be2_port_3 } + - port: { get_resource: be2_port_4 } + - port: { get_resource: be2_port_5 } + - port: { get_resource: be2_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be2_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be2_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be2_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be2_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be2_Cricket_OCS_protected_ips}}] + + be2_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be2_OAM_direct_ips}}] + + server_scp_be3: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be3_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be3 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be3_port_3 } + - port: { get_resource: be3_port_4 } + - port: { get_resource: be3_port_5 } + - port: { get_resource: be3_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be3_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be3_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be3_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be3_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be3_Cricket_OCS_protected_ips}}] + + be3_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be3_OAM_direct_ips}}] + + server_scp_be4: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be4_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be4 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be4_port_3 } + - port: { get_resource: be4_port_4 } + - port: { get_resource: be4_port_5 } + - port: { get_resource: be4_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be4_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } + + be4_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + be4_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + be4_port_5: + type: OS::Neutron::Port + properties: + network: { get_param: Cricket_OCS_protected_net_id } + fixed_ips: [{"ip_address": {get_param: be4_Cricket_OCS_protected_ips}}] + + be4_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: be4_OAM_direct_ips}}] + + server_scp_fe0: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe0_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe0 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe0_port_0 } + - port: { get_resource: fe0_port_2 } + - port: { get_resource: fe0_port_3 } + - port: { get_resource: fe0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe0_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe0_port_0: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_A1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_SIGNET_vrf_A1_direct_ips}}] + + fe0_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe0_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe0_OAM_direct_ips}}] + + server_scp_fe1: + type: OS::Nova::Server +# depends on: scp_be_wait_condition + properties: + name: { get_param: vm_scp_fe1_name } + image: { get_param: image_scp_fe_id } +# availability_zone: { get_param: availability_zone_fe1 } + flavor: { get_param: flavor_scp_fe_id } + scheduler_hints: { group: { get_resource: FE_Affinity } } + networks: + - port: { get_resource: fe1_port_1 } + - port: { get_resource: fe1_port_2 } + - port: { get_resource: fe1_port_3 } + - port: { get_resource: fe1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_fe1_name} +# wc_notify: { get_attr: ['scp_fe_wait_handle', 'curl_cli'] } + + fe1_port_1: + type: OS::Neutron::Port + properties: + network: { get_param: SIGNET_vrf_B1_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_SIGNET_vrf_B1_direct_ips}}] + + fe1_port_2: + type: OS::Neutron::Port + properties: + network_id: { get_resource: FE_Clustering_KA } + + fe1_port_3: + type: OS::Neutron::Port + properties: + network_id: { get_resource: Clustering_Network } + + fe1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: fe1_OAM_direct_ips}}] + + server_smp0: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp0_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp0 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp0_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp0_OAM_direct_ips}}] + + server_smp1: + type: OS::Nova::Server + properties: + name: { get_param: vm_smp1_name } + image: { get_param: image_smp_id } +# availability_zone: { get_param: availability_zone_smp1 } + flavor: { get_param: flavor_smp_id } + scheduler_hints: { group: { get_resource: SMP_Affinity } } + networks: + - port: { get_resource: smp1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_smp1_name} +# wc_notify: { get_attr: ['smp_wait_handle', 'curl_cli'] } + + smp1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: smp1_OAM_direct_ips}}] + + server_db0: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db0_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db0 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db0_port_4 } + - port: { get_resource: db0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db0_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db0_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db0_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db0_OAM_direct_ips}}] + + server_db1: + type: OS::Nova::Server +# depends_on: smp_wait_condition + properties: + name: { get_param: vm_db1_name } + image: { get_param: image_db_id } +# availability_zone: { get_param: availability_zone_db1 } + flavor: { get_param: flavor_db_id } + scheduler_hints: { group: { get_resource: DB_Affinity } } + networks: + - port: { get_resource: db1_port_4 } + - port: { get_resource: db1_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_db1_name} +# wc_notify: { get_attr: ['db_wait_handle', 'curl_cli'] } + + db1_port_4: + type: OS::Neutron::Port + properties: + network_id: { get_resource: DB_Network } + + db1_port_7: + type: OS::Neutron::Port + properties: + network: { get_param: OAM_direct_net_id } + fixed_ips: [{"ip_address": {get_param: db1_OAM_direct_ips}}] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/heatEnv/yuli.yaml b/test-apis-ci/src/test/resources/CI/tests/heatEnv/yuli.yaml new file mode 100644 index 0000000000..7d4a85c2b6 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/heatEnv/yuli.yaml @@ -0,0 +1,144 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: string + description: city name + default: Hulon + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 + private_building: + type: boolean + description: home_number + default: true +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/BindingAsset.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/BindingAsset.yml new file mode 100644 index 0000000000..5117247373 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/BindingAsset.yml @@ -0,0 +1,14 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 + +node_types: + org.openecomp.resource.cp: + derived_from: tosca.nodes.Root + properties: + type: + type: string + required: false + requirements: + - VirtualBinding: + capability: tosca.capabilities.network.Bindable + relationship: tosca.relationships.network.BindsTo + occurrences: [0, UNBOUNDED] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPHasNoReqCap.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPHasNoReqCap.yml new file mode 100644 index 0000000000..8309df24b5 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPHasNoReqCap.yml @@ -0,0 +1,9 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 + +node_types: + org.openecomp.resource.cp.CP: + derived_from: tosca.nodes.Compute + properties: + type: + type: string + required: false \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPHasNoReqCap_DerivedFromMyCompute1.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPHasNoReqCap_DerivedFromMyCompute1.yml new file mode 100644 index 0000000000..478e742bc5 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPHasNoReqCap_DerivedFromMyCompute1.yml @@ -0,0 +1,9 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 + +node_types: + org.openecomp.resource.cp.CP: + derived_from: org.openecomp.resource.MyCompute1 + properties: + type: + type: string + required: false \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPWithAttributes.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPWithAttributes.yml new file mode 100644 index 0000000000..807f7fe630 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CPWithAttributes.yml @@ -0,0 +1,56 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 + +node_types: + org.openecomp.resource.cp.CP: derived_from: tosca.nodes.Root + properties: + type: + type: string + required: false + ip_address: + type: string + required: false + description: Allow the user to set a static IP. + order: + type: integer + required: false + default: 0 + description: The order of the NIC on the compute instance (e.g. eth2). + is_default: + type: boolean + required: false + default: false + description: “If is_default=true this port will be used for the default gateway route. Only one port that is associated to single compute node can set as is_default=true.” + ip_range_start: + type: string + required: false + description: “Defines the starting IP of a range to be allocated for the VFC instances that are associated with this Port.” + ip_range_end: + type: string + required: false + description: “Defines the ending IP of a range to be allocated for the compute instances that are associated with this Port.” + is_tagged: + type: boolean + required: false + default: false + description: + attributes: + private_address: + type: string + default: "Hello" + value: "HelloWord" + public_address: + default: "DefaultValuePublicAddress" + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - virtualLink: + capability: tosca.capabilities.network.Linkable relationship: tosca.relationships.network.LinksTo + - virtualbinding: + capability: tosca.capabilities.network.Bindable relationship: tosca.relationships.network.BindsTo \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveCapTest_1.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveCapTest_1.yml new file mode 100644 index 0000000000..b9e6c4f9b5 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveCapTest_1.yml @@ -0,0 +1,34 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute1: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + capaBility: + type: tosca.capabilities.OperatingSystem diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveCapTest_2.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveCapTest_2.yml new file mode 100644 index 0000000000..230e4fa924 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveCapTest_2.yml @@ -0,0 +1,34 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute2: + derived_from: org.openecomp.resource.MyCompute1 + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + Capability: + type: tosca.capabilities.OperatingSystem diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveReqTest_1.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveReqTest_1.yml new file mode 100644 index 0000000000..0d097a8f20 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveReqTest_1.yml @@ -0,0 +1,34 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute1: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - requirEment: + capability: tosca.capabilities.Endpoint + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveReqTest_2.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveReqTest_2.yml new file mode 100644 index 0000000000..9cc1f2737b --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/CaseInsensitiveReqTest_2.yml @@ -0,0 +1,34 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute2: + derived_from: org.openecomp.resource.MyCompute1 + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - Requirement: + capability: tosca.capabilities.Endpoint + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DerivedFromCPWithOwnReq.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DerivedFromCPWithOwnReq.yml new file mode 100644 index 0000000000..3514acfe9f --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DerivedFromCPWithOwnReq.yml @@ -0,0 +1,14 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 + +node_types: + org.openecomp.resource.cp.LAN: + derived_from: org.openecomp.resource.cp.CP + properties: + type: + type: string + required: false + requirements: + - virtualLink: + capability: tosca.capabilities.network.Linkable + relationship: tosca.relationships.network.LinksTo + occurrences: [0, UNBOUNDED] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DerivedFromWebApplication_HasNoReqType.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DerivedFromWebApplication_HasNoReqType.yml new file mode 100644 index 0000000000..7fbf4ec132 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DerivedFromWebApplication_HasNoReqType.yml @@ -0,0 +1,27 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyChildWebApplication: + derived_from: tosca.nodes.WebApplication + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - diff: + capability: + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + deff: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentCapFromRoot.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentCapFromRoot.yml new file mode 100644 index 0000000000..fe79bb3af9 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentCapFromRoot.yml @@ -0,0 +1,26 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyAsset: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - test: + capability: tosca.capabilities.Scalable + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqAndCap.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqAndCap.yml new file mode 100644 index 0000000000..798cd5b9cd --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqAndCap.yml @@ -0,0 +1,34 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute1: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - DependencY: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + FeaTurE: + type: tosca.capabilities.OperatingSystem \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqCapFromCompute1.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqCapFromCompute1.yml new file mode 100644 index 0000000000..c72d0ee62a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqCapFromCompute1.yml @@ -0,0 +1,22 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute2: + derived_from: org.openecomp.resource.MyCompute1 + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - diff: + capability: tosca.capabilities.Container + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqCapFromCompute2.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqCapFromCompute2.yml new file mode 100644 index 0000000000..7132ca493a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqCapFromCompute2.yml @@ -0,0 +1,25 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute3: + derived_from: org.openecomp.resource.MyCompute1 + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - diff: + capability: tosca.capabilities.Container + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + deff: + type: tosca.capabilities.Container diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqFromCompute.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqFromCompute.yml new file mode 100644 index 0000000000..e9438bae3c --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/DifferentReqFromCompute.yml @@ -0,0 +1,32 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute1: + derived_from: tosca.nodes.Compute + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - test: + capability: tosca.capabilities.Scalable + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/FatherHasNoReqCap.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/FatherHasNoReqCap.yml new file mode 100644 index 0000000000..039ab61939 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/FatherHasNoReqCap.yml @@ -0,0 +1,9 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 + +node_types: + org.openecomp.resource.cp.CP: + derived_from: tosca.nodes.Root + properties: + type: + type: string + required: false \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure01.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure01.yml new file mode 100644 index 0000000000..f20a9eb48f --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure01.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_boolean: + type: list + description : another description + default: + - false + - true + entry_schema: + description: This is my property + type: booolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure02.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure02.yml new file mode 100644 index 0000000000..f1af89ca6a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure02.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - false + - truee + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure03.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure03.yml new file mode 100644 index 0000000000..974d96ba5b --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure03.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - false + - 3 + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure04.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure04.yml new file mode 100644 index 0000000000..52377e4b02 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure04.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - false + - 3.56 + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure05.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure05.yml new file mode 100644 index 0000000000..c66b4347f6 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure05.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - 10000 + - 3.56 + entry_schema: + description: This is my property + type: integer + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure06.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure06.yml new file mode 100644 index 0000000000..79b3c03cdf --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure06.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - 10000 + - aaaa + entry_schema: + description: This is my property + type: integer + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure07.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure07.yml new file mode 100644 index 0000000000..5556e9ddfb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure07.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - 10000 + - true + entry_schema: + description: This is my property + type: integer + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure08.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure08.yml new file mode 100644 index 0000000000..a3b21a64a3 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure08.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - 10.50 + - true + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure09.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure09.yml new file mode 100644 index 0000000000..dc28591499 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure09.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - 10.50 + - asdc + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure10.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure10.yml new file mode 100644 index 0000000000..e465448064 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure10.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - 10.50 + - 500 + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure11.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure11.yml new file mode 100644 index 0000000000..a428b51974 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure11.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - 10.50 + - 500.0@ + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure12.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure12.yml new file mode 100644 index 0000000000..d840253120 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure12.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - 10000 + - 3# + entry_schema: + description: This is my property + type: integer + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure13.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure13.yml new file mode 100644 index 0000000000..4eb59886e4 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure13.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - false + - true% + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure14.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure14.yml new file mode 100644 index 0000000000..ad263f3d00 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure14.yml @@ -0,0 +1,18 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - false + - falsee + - true + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure15.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure15.yml new file mode 100644 index 0000000000..93e8caa0a3 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure15.yml @@ -0,0 +1,19 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: list + description : another description + default: + - 10.5 + - 10.6x + - 20.5 + - 30.5 + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure16.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure16.yml new file mode 100644 index 0000000000..ed8ea4d70c --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/ListPropertyFalure16.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_boolean: + type: koko + description : another description + default: + - false + - true + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure01.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure01.yml new file mode 100644 index 0000000000..c7ff0743f2 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure01.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_boolean: + type: map + description : another description + default: + - false + - true + entry_schema: + description: This is my property + type: booolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure02.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure02.yml new file mode 100644 index 0000000000..d9abb87db8 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure02.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - false + - truee + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure03.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure03.yml new file mode 100644 index 0000000000..e8f9b6eaa9 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure03.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - false + - 3 + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure04.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure04.yml new file mode 100644 index 0000000000..d9dc4f955b --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure04.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - false + - 3.56 + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure05.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure05.yml new file mode 100644 index 0000000000..aba6ff1992 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure05.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - 10000 + - 3.56 + entry_schema: + description: This is my property + type: integer + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure06.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure06.yml new file mode 100644 index 0000000000..f27904d6e6 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure06.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - 10000 + - aaaa + entry_schema: + description: This is my property + type: integer + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure07.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure07.yml new file mode 100644 index 0000000000..ea123f3b1b --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure07.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - 10000 + - true + entry_schema: + description: This is my property + type: integer + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure08.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure08.yml new file mode 100644 index 0000000000..87b51fb2de --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure08.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - 10.50 + - true + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure09.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure09.yml new file mode 100644 index 0000000000..2fc8ded544 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure09.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - 10.50 + - asdc + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure10.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure10.yml new file mode 100644 index 0000000000..3ab449d72e --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure10.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - 10.50 + - 500 + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure11.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure11.yml new file mode 100644 index 0000000000..e437de822e --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure11.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - 10.50 + - 500.0@ + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure12.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure12.yml new file mode 100644 index 0000000000..f2fbc7c435 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure12.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - 10000 + - 3# + entry_schema: + description: This is my property + type: integer + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure13.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure13.yml new file mode 100644 index 0000000000..e375aae197 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure13.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - false + - true% + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure14.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure14.yml new file mode 100644 index 0000000000..e087212f1b --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure14.yml @@ -0,0 +1,18 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - false + - falsee + - true + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure15.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure15.yml new file mode 100644 index 0000000000..3923ee18d7 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure15.yml @@ -0,0 +1,19 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_property: + type: map + description : another description + default: + - 10.5 + - 10.6x + - 20.5 + - 30.5 + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure16.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure16.yml new file mode 100644 index 0000000000..ed8ea4d70c --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MapPropertyFalure16.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_boolean: + type: koko + description : another description + default: + - false + - true + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MyFatherCompute_NoReqCap.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MyFatherCompute_NoReqCap.yml new file mode 100644 index 0000000000..dfc564b458 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/MyFatherCompute_NoReqCap.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyFatherCompute: + derived_from: tosca.nodes.Compute + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameCapAsCompute.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameCapAsCompute.yml new file mode 100644 index 0000000000..533333ee09 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameCapAsCompute.yml @@ -0,0 +1,26 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute1: + derived_from: tosca.nodes.Compute + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + capabilities: + host: + type: tosca.capabilities.Container + endpoint : + type: tosca.capabilities.Endpoint.Admin + OS: + type: tosca.capabilities.OperatingSystem + BINDING: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameReqAsCompute.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameReqAsCompute.yml new file mode 100644 index 0000000000..9d8b2d8375 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameReqAsCompute.yml @@ -0,0 +1,23 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute1: + derived_from: tosca.nodes.Compute + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - LOCAL_STORAGE: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, 1] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameReqAsCompute_DerivedFromMyCompute1.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameReqAsCompute_DerivedFromMyCompute1.yml new file mode 100644 index 0000000000..a5413e516f --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/SameReqAsCompute_DerivedFromMyCompute1.yml @@ -0,0 +1,23 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute2: + derived_from: org.openecomp.resource.MyCompute1 + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - LOCAL_STORAGE: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, 2] \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/computeCap11.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/computeCap11.yml new file mode 100644 index 0000000000..9cea0b9dc8 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/computeCap11.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vfc.vfc3: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [1, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + occurrences: [1, 1] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/computeCap1UNBOUNDED.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/computeCap1UNBOUNDED.yml new file mode 100644 index 0000000000..24efc27711 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/computeCap1UNBOUNDED.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vfc.vfc2: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [1, 1] + capabilities: + host: + type: tosca.capabilities.Container + occurrences: [1, UNBOUNDED] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/derivedFromMyCompute.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/derivedFromMyCompute.yml new file mode 100644 index 0000000000..237bec1f0c --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/derivedFromMyCompute.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.DerivedFromMyCompute: + derived_from: org.openecomp.resource.MyCompute + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/derivedFromWebAppDerivedReqCap.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/derivedFromWebAppDerivedReqCap.yml new file mode 100644 index 0000000000..0679bff4b1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/derivedFromWebAppDerivedReqCap.yml @@ -0,0 +1,15 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyWebApp: + derived_from: tosca.nodes.WebApplication + properties: + context_root: + type: string + capabilities: + app_endpoint: + type: tosca.capabilities.Endpoint.Admin #derived from WebApplication's tosca.capabilities.Endpoint "app_endpoint" + requirements: + - host: + capability: tosca.capabilities.Container.Docker #derived from WebApplication's tosca.capabilities.Container "host" + node: tosca.nodes.WebServer + relationship: tosca.relationships.HostedOn diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importAttributeSuccessFlow.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importAttributeSuccessFlow.yml new file mode 100644 index 0000000000..0fa9a302f2 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importAttributeSuccessFlow.yml @@ -0,0 +1,53 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyComputeTest: + derived_from: tosca.nodes.Root + properties: + myProp: + type: tosca.datatypes.Credential + descritpion: hey Desc + default: + "protocol" : hey1 + "token_type" : hey2 + "token" : hey3 + "keys" : {"keyA" : "val1" , keyB : val2} + "user" : hey4 + attributes: + private_address: + type: string + status: supported + default: myDefault + public_address: + type: string + networks: + type: map + default: {keyA : val1 , keyB : val2} + entry_schema: + type: string + ports: + type: tosca.datatypes.Credential + description: this is my description + default: + "protocol" : hey1 + "token_type" : hey2 + "token" : hey3 + "keys" : {"keyA" : "val1" , keyB : val2} + "user" : hey4 + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importCapabilityNameExistsOnParent.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importCapabilityNameExistsOnParent.yml new file mode 100644 index 0000000000..4d6db6c8c0 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importCapabilityNameExistsOnParent.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute1: + derived_from: tosca.nodes.Compute + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + Binding: #"binding" exists on parent + type: tosca.capabilities.OperatingSystem diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importDuplicateCapability.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importDuplicateCapability.yml new file mode 100644 index 0000000000..fcc3952f94 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importDuplicateCapability.yml @@ -0,0 +1,42 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + - LOCAL_Storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + Scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importDuplicateRequirements.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importDuplicateRequirements.yml new file mode 100644 index 0000000000..7cab3ac590 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importDuplicateRequirements.yml @@ -0,0 +1,40 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + - LOCAL_Storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertyBadDefault.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertyBadDefault.yml new file mode 100644 index 0000000000..a3ff088a35 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertyBadDefault.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.TestResource: + derived_from: tosca.nodes.Root + properties: + my_prop: + type: list + description : another description + default: + - 12 + - true + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertyGoodDefault.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertyGoodDefault.yml new file mode 100644 index 0000000000..2f864a727e --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertyGoodDefault.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_prop: + type: list + description : another description + default: + - false + - true + entry_schema: + description: This is my property + type: string + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertySuccessFlow.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertySuccessFlow.yml new file mode 100644 index 0000000000..fd52df5f9b --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importListPropertySuccessFlow.yml @@ -0,0 +1,198 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + my_boolean: + type: list + description : another description + default: + - false + - true + entry_schema: + description: This is my property + type: boolean + my_boolean_array: + type: list + description : another description + default: [ true , false ] + entry_schema: + description: This is my property + type: boolean + duplicate_boolean_values: + type: list + description : another description + default: [ true , false , true ] + entry_schema: + description: This is my property + type: boolean + boolean_null_value: + type: list + description : another description + default: + - true + - + - false + entry_schema: + description: This is my property + type: boolean + my_integers: + type: list + description : another description + default: + - 0 + - 1000 + - -1000 + - 50 + entry_schema: + description: This is my property + type: integer + my_integers_array: + type: list + description : another description + default: [ 10 , -1000, 0 ] + entry_schema: + description: This is my property + type: integer + duplicate_integers_values: + type: list + description : another description + default: [ 10 , 10, -1000, 0 ] + entry_schema: + description: This is my property + type: integer + integer_null_value: + type: list + description : another description + default: + - 1000 + - + - 2000 + entry_schema: + description: This is my property + type: integer + my_string: + type: list + description : another description + default: + - asdc + - $?^@ecomp$!#%()_-~@+*^...;;/w# + - uc + entry_schema: + description: This is my property + type: string + my_string_array: + type: list + description : another description + default: [ AAA, ~$~#bbb%^*_-, qwe , 1.3 , 500 , true ] + entry_schema: + description: This is my property + type: string + string_null_value: + type: list + description : another description + default: + - asdc + - + - uc + entry_schema: + description: This is my property + type: string + string_space_value: + type: list + description : another description + default: + - asdc + - + - uc + entry_schema: + description: This is my property + type: string + duplicate_string_values: + type: list + description : another description + default: + - asdc + - asdc + - uc + entry_schema: + description: This is my property + type: string + my_float: + type: list + description : another description + default: + - 6 + - 1000.000001 + - -3.0f + entry_schema: + description: This is my property + type: float + my_float_array: + type: list + description : another description + default: [ 0.01 , -5.0 , 2.1f ] + entry_schema: + description: This is my property + type: float + duplicate_float_values: + type: list + description : another description + default: + - 0.0 + - 0.0 + - 4.555555 + entry_schema: + description: This is my property + type: float + float_no_default_values: + type: list + description : another description + default: + entry_schema: + description: This is my property + type: float + float_null_value: + type: list + description : another description + default: + - 6 + - + - -3.0f + entry_schema: + description: This is my property + type: float + float_space_value: + type: list + description : another description + default: + - 6 + - + - -3.0f + entry_schema: + description: This is my property + type: float + integer_no_default_values: + type: list + description : another description + default: + entry_schema: + description: This is my property + type: integer + string_no_default_values: + type: list + description : another description + default: + entry_schema: + description: This is my property + type: string + boolean_no_default_values: + type: list + description : another description + default: + entry_schema: + description: This is my property + type: boolean + capabilities: + link: + type: tosca.capabilities.network.Linkable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importMapPropertySuccessFlow.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importMapPropertySuccessFlow.yml new file mode 100644 index 0000000000..f856603397 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importMapPropertySuccessFlow.yml @@ -0,0 +1,452 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.LinkTest: + derived_from: tosca.nodes.Root + properties: + string_prop01: + type: map + description : another description + default: {keyA : val1 , keyB : val2} + entry_schema: + description: This is my property + type: string + string_prop02: + type: map + description : another description + default: {keyA : "val1" , keyB : "val2"} + entry_schema: + description: This is my property + type: string + string_prop03: + type: map + description : another description + default: {"keyA" : "val1" , keyB : val2} + entry_schema: + description: This is my property + type: string + string_prop04: + type: map + description : another description + default: {"keyA" : 10 , keyB : true } + entry_schema: + description: This is my property + type: string + string_prop05: + type: map + description : another description + default: {"keyA" : , keyB : "Big" } + entry_schema: + description: This is my property + type: string + string_prop06: + type: map + description : another description + default: {"keyA" : aaaA , keyB : null } + entry_schema: + description: This is my property + type: string + string_prop07: + type: map + description : another description + default: {"keyA" : NULL , keyB : Null } + entry_schema: + description: This is my property + type: string + string_prop08: + type: map + description : another description + default: {"keyA" : "" , keyB : "abcd" } + entry_schema: + description: This is my property + type: string + string_prop09: + type: map + description : another description + default: {"keyA" : " " , keyB : "abcd" } + entry_schema: + description: This is my property + type: string + string_prop10: + type: map + description : another description + default: {"keyA" : " aaaa" , keyB : " bbbb" } + entry_schema: + description: This is my property + type: string + string_prop11: + type: map + description : another description + default: {"keyA" : "aaaa " , keyB : "bbbb " } + entry_schema: + description: This is my property + type: string + string_prop12: + type: map + description : another description + default: {"keyA" : " aaaa " , keyB : " bbbb ccccc " } + entry_schema: + description: This is my property + type: string + string_prop13: + type: map + description : another description + default: + keyA : "aaaa" + entry_schema: + description: This is my property + type: string + string_prop14: + type: map + description : another description + default: + keyA : " aaaa " + entry_schema: + description: This is my property + type: string + string_prop15: + type: map + description : another description + default: + keyA : AbcD + entry_schema: + description: This is my property + type: string + string_prop16: + type: map + description : another description + default: + keyA : AbcD + entry_schema: + description: This is my property + type: string + string_prop17: + type: map + description : another description + default: + keyA : AbcD + entry_schema: + description: This is my property + type: string + string_prop18: + type: map + description : another description + default: + keyA : AbcD + entry_schema: + description: This is my property + type: string + string_prop19: + type: map + description : another description + default: + keyA : AbcD + entry_schema: + description: This is my property + type: string + string_prop20: + type: map + description : another description + default: + keyA : aaaa + keya : aaaa + Keya : Aaaa + KEYA : nnnn + entry_schema: + description: This is my property + type: string + string_prop21: + type: map + description : another description + default: + keyA : NULL + keyB : null + keyC : Null + entry_schema: + description: This is my property + type: string + string_prop22: + type: map + description : another description + default: + entry_schema: + description: This is my property + type: string + integer_prop01: + type: map + description : another description + default: {keyA : 1 , keyB : 1000} + entry_schema: + description: This is my property + type: integer + integer_prop02: + type: map + description : another description + default: {keyA : Null , keyB : NULL ,keyC : null } + entry_schema: + description: This is my property + type: integer + integer_prop03: + type: map + description : another description + default: {keyA : , keyB : -600} + entry_schema: + description: This is my property + type: integer + integer_prop03: + type: map + description : another description + default: {keyA : 800 , keyB : -600} + entry_schema: + description: This is my property + type: integer + integer_prop04: + type: map + description : another description + default: {keyA : , keyB : -600} + entry_schema: + description: This is my property + type: integer + integer_prop05: + type: map + description : another description + default: {keyA : 100 , keyB : 0 } + entry_schema: + description: This is my property + type: integer + integer_prop06: + type: map + description : another description + default: {keyA : 100 , keyB : 00} + entry_schema: + description: This is my property + type: integer + integer_prop07: + type: map + description : another description + default: {keyA : 100 , keyB : 100 } + entry_schema: + description: This is my property + type: integer + integer_prop08: + type: map + description : another description + default: + keyA : 100 + keyB : 200 + entry_schema: + description: This is my property + type: integer + integer_prop09: + type: map + description : another description + default: + keyA : 100 + keyB : 200 + entry_schema: + description: This is my property + type: integer + integer_prop10: + type: map + description : another description + default: + keyA : null + keyA : Null + keyB : 1111 + keyB : 2222 + entry_schema: + description: This is my property + type: integer + integer_prop11: + type: map + description : another description + default: + keyA : null + keyB : Null + keyC : NULL + keyD : + entry_schema: + description: This is my property + type: integer + integer_prop12: + type: map + description : another description + default: + entry_schema: + description: This is my property + type: integer + integer_prop13: + type: map + description : another description + default: {keyA : 100 , keyA : 200} + entry_schema: + description: This is my property + type: integer + boolean_prop01: + type: map + description : another description + default: {keyA : true , keyB : false , keyC : false } + entry_schema: + description: This is my property + type: boolean + boolean_prop02: + type: map + description : another description + default: {keyA : TRUE , keyB : FALSE , keyC : False } + entry_schema: + description: This is my property + type: boolean + boolean_prop03: + type: map + description : another description + default: + keyA : null + keyB : Null + keyC : NULL + keyD : + entry_schema: + description: This is my property + type: boolean + boolean_prop04: + type: map + description : another description + default: {keyA : Null , keyB : NULL ,keyC : null ,keyD : } + entry_schema: + description: This is my property + type: boolean + boolean_prop05: + type: map + description : another description + default: {keyA : true , keyB : false , keyC : false } + entry_schema: + description: This is my property + type: boolean + boolean_prop06: + type: map + description : another description + default: + keyA : true + keyB : true + keyC : false + entry_schema: + description: This is my property + type: boolean + boolean_prop07: + type: map + description : another description + default: + entry_schema: + description: This is my property + type: boolean + boolean_prop08: + type: map + description : another description + default: + keyA : false + keyA : true + keyB : true + keyB : false + entry_schema: + description: This is my property + type: boolean + boolean_prop09: + type: map + description : another description + default: {keyA : true,keyA : false,keyB : false,keyB : true} + entry_schema: + description: This is my property + type: boolean + float_prop01: + type: map + description : another description + default: {keyA : 1.20 , keyB : 3.56f , keyC : 33} + entry_schema: + description: This is my property + type: float + float_prop02: + type: map + description : another description + default: {keyA : 0.00, keyB : 0.0 , keyC : 0 } + entry_schema: + description: This is my property + type: float + float_prop03: + type: map + description : another description + default: {keyA : null, keyB : Null , keyC : NULL , keyD : } + entry_schema: + description: This is my property + type: float + float_prop04: + type: map + description : another description + default: {keyA : 1.20 , keyB : 3.56f , keyC : 33 } + entry_schema: + description: This is my property + type: float + float_prop05: + type: map + description : another description + default: + keyA : 33 + keyB : 1.2000 + keyC : 3.607f + keyD : 0 + entry_schema: + description: This is my property + type: float + float_prop06: + type: map + description : another description + default: + keyA : 33 + keyB : 1.2000 + keyC : 3.607f + entry_schema: + description: This is my property + type: float + float_prop07: + type: map + description : another description + default: + keyA : null + keyB : Null + keyC : NULL + keyD : + entry_schema: + description: This is my property + type: float + float_prop08: + type: map + description : another description + default: + entry_schema: + description: This is my property + type: float + float_prop09: + type: map + description : another description + default: + keyA : 3.5 + keyA : 0.01 + keyB : 3.6 + keyB : + entry_schema: + description: This is my property + type: float + float_prop10: + type: map + description : another description + default: {keyA : 0.0002} + entry_schema: + description: This is my property + type: float + float_prop11: + type: map + description : another description + default: {keyA : 0.000 , keyA : 003.56f, keyB : 33} + entry_schema: + description: This is my property + type: float + capabilities: + link: + type: tosca.capabilities.network.Linkable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importRequirementNameExistsOnParent.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importRequirementNameExistsOnParent.yml new file mode 100644 index 0000000000..e4d626fca6 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importRequirementNameExistsOnParent.yml @@ -0,0 +1,34 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute1: + derived_from: tosca.nodes.Compute + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - Local_Storage: + capability: tosca.capabilities.Endpoint + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importRequirementNameExistsOnParent_DerivedFromMyCompute1.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importRequirementNameExistsOnParent_DerivedFromMyCompute1.yml new file mode 100644 index 0000000000..7ae9552d6a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/importRequirementNameExistsOnParent_DerivedFromMyCompute1.yml @@ -0,0 +1,34 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute2: + derived_from: org.openecomp.resource.MyCompute1 + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - Local_Storage: + capability: tosca.capabilities.Endpoint + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/missingCapInCapDefinition.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/missingCapInCapDefinition.yml new file mode 100644 index 0000000000..301116c985 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/missingCapInCapDefinition.yml @@ -0,0 +1,37 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +description: Template for vSCP -- connectable to OCS-FW -- temporary model for 1602 demo + +############################ +# The model capture four sub-components (VDUs) and their connectivity to six +# networks. +############################ + +node_types: + +#The node type for vSCP +#used for substitution mapping, or to describe vSCP resource in ASDC studio + org.openecomp.resource.vSCP-03-16: + derived_from: tosca.nodes.Root + requirements: + - sigtran_connection1: + capability: tosca.capabilities.Node + - sigtran_connection2: + capability: tosca.capabilities.Node + - ocs_connection: + capability: tosca.capabilities.Node + - oam_connection: + capability: tosca.capabilities.Node + - firewall: + capability: tosca.capabilities.Node + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: org.openecomp.capabilities.networkInterfaceNotFound \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/missingCapInReqDefinition.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/missingCapInReqDefinition.yml new file mode 100644 index 0000000000..d100dafdf9 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/missingCapInReqDefinition.yml @@ -0,0 +1,25 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +description: Template for vSCP -- connectable to OCS-FW -- temporary model for 1602 demo + +############################ +# The model capture four sub-components (VDUs) and their connectivity to six +# networks. +############################ + +node_types: + +#The node type for vSCP +#used for substitution mapping, or to describe vSCP resource in ASDC studio + org.openecomp.resource.vSCP-03-16: + derived_from: tosca.nodes.Root + requirements: + - sigtran_connection1: + capability: org.openecomp.capabilities.networkInterfaceNotFound + - sigtran_connection2: + capability: tosca.capabilities.Node + - ocs_connection: + capability: tosca.capabilities.Node + - oam_connection: + capability: tosca.capabilities.Node + - firewall: + capability: tosca.capabilities.Node \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myChildCompute_NoReqCap.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myChildCompute_NoReqCap.yml new file mode 100644 index 0000000000..cc5b202bc7 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myChildCompute_NoReqCap.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyChildCompute: + derived_from: org.openecomp.resource.MyFatherCompute + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myChildWebApp_DerivedFromContainer.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myChildWebApp_DerivedFromContainer.yml new file mode 100644 index 0000000000..b7859d4c14 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myChildWebApp_DerivedFromContainer.yml @@ -0,0 +1,15 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyChildWebApp: + derived_from: org.openecomp.resource.MyWebApp + properties: + context_root: + type: string + capabilities: + app_endpoint: + type: tosca.capabilities.Endpoint + requirements: + - host: + capability: tosca.capabilities.Container + node: tosca.nodes.WebServer + relationship: tosca.relationships.HostedOn \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myCompute.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myCompute.yml new file mode 100644 index 0000000000..98bf9b7902 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myCompute.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeDerivedFromNotExists.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeDerivedFromNotExists.yml new file mode 100644 index 0000000000..2b2807395a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeDerivedFromNotExists.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.RootNotExists + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeIncorrectDefenitionVersionValue.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeIncorrectDefenitionVersionValue.yml new file mode 100644 index 0000000000..2fa3ad0c08 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeIncorrectDefenitionVersionValue.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: toscaSimpleYaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeIncorrectNameSpaceFormat.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeIncorrectNameSpaceFormat.yml new file mode 100644 index 0000000000..d1a613fff2 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeIncorrectNameSpaceFormat.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource2.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeNoDefenitionVersion.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeNoDefenitionVersion.yml new file mode 100644 index 0000000000..8084d049db --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeNoDefenitionVersion.yml @@ -0,0 +1,34 @@ +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeOccurencySuccess.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeOccurencySuccess.yml new file mode 100644 index 0000000000..40ae610c06 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeOccurencySuccess.yml @@ -0,0 +1,77 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [1, UNBOUNDED] + - local_storage200: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [1, 1] + - local_storage300: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [1, 10] + - local_storage400: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [1, 10000000] + - local_storage500: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [2, 3] + - local_storageNoOccurrences600: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpointNoOccurrence : + type: tosca.capabilities.Endpoint.Admin + endpoint200 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [1, 2] + endpoint300 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [1, 1] + endpoint400 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [1, 10] + endpoint500 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [1, 10000000] + endpoint600 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [1, UNBOUNDED ] + endpoint700 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [2, 4 ] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeParssingFalure.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeParssingFalure.yml new file mode 100644 index 0000000000..b243add14a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeParssingFalure.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requiremens: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilitis: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeReqNameExistsOnDerived.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeReqNameExistsOnDerived.yml new file mode 100644 index 0000000000..43d92d1681 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeReqNameExistsOnDerived.yml @@ -0,0 +1,34 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute1: + derived_from: tosca.nodes.Compute + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - Local_Storage: #"local_storage" exists on parent + capability: tosca.capabilities.Endpoint + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeVF.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeVF.yml new file mode 100644 index 0000000000..90e771dab1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeVF.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.VF.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeWithNodeTypesTwice.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeWithNodeTypesTwice.yml new file mode 100644 index 0000000000..73b201eab4 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeWithNodeTypesTwice.yml @@ -0,0 +1,42 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable + + org.openecomp.resource.example.TransactionSubsystem: + derived_from: tosca.nodes.Root + capabilities: + message_receiver: tosca.capabilities.Endpoint + requirements: + - database_endpoint: tosca.capabilities.Endpoint.Database \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeWithTopologyTemplate.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeWithTopologyTemplate.yml new file mode 100644 index 0000000000..c451eb2514 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myComputeWithTopologyTemplate.yml @@ -0,0 +1,44 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +topology_template: + description: Template of an application connecting to a database. + + node_templates: + web_app: + type: tosca.nodes.WebApplication.MyWebApp + requirements: + - host: web_server + - database_endpoint: db +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myFatherWebApp_derviedFromDocker.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myFatherWebApp_derviedFromDocker.yml new file mode 100644 index 0000000000..43a9a174f8 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myFatherWebApp_derviedFromDocker.yml @@ -0,0 +1,16 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyWebApp: + derived_from: tosca.nodes.WebApplication + properties: + context_root: + type: string + capabilities: + app_endpoint: + type: tosca.capabilities.Endpoint + requirements: + - HOSt: + capability: tosca.capabilities.Container.Docker + node: tosca.nodes.WebServer + relationship: tosca.relationships.HostedOn + occurrences: [ 1, 2 ] diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myLinkVL.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myLinkVL.yml new file mode 100644 index 0000000000..7c796d2801 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myLinkVL.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vl.MyLink: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myPortCP.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myPortCP.yml new file mode 100644 index 0000000000..ff255f2394 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/myPortCP.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.cp.MyPort: + derived_from: org.openecomp.resource.cp.Port + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage: + capability: tosca.capabilities.network.Bindable + node: org.openecomp.resource.vl.MyLink + relationship: tosca.relationships.BindTo + occurrences: [0, UNBOUNDED] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable diff --git a/openecomp-be/sonar-project.properties b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/noContent.yml similarity index 100% rename from openecomp-be/sonar-project.properties rename to test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/noContent.yml diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure01.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure01.yml new file mode 100644 index 0000000000..f007a0fed2 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure01.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [2, 0] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure02.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure02.yml new file mode 100644 index 0000000000..0487b63cb3 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure02.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [-1, 2] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure03.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure03.yml new file mode 100644 index 0000000000..7afdffa59d --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure03.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [1, -2] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure04.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure04.yml new file mode 100644 index 0000000000..f8a582f401 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure04.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [ , 2] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure05.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure05.yml new file mode 100644 index 0000000000..f1c6a93e1f --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure05.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [ 1, ] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure06.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure06.yml new file mode 100644 index 0000000000..b0ef54b0eb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure06.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [ 0 , 0 ] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure07.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure07.yml new file mode 100644 index 0000000000..afd999f575 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure07.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [ @ , 1 ] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure08.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure08.yml new file mode 100644 index 0000000000..60efc99273 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure08.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [ 1.0 , 2.0 ] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure09.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure09.yml new file mode 100644 index 0000000000..d6ec7eabe6 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure09.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [ "1" , "2" ] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure10.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure10.yml new file mode 100644 index 0000000000..27de429186 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure10.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [ ] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure11.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure11.yml new file mode 100644 index 0000000000..5bdae3a5f5 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure11.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + occurrences: [ UNBOUNDED , UNBOUNDED ] + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure31.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure31.yml new file mode 100644 index 0000000000..8c3034afce --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure31.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ 2, 1] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure32.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure32.yml new file mode 100644 index 0000000000..4b5eba9110 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure32.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ -1, 2] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure33.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure33.yml new file mode 100644 index 0000000000..9c42e22aa1 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure33.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ 1, -2] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure34.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure34.yml new file mode 100644 index 0000000000..49953b5834 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure34.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ , 2] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure35.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure35.yml new file mode 100644 index 0000000000..8d8985d7f7 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure35.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ 1 , ] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure36.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure36.yml new file mode 100644 index 0000000000..12944507f6 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure36.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ 0 , 0 ] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure37.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure37.yml new file mode 100644 index 0000000000..618c980e16 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure37.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ 0 , # ] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure38.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure38.yml new file mode 100644 index 0000000000..d0c4575c83 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure38.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ 1.0 , 2.0 ] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure39.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure39.yml new file mode 100644 index 0000000000..024338d380 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure39.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ "1" , "2" ] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure40.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure40.yml new file mode 100644 index 0000000000..a4a32ba772 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure40.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ ] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure41.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure41.yml new file mode 100644 index 0000000000..c3024a3ee4 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/occurencyFalure41.yml @@ -0,0 +1,35 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.MyCompute: + derived_from: tosca.nodes.Root + attributes: + private_address: + type: string + public_address: + type: string + networks: + type: map + entry_schema: + type: tosca.datatypes.network.NetworkInfo + ports: + type: map + entry_schema: + type: tosca.datatypes.network.PortInfo + requirements: + - local_storage100: + capability: tosca.capabilities.Attachment + node: tosca.nodes.BlockStorage + relationship: tosca.relationships.AttachesTo + capabilities: + host: + type: tosca.capabilities.Container + valid_source_types: [tosca.nodes.SoftwareComponent] + endpoint100 : + type: tosca.capabilities.Endpoint.Admin + occurrences: [ UNBOUNDED, UNBOUNDED ] + os: + type: tosca.capabilities.OperatingSystem + scalable: + type: tosca.capabilities.Scalable + binding: + type: tosca.capabilities.network.Bindable \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/softwareComponentReq11.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/softwareComponentReq11.yml new file mode 100644 index 0000000000..b9bda183e6 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/softwareComponentReq11.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vfc.vfc4: + derived_from: tosca.nodes.Root + properties: + # domain-specific software component version + component_version: + type: version + required: false + admin_credential: + type: tosca.datatypes.Credential + required: false + requirements: + - host: + capability: tosca.capabilities.Container + relationship: tosca.relationships.HostedOn + occurrences: [1, 1] diff --git a/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/softwareComponentReq12.yml b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/softwareComponentReq12.yml new file mode 100644 index 0000000000..9676bcdb6c --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/importToscaResourceByCreateUrl/softwareComponentReq12.yml @@ -0,0 +1,17 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +node_types: + org.openecomp.resource.vfc.vfc1: + derived_from: tosca.nodes.Root + properties: + # domain-specific software component version + component_version: + type: version + required: false + admin_credential: + type: tosca.datatypes.Credential + required: false + requirements: + - host: + capability: tosca.capabilities.Container + relationship: tosca.relationships.HostedOn + occurrences: [1, 2] diff --git a/test-apis-ci/src/test/resources/CI/tests/testCsarAPI/topology.txt b/test-apis-ci/src/test/resources/CI/tests/testCsarAPI/topology.txt new file mode 100644 index 0000000000..f46af26605 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/testCsarAPI/topology.txt @@ -0,0 +1 @@ +{"id":"c25811fc-e03f-401d-93ca-45d9bd312703","delegateId":"17710a88-f3d8-483d-aded-afee2906a8c1","delegateType":"topologytemplate","dependencies":[{"name":"tosca-normative-types-softwareComponent","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-webServer","version":"1.0.0.wd03-SNAPSHOT"},{"name":"apache-type","version":"2.0.0-SNAPSHOT"},{"name":"tosca-normative-types-compute","version":"1.0.0.wd03-SNAPSHOT"},{"name":"tosca-normative-types-root","version":"1.0.0.wd03-SNAPSHOT"}],"nodeTemplates":[{"key":"Compute_2","value":{"type":"tosca.nodes.Compute","name":null,"properties":{"disk_size":null,"num_cpus":null,"os_distribution":null,"os_arch":null,"mem_size":null,"os_type":null,"os_version":null},"attributes":{"ip_address":null,"tosca_id":null,"tosca_name":null},"relationships":null,"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"network":{"type":"tosca.capabilities.Connectivity","properties":null}},"capabilities":{"host":{"type":"tosca.capabilities.Container","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null},"attach":{"type":"tosca.capabilities.Attachment","properties":null},"scalable":{"type":"tosca.capabilities.Scalable","properties":{"max_intances":{"value":"1","definition":false},"default_instances":{"value":"1","definition":false},"min_intances":{"value":"1","definition":false}}}},"artifacts":null}},{"key":"Apache","value":{"type":"alien.nodes.Apache","name":null,"properties":{"port":"80","document_root":"/var/www","version":"2.4"},"attributes":{"tosca_id":null,"tosca_name":null},"relationships":{"attachToCompute_2":{"type":"tosca.relationships.AttachTo","target":"Compute_2","requirementName":"dependency","requirementType":"tosca.capabilities.Root","targetedCapabilityName":"attach"}},"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"host":{"type":"tosca.nodes.Compute","properties":null}},"capabilities":{"secure_endpoint":{"type":"tosca.capabilities.Endpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"app_endpoint":{"type":"tosca.capabilities.Endpoint","properties":{"port":null,"protocol":{"value":"tcp","definition":false},"url_path":null,"secure":{"value":"false","definition":false}}},"host":{"type":"alien.capabilities.ApacheContainer","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null}},"artifacts":null}},{"key":"Compute","value":{"type":"tosca.nodes.Compute","name":null,"properties":{"disk_size":null,"num_cpus":null,"os_distribution":null,"os_arch":null,"mem_size":null,"os_type":null,"os_version":null},"attributes":{"ip_address":null,"tosca_id":null,"tosca_name":null},"relationships":null,"requirements":{"dependency":{"type":"tosca.capabilities.Root","properties":null},"network":{"type":"tosca.capabilities.Connectivity","properties":null}},"capabilities":{"host":{"type":"tosca.capabilities.Container","properties":{"valid_node_types":null}},"root":{"type":"tosca.capabilities.Root","properties":null},"attach":{"type":"tosca.capabilities.Attachment","properties":null},"scalable":{"type":"tosca.capabilities.Scalable","properties":{"max_intances":{"value":"1","definition":false},"default_instances":{"value":"1","definition":false},"min_intances":{"value":"1","definition":false}}}},"artifacts":null}}]} \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/testCsarAPI/topologyTemplate.txt b/test-apis-ci/src/test/resources/CI/tests/testCsarAPI/topologyTemplate.txt new file mode 100644 index 0000000000..f3fdf0297b --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/testCsarAPI/topologyTemplate.txt @@ -0,0 +1 @@ +{"id":"17710a88-f3d8-483d-aded-afee2906a8c1","name":"MichaelTest2","description":null,"topologyId":"c25811fc-e03f-401d-93ca-45d9bd312703"} \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool10_false.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool10_false.yaml new file mode 100644 index 0000000000..b6faadd4f9 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool10_false.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: NO + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool11_false.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool11_false.yaml new file mode 100644 index 0000000000..7fb2923b04 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool11_false.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: 0 + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool12_false.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool12_false.yaml new file mode 100644 index 0000000000..fd451aa3af --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool12_false.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: OFF + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool1_true.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool1_true.yaml new file mode 100644 index 0000000000..a253e4c8d7 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool1_true.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: t + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool2_true.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool2_true.yaml new file mode 100644 index 0000000000..ce273b3522 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool2_true.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: true + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool3_true.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool3_true.yaml new file mode 100644 index 0000000000..4680eb6996 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool3_true.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: on + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool4_true.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool4_true.yaml new file mode 100644 index 0000000000..1ed7781831 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool4_true.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: y + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool5_true.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool5_true.yaml new file mode 100644 index 0000000000..c0b42e6288 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool5_true.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: yes + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool6_true.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool6_true.yaml new file mode 100644 index 0000000000..24b862b751 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool6_true.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: 1 + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool7_false.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool7_false.yaml new file mode 100644 index 0000000000..7bad8efd6f --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool7_false.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: F + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool8_false.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool8_false.yaml new file mode 100644 index 0000000000..8b35e2adf7 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool8_false.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: FALSE + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool9_false.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool9_false.yaml new file mode 100644 index 0000000000..2768e0d480 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_bool9_false.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: N + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_number1.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_number1.yaml new file mode 100644 index 0000000000..fc7f84ca81 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_number1.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: number + description: city name + default: 12 + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_number2.yaml b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_number2.yaml new file mode 100644 index 0000000000..28ec3358be --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/tmp/positive_artifact_number2.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: number + description: city name + default: 12.12 + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/uploadComponent/images/mysql.png b/test-apis-ci/src/test/resources/CI/tests/uploadComponent/images/mysql.png new file mode 100644 index 0000000000000000000000000000000000000000..8e02f49b7b10c6a728daf2eb8aede897d46427fc GIT binary patch literal 63119 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�-@jPt>5oqM$Wb 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 I?%O~AA6jwX6951J literal 0 HcmV?d00001 diff --git a/test-apis-ci/src/test/resources/CI/tests/uploadComponent/mysql.yml b/test-apis-ci/src/test/resources/CI/tests/uploadComponent/mysql.yml new file mode 100644 index 0000000000..a2eb4d423a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/uploadComponent/mysql.yml @@ -0,0 +1,85 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0_wd03 +description: MySQL RDBMS installation on a specific mounted volume path. +template_name: mysql-uploadComponent +template_version: 1.1.1-SNAPSHOT +template_author: FastConnect + +imports: + - "tosca-normative-types-root:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-compute:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-database:1.0.0.wd03-SNAPSHOT" + - "tosca-normative-types-DBMS:1.0.0.wd03-SNAPSHOT" + +node_types: + alien.nodes.Mysql-uploadComponent: + derived_from: tosca.nodes.Database + description: > + A node to install MySQL v5.5 database with data + on a specific attached volume. + capabilities: + host: + type: alien.capabilities.MysqlDatabase + properties: + valid_node_types: [ tosca.nodes.WebApplication ] + requirements: + - host: tosca.nodes.Compute + type: tosca.relationships.HostedOn + tags: + icon: /images/mysql.png + properties: + db_port: + type: integer + default: 3306 + description: The port on which the underlying database service will listen to data. + db_name: + type: string + required: true + default: wordpress + description: The logical name of the database. + db_user: + type: string + default: pass + description: The special user account used for database administration. + db_password: + type: string + default: pass + description: The password associated with the user account provided in the ‘db_user’ property. + bind_address: + type: boolean + default: true + required: false + description: If true,the server accepts TCP/IP connections on all server host IPv4 interfaces. + storage_path: + type: string + default: /mountedStorage + constraints: + - valid_values: [ "/mountedStorage", "/var/mysql" ] + interfaces: + Standard: + create: scripts/install_mysql.sh + start: + inputs: + VOLUME_HOME: { get_property: [SELF, storage_path] } + PORT: { get_property: [SELF, db_port] } + DB_NAME: { get_property: [SELF, db_name] } + DB_USER: { get_property: [SELF, db_user] } + DB_PASSWORD: { get_property: [SELF, db_password] } + BIND_ADRESS: { get_property: [SELF, bind_address] } + implementation: scripts/start_mysql.sh + fastconnect.cloudify.extensions: + start_detection: + inputs: + PORT: { get_property: [SELF, db_port] } + implementation: scripts/mysql_start_detection.groovy + artifacts: + - scripts: scripts + type: tosca.artifacts.File + +capability_types: + alien.capabilities.MysqlDatabase: + derived_from: tosca.capabilities.Container + +artifact_types: + tosca.artifacts.GroovyScript: + description: A groovy script (.groovy file) + file_ext: [groovy] diff --git a/test-apis-ci/src/test/resources/CI/tests/uploadComponent/scripts/install_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/uploadComponent/scripts/install_mysql.sh new file mode 100644 index 0000000000..400bcf40cb --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/uploadComponent/scripts/install_mysql.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "Debian based MYSQL install 5..." +LOCK="/tmp/lockaptget" + +while true; do + if mkdir "${LOCK}" &>/dev/null; then + echo "MySQL take the lock" + break; + fi + echo "Waiting the end of one of our recipes..." + sleep 0.5 +done + +while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do + echo "Waiting for other software managers to finish..." + sleep 0.5 +done +sudo rm -f /var/lib/dpkg/lock + +sudo apt-get update || (sleep 15; sudo apt-get update || exit ${1}) +sudo DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server-5.5 pwgen || exit ${1} +rm -rf "${LOCK}" + +sudo /etc/init.d/mysql stop +sudo rm -rf /var/lib/apt/lists/* +sudo rm -rf /var/lib/mysql/* +echo "MySQL Installation complete." \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/uploadComponent/scripts/start_mysql.sh b/test-apis-ci/src/test/resources/CI/tests/uploadComponent/scripts/start_mysql.sh new file mode 100644 index 0000000000..648bd45756 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/uploadComponent/scripts/start_mysql.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +echo "------------------------ ENV ------------------------" +echo "ENV VAR USED VOLUME_HOME : $VOLUME_HOME" +echo "ENV VAR USED PORT : $PORT" +echo "ENV VAR USED DB_NAME : $DB_NAME" +echo "ENV VAR USED DB_USER : $DB_USER" +echo "ENV VAR USED DB_PASSWORD : $DB_PASSWORD" +echo "---------------------------- ------------------------" + +CURRENT_PATH=`dirname "$0"` + +function StartMySQL { + echo "Starting MYSQL..." + sudo /etc/init.d/mysql stop + sudo /usr/bin/mysqld_safe > /dev/null 2>&1 & + RET=1 + while [[ RET -ne 0 ]]; do + echo "=> Waiting for confirmation of MySQL service startup" + sleep 5 + sudo mysql -uroot -e "status" > /dev/null 2>&1 + RET=$? + done +} + +function AllowFileSystemToMySQL { + MYSQL_DATA_DIR=$VOLUME_HOME/data + MYSQL_LOG=$VOLUME_HOME/logs + + echo "Setting data directory to $MYSQL_DATA_DIR an logs to $MYSQL_LOG ..." + if sudo test ! -d $MYSQL_DATA_DIR; then + echo "Creating DATA dir > $MYSQL_DATA_DIR ..." + sudo mkdir -p $MYSQL_DATA_DIR + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_DATA_DIR + fi + if sudo test ! -d $MYSQL_LOG; then + echo "Creating LOG dir > $MYSQL_LOG ..." + sudo mkdir -p $MYSQL_LOG + # mysql as owner and group owner + sudo chown -R mysql:mysql $MYSQL_LOG + fi + + # edit app mysql permission in : /etc/apparmor.d/usr.sbin.mysqld + COUNT_LINE=`sudo cat /etc/apparmor.d/usr.sbin.mysqld | wc -l` + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_DATA_DIR/** rwk," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/ r," /etc/apparmor.d/usr.sbin.mysqld + sudo sed -i "$(($COUNT_LINE)) i $MYSQL_LOG/** rwk," /etc/apparmor.d/usr.sbin.mysqld + + # reload app permission manager service + sudo service apparmor reload +} + +function UpdateMySQLConf { + echo "Updating MySQL conf files [DATA, LOGS]..." + sudo sed -i "s:/var/lib/mysql:$MYSQL_DATA_DIR:g" /etc/mysql/my.cnf + sudo sed -i "s:/var/log/mysql/error.log:$MYSQL_LOG/error.log:g" /etc/mysql/my.cnf + sudo sed -i "s:3306:$PORT:g" /etc/mysql/my.cnf + + if sudo test ! -f /usr/share/mysql/my-default.cnf; then + sudo cp /etc/mysql/my.cnf /usr/share/mysql/my-default.cnf + fi + if sudo test ! -f /etc/mysql/conf.d/mysqld_charset.cnf; then + sudo cp $configs/mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf + fi + + if [ "$BIND_ADRESS" == "true" ]; then + sudo sed -i "s/bind-address.*/bind-address = 0.0.0.0/" /etc/mysql/my.cnf + fi +} + +function InitMySQLDb { + # create database DB_NAME + if [ "$DB_NAME" ]; then + echo "INIT DATABASE $DB_NAME" + sudo mysql -u root -e "CREATE DATABASE $DB_NAME"; + fi + + # create user and give rights + if [ "$DB_USER" ]; then + echo "CREATE USER $DB_USER WITH PASSWORD $DB_PASSWORD AND GRAND RIGHTS ON $DB_NAME" + sudo mysql -uroot -e "CREATE USER '${DB_USER}'@'%' IDENTIFIED BY '$DB_PASSWORD'" + sudo mysql -uroot -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'%' WITH GRANT OPTION" + sudo mysql -uroot -e "FLUSH PRIVILEGES" + fi +} + +# Create a new database path to the attched volume +if sudo test ! -d $VOLUME_HOME/data; then + echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME/data" + AllowFileSystemToMySQL + UpdateMySQLConf + echo "=> Init new database path to $MYSQL_DATA_DIR" + sudo mysql_install_db --basedir=/usr --datadir=$MYSQL_DATA_DIR + echo "=> MySQL database initialized !" +else + echo "=> Using an existing volume of MySQL" + AllowFileSystemToMySQL + UpdateMySQLConf +fi + +# Finally start MySQL with new configuration +StartMySQL +InitMySQLDb \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/artifact_unsupported.yaml b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/artifact_unsupported.yaml new file mode 100644 index 0000000000..764b8d4c58 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/artifact_unsupported.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: number123 + description: city name + default: 12.12 + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_bool1.yaml b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_bool1.yaml new file mode 100644 index 0000000000..19119f3d9a --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_bool1.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: K + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_bool2.yaml b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_bool2.yaml new file mode 100644 index 0000000000..f9c09a4fed --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_bool2.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: boolean + description: city name + default: 11 + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_number1.yaml b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_number1.yaml new file mode 100644 index 0000000000..9a489879cc --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_number1.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: number + description: city name + default: 1.2Noo + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_number2.yaml b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_number2.yaml new file mode 100644 index 0000000000..4c0e07affc --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_number2.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: number + description: city name + default: 1 2 3 + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_string1.yaml b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_string1.yaml new file mode 100644 index 0000000000..f52ef04712 --- /dev/null +++ b/test-apis-ci/src/test/resources/CI/tests/yamlFieldsValidation/negative_artifact_string1.yaml @@ -0,0 +1,140 @@ +heat_template_version: 2013-05-23 +################################# +# +# Changes in v0.2: +# - Unique availability zone for each VM +# - LAN8 and SLAN networks removed according to latest Prod/Type I diagram +# - 2 DB VMs added +# - Images corrected +# - VM start-up order: SMP->DB->BE->FE (no error handling yet) +# - Provisioning scripts placeholders +# +################################# + +description: ASC Template + +parameters: + city_name: + type: string + description: city name + default: שלום + address: + type: string + description: address + default: Alonim + home_number: + type: number + description: home_number + default: 8 +resources: +# scp_be_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_be_wait_handle } +# count: 5 +# timeout: 300 +# scp_be_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# scp_fe_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: scp_fe_wait_handle } +# count: 2 +# timeout: 300 +# scp_fe_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# smp_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: smp_wait_handle } +# count: 2 +# timeout: 300 +# smp_wait_handle: +# type: OS::Heat::WaitConditionHandle +# +# db_wait_condition: +# type: OS::Heat::WaitCondition +# properties: +# handle: { get_resource: db_wait_handle } +# count: 2 +# timeout: 300 +# db_wait_handle: +# type: OS::Heat::WaitConditionHandle + + FE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + BE_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + SMP_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + DB_Affinity: + type: OS::Nova::ServerGroup + properties: + policies: ["anti-affinity"] + + FE_Clustering_KA: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_fe_cluster_net_id } + + FE_Clustering_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: FE_Clustering_KA } + cidr: { get_param: int_vscp_fe_cluster_cidr } + + Clustering_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_cluster_net_id } + + Clustering_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: Clustering_Network } + cidr: { get_param: int_vscp_cluster_cidr } + + DB_Network: + type: OS::Contrail::VirtualNetwork + properties: + name: { get_param: int_vscp_db_network_net_id } + + DB_Network_subnet: + type: OS::Neutron::Subnet + properties: + network_id: { get_resource: DB_Network } + cidr: { get_param: int_vscp_db_network_cidr } + + server_scp_be0: + type: OS::Nova::Server +# depends on: db_wait_condition + properties: + name: { get_param: vm_scp_be0_name } + image: { get_param: image_scp_be_id } +# availability_zone: { get_param: availability_zone_be0 } + flavor: { get_param: flavor_scp_be_id } + scheduler_hints: { group: { get_resource: BE_Affinity } } + networks: + - port: { get_resource: be0_port_3 } + - port: { get_resource: be0_port_4 } + - port: { get_resource: be0_port_5 } + - port: { get_resource: be0_port_7 } + metadata: + vnf_id: { get_param: vnf_id } + user_data: + str_replace: + template: | + #!/bin/bash + #todo: provision $vm_name + wc_notify --data-binary '{"status": "SUCCESS"}' + params: + $vm_name: {get_param: vm_scp_be0_name} +# wc_notify: { get_attr: ['scp_be_wait_handle', 'curl_cli'] } diff --git a/test-apis-ci/src/test/resources/config.json b/test-apis-ci/src/test/resources/config.json new file mode 100644 index 0000000000..71c9d35e59 --- /dev/null +++ b/test-apis-ci/src/test/resources/config.json @@ -0,0 +1,12 @@ +{ + +catalogBeHost: behost, +catalogFeHost: fehost, +esHost: eshost, +catalogFePort: 8080, +catalogBePort: 8080, +esPort: 9200, +resourceConfigDir: "src/test/resources/CI/tests", +componentsConfigDir: "src/test/resources/CI/components" + +} \ No newline at end of file diff --git a/test-apis-ci/src/test/resources/logback-test.xml b/test-apis-ci/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..03ce9d1243 --- /dev/null +++ b/test-apis-ci/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file diff --git a/test-apis-ci/testng.xml b/test-apis-ci/testng.xml new file mode 100644 index 0000000000..8a47ef6d62 --- /dev/null +++ b/test-apis-ci/testng.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/test-apis-ci/testngLifeCycle.xml b/test-apis-ci/testngLifeCycle.xml new file mode 100644 index 0000000000..aa390dc213 --- /dev/null +++ b/test-apis-ci/testngLifeCycle.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-apis-ci/tmpCSAR b/test-apis-ci/tmpCSAR new file mode 100644 index 0000000000000000000000000000000000000000..c1d56528af5d7092629b3098fe741b961862794c GIT binary patch literal 1844 zcmWIWW@Zs#;Nak3*b_O$lK}}x0@)${!Oo7lzNsaNDTyVC`e3eJE|AOpk-x0$%2!`q zν;&v;(t_14uocjo-&AcHH$4~qE8c$~xxpA_kN`RaK3UMyX;C8)qp=hR94Fb=;n z+MZ{;pA?&VeqOPDacWUn zW^$^ob0(B!W@(;cWNKnzY+`7sTaubvkds)Fs#lqt^ESk{`?dp*t@(bZ4FP5Re4WYH z{qmMZXYl`BaMyPB&k4efw#jKJ;?w{9I8~T%J2kQ>tNKRytchQisAo#-XnOVk0Moj@ z0>(Js8GQNgj)tnVnjgwi@cirjT)4!MhF`r$fFYiZ-;21C*YN{WD`7X!VD+??J?cZ-@81X|z!7MXc(y~d)9<3(4^GvXN%GiPX} zO}X*xZFb$9ALcU)D!*CJiM_EX&m?U3{#`|Pf4{!>`>?d)s+G(yYZaFAu6cd&=Q7)g zcGaT#yB~^(^IJqJf4Nb%tuSG$f$Fp=g?w7UG7@JsrUYqUFnOY*9V)SUiNfuBFZcc{ zak!XxJGxc5{^GQUPB+hMPkR<~xh2)G`%~tTGe$=~=$tq3^LlVa!Cuy*ppM&py=8 zc&R!^F!*Ht$IuB|EzC7OYk5a+;NY6ti7Af6tETR|Q=q)FNj+=UACy zdE{2ciBu0olT0Dc)`=H$CKj6J^?S~nQOu`X*J1NxQK4e`@2vvuxqCDp$%A6kVq2|2 zJ}@?QS@6ZCE=Fv^;w>|;xFj(TnBmJaQ_@pQbPe^uF`3(Un(vT;fa~|aUB~_gXl?0O z`R6o8u%K2TwWw`kpL@g+Pjwx;%45xRfgG=(yodm|n8?VP=*A<55-4#XzzSeOLe2ODl1hL#E3hPCU|<2l LRA8X*WCig6a{bVV literal 0 HcmV?d00001 diff --git a/ui-ci-dev/.gitignore b/ui-ci-dev/.gitignore new file mode 100644 index 0000000000..6405eb7c05 --- /dev/null +++ b/ui-ci-dev/.gitignore @@ -0,0 +1,2 @@ +/bin/ +test-output/ \ No newline at end of file diff --git a/ui-ci-dev/pom.xml b/ui-ci-dev/pom.xml new file mode 100644 index 0000000000..f0ead6de8a --- /dev/null +++ b/ui-ci-dev/pom.xml @@ -0,0 +1,287 @@ + + 4.0.0 + + org.openecomp.sdc + sdc-main + + 1.1.0-SNAPSHOT + + ui-ci-dev + Selenium tests for the SDnC Application + + + + + + com.google.guava + guava + ${guava.version} + compile + + + org.seleniumhq.selenium + selenium-java + 3.0.1 + + + + org.seleniumhq.selenium + selenium-server + 2.48.2 + runtime + + + + org.openecomp.sdc + asdc-tests + ${asdc-tests.version} + + + + org.yaml + snakeyaml + ${snakeyaml.version} + compile + + + + com.google.code.gson + gson + ${gson.version} + compile + + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + compile + + + + org.apache.httpcomponents + httpmime + ${httpclient.version} + compile + + + + commons-io + commons-io + 1.3.2 + compile + + + + commons-logging + commons-logging + ${commons-logging} + compile + + + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + compile + + + + + com.thinkaurelius.titan + titan-core + ${titan.version} + compile + + + + com.thinkaurelius.titan + titan-cassandra + ${titan.version} + compile + + + + org.codehaus.jackson + jackson-mapper-asl + 1.9.2 + compile + + + + com.fasterxml.jackson.core + jackson-databind + 2.3.1 + compile + + + + com.fasterxml.jackson.core + jackson-core + 2.3.1 + compile + + + + org.openecomp.sdc + sdc-distribution-client + 1.1.3 + + + + junit + junit + ${junit.version} + compile + + + + org.testng + testng + ${testng.version} + compile + + + + xml-apis + xml-apis + 1.4.01 + compile + + + + com.googlecode.json-simple + json-simple + ${json-simple.version} + compile + + + + com.relevantcodes + extentreports + 1.4 + + + + org.apache.commons + commons-jci-core + ${commons-jci-core.version} + compile + + + + org.sikuli + sikuli-api + 1.2.0 + + + + org.sikuli + sikuli-core + 1.2.2 + + + + + + commons-codec + commons-codec + ${commons-codec} + compile + + + + + + + + + + + + + org.codehaus.mojo + properties-maven-plugin + 1.0-alpha-1 + false + + + + ui-ci-dev + initialize + + read-project-properties + + + + + ../target/FullReleaseVersion.properties + + + + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.5.5 + + + create.jar.with.dependencies + package + + single + + + + + org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest + + + + jar-with-dependencies + + + + + + + + + + + + + + + + + + + + + + + + + + + com.fortify.ps.maven.plugin + sca-maven-plugin + 4.30 + + false + + + + + diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/scripts/CreateVfsFromOnboarding.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/scripts/CreateVfsFromOnboarding.java new file mode 100644 index 0000000000..b11f8d19ef --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/scripts/CreateVfsFromOnboarding.java @@ -0,0 +1,67 @@ +package org.openecomp.sdc.uici.scripts; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.openecomp.sdc.uici.tests.datatypes.CleanTypeEnum; +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.uici.tests.utilities.OnboardUtility; + +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; +import com.google.gson.GsonBuilder; + +/** + * This Class functions to load mass zip files to vfs through onboarding.
+ * It uses both BE & UI APIs + * + * @author mshitrit + * + */ +public class CreateVfsFromOnboarding extends SetupCDTest { + public static void main(String[] args) { + CreateVfsFromOnboarding manager = new CreateVfsFromOnboarding(); + + FunctionalInterfaces.swallowException(() -> manager.setEnvParameters(CleanTypeEnum.NONE.name())); + // String folderPath = args[0]; + String folderPath = "C:\\onboardingTest\\onBoardingZips"; + File folder = new File(folderPath); + File[] listOfFiles = folder.listFiles(); + List zipFileNames = Arrays.asList(listOfFiles).stream().map(file -> file.getName()) + .filter(fileName -> fileName.endsWith(".zip")).collect(Collectors.toList()); + Map filesSuccessMap = new HashMap<>(); + for (String fileName : zipFileNames) { + try { + // Before + manager.beforeState(null); + manager.setBrowserBeforeTest(); + createSingleVfFromOnboarding(folderPath, fileName); + filesSuccessMap.put(fileName, "SUCCESS"); + + } catch (Exception e) { + filesSuccessMap.put(fileName, "FAIL"); + } finally { + FunctionalInterfaces.swallowException(() -> manager.afterState(null)); + manager.quitAfterTest(); + } + } + Path file = Paths.get("RunResults.txt"); + String stringDataModel = new GsonBuilder().setPrettyPrinting().create().toJson(filesSuccessMap); + FunctionalInterfaces.swallowException(() -> Files.write(file, stringDataModel.getBytes())); + } + + private static void createSingleVfFromOnboarding(String filePath, String zipFileName) { + String userId = UserRoleEnum.DESIGNER.getUserId(); + OnboardUtility.createVfFromOnboarding(userId, zipFileName, filePath); + GeneralUIUtils.submitForTestingElement("Vf From Onboarding"); + + } +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CanvasElement.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CanvasElement.java new file mode 100644 index 0000000000..c23d05ab23 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CanvasElement.java @@ -0,0 +1,33 @@ +package org.openecomp.sdc.uici.tests.datatypes; + +import org.apache.commons.lang3.tuple.ImmutablePair; + +public final class CanvasElement { + private final String uniqueId; + private ImmutablePair location; + private String elementName; + + public String getElementName() { + return elementName; + } + + public CanvasElement(String uniqueId, String elementName, ImmutablePair location) { + super(); + this.uniqueId = uniqueId; + this.location = location; + this.elementName = elementName; + } + + public String getUniqueId() { + return uniqueId; + } + + public ImmutablePair getLocation() { + return location; + } + + public void setLocation(ImmutablePair location) { + this.location = location; + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CanvasManager.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CanvasManager.java new file mode 100644 index 0000000000..5ef8c7a56a --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CanvasManager.java @@ -0,0 +1,206 @@ +package org.openecomp.sdc.uici.tests.datatypes; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +public final class CanvasManager { + private Map canvasElements; + private Actions actions; + private WebElement canvas; + private int reduceCanvasWidthFactor; + // Offsets Are used to find upper right corner of canvas element in order to + // connect links + private static final int CANVAS_ELEMENT_Y_OFFSET = 40; + private static final int CANVAS_ELEMENT_X_OFFSET = 21; // 14 - 27 + + private CanvasManager() { + canvasElements = new HashMap<>(); + actions = new Actions(GeneralUIUtils.getDriver()); + canvas = GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.GeneralCanvasItems.CANVAS.getValue()); + try { + WebElement webElement = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.GeneralCanvasItems.CANVAS_RIGHT_PANEL.getValue()); + reduceCanvasWidthFactor = webElement.getSize().width; + } catch (Exception e) { + reduceCanvasWidthFactor = 0; + } + } + + public static CanvasManager getCanvasManager() { + return new CanvasManager(); + } + + public List getCanvasElements() { + return canvasElements.values().stream().collect(Collectors.toList()); + } + + private void addCanvasElement(CanvasElement element) { + canvasElements.put(element.getUniqueId(), element); + } + + private void moveElementOnCanvas(CanvasElement canvasElement, ImmutablePair newLocation) { + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.sleep(500); + actions.moveToElement(canvas, canvasElement.getLocation().left, canvasElement.getLocation().right); + actions.clickAndHold(); + actions.moveToElement(canvas, newLocation.left, newLocation.right); + actions.release(); + actions.perform(); + canvasElement.setLocation(newLocation); + GeneralUIUtils.waitForLoader(); + + } + + public void moveElementOnCanvas(CanvasElement canvasElement) { + moveElementOnCanvas(canvasElement, getFreePosition()); + } + + public void deleteElementFromCanvas(CanvasElement canvasElement) { + GeneralUIUtils.waitForLoader(); + actions.moveToElement(canvas, canvasElement.getLocation().left, canvasElement.getLocation().right); + actions.click(); + actions.perform(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.GeneralCanvasItems.DELETE_INSTANCE_BUTTON.getValue()) + .click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.OK.getValue()).click(); + canvasElements.remove(canvasElement.getUniqueId()); + GeneralUIUtils.waitForLoader(); + } + + public void selectElementFromCanvas(CanvasElement canvasElement) { + GeneralUIUtils.waitForLoader(); + actions.moveToElement(canvas, canvasElement.getLocation().left, canvasElement.getLocation().right); + actions.click(); + actions.perform(); + GeneralUIUtils.waitForLoader(); + } + + public CanvasElement createElementOnCanvas(LeftPanelCanvasItems canvasItem) { + return createElementOnCanvas(canvasItem.getValue(), false); + } + + /** + * Creates Element on the Canvas - use the element name. + * + * @param elementName + * @return + */ + public CanvasElement createElementOnCanvas(String elementName) { + return createElementOnCanvas(elementName, true); + } + + private CanvasElement createElementOnCanvas(String elementName, boolean addPrefix) { + if (addPrefix) { + elementName = DataTestIdEnum.LEFT_PANEL_PREFIX + elementName; + } + GeneralUIUtils.waitForLoader(); + WebElement element = GeneralUIUtils.getWebElementWaitForVisible(elementName); + ImmutablePair freePosition = getFreePosition(); + actions.moveToElement(element, 0, 0); + actions.clickAndHold(); + actions.moveToElement(canvas, freePosition.left, freePosition.right); + actions.release(); + actions.perform(); + + String uniqueId = elementName + "_" + UUID.randomUUID().toString(); + CanvasElement canvasElement = new CanvasElement(uniqueId, elementName, freePosition); + addCanvasElement(canvasElement); + GeneralUIUtils.waitForLoader(); + return canvasElement; + } + + public CanvasElement createUniqueVFOnCanvas(LeftPanelCanvasItems canvasItem) { + GeneralUIUtils.waitForLoader(); + WebElement element = GeneralUIUtils.getWebElementWaitForVisible(canvasItem.getValue()); + ImmutablePair freePosition = getFreePosition(); + actions.moveToElement(element, 0, 0); + actions.clickAndHold(); + actions.moveToElement(canvas, freePosition.left, freePosition.right); + actions.release(); + actions.perform(); + + String uniqueId = canvasItem.name() + "_" + UUID.randomUUID().toString(); + CanvasElement canvasElement = new CanvasElement(uniqueId, canvasItem.getValue(), freePosition); + addCanvasElement(canvasElement); + GeneralUIUtils.waitForLoader(); + return canvasElement; + } + + private ImmutablePair getFreePosition() { + // TODO ui-ci use better method + ImmutablePair randomPosition = null; + boolean freePosition = false; + int minSpace = 150; + while (!freePosition) { + ImmutablePair tempRandomPosition = getRandomPosition(); + freePosition = !canvasElements.values().stream().map(e -> e.getLocation()) + .filter(e -> Math.abs(e.left - tempRandomPosition.left) < minSpace + && Math.abs(e.right - tempRandomPosition.right) < minSpace) + .findAny().isPresent(); + randomPosition = tempRandomPosition; + } + return randomPosition; + } + + private ImmutablePair getRandomPosition() { + int edgeBuffer = 50; + Random random = new Random(); + int xElement = random.nextInt(canvas.getSize().width - 2 * edgeBuffer - reduceCanvasWidthFactor) + edgeBuffer; + int yElement = random.nextInt(canvas.getSize().height - 2 * edgeBuffer) + edgeBuffer; + return new ImmutablePair(xElement, yElement); + } + + /** + * Links two elements on canvas.
+ * Currently Supports Only elements in the default size.
+ * Will not work for container type or smaller elements (cp, vl etc...)
+ * + * @param firstElement + * @param secondElement + */ + public void linkElements(CanvasElement firstElement, CanvasElement secondElement) { + GeneralUIUtils.waitForLoader(); + drawSimpleLink(firstElement, secondElement); + selectReqAndCapAndConnect(); + + GeneralUIUtils.waitForLoader(); + + } + + private void selectReqAndCapAndConnect() { + // Select First Cap + GeneralUIUtils.getWebElementsListWaitForVisible(DataTestIdEnum.LinkMenuItems.LINK_ITEM_CAP.getValue()).get(0) + .click(); + // Select First Req + GeneralUIUtils.getWebElementsListWaitForVisible(DataTestIdEnum.LinkMenuItems.LINK_ITEM_REQ.getValue()).get(0) + .click(); + // Connect + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.LinkMenuItems.CONNECT_BUTTON.getValue()).click(); + + } + + private void drawSimpleLink(CanvasElement firstElement, CanvasElement secondElement) { + + int yOffset = CANVAS_ELEMENT_Y_OFFSET; + int xOffset = CANVAS_ELEMENT_X_OFFSET; + actions.moveToElement(canvas, firstElement.getLocation().left + xOffset, + firstElement.getLocation().right - yOffset); + + actions.clickAndHold(); + actions.moveToElement(canvas, secondElement.getLocation().left + xOffset, + secondElement.getLocation().right - yOffset); + actions.release(); + actions.perform(); + GeneralUIUtils.waitForLoader(); + } +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CleanTypeEnum.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CleanTypeEnum.java new file mode 100644 index 0000000000..f0691b89fc --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CleanTypeEnum.java @@ -0,0 +1,28 @@ +package org.openecomp.sdc.uici.tests.datatypes; + +import java.util.Arrays; +import java.util.Optional; + +/** + * enum that represents possible methods to clean DB before and after tests. + * + * @author mshitrit + * + */ +public enum CleanTypeEnum { + FULL, + /** Unreliable should be only used in dev **/ + PARTIAL, NONE; + + /** + * Returns CleanType enum by it name + * + * @param cleanType + * @return + */ + public static CleanTypeEnum findByName(String cleanType) { + final Optional findAny = Arrays.asList(CleanTypeEnum.values()).stream() + .filter(e -> e.name().equals(cleanType)).findAny(); + return findAny.get(); + } +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CreateAndImportButtonsEnum.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CreateAndImportButtonsEnum.java new file mode 100644 index 0000000000..382584a48d --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CreateAndImportButtonsEnum.java @@ -0,0 +1,7 @@ +package org.openecomp.sdc.uici.tests.datatypes; + +public enum CreateAndImportButtonsEnum { + + IMPORT_VF, IMPORT_VFC, IMPORT_CP, IMPORT_VL, CREATE_VF, CREATE_SERVICE, CREATE_PRODUCT; + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CreateAndUpdateStepsEnum.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CreateAndUpdateStepsEnum.java new file mode 100644 index 0000000000..454affe528 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/CreateAndUpdateStepsEnum.java @@ -0,0 +1,25 @@ +package org.openecomp.sdc.uici.tests.datatypes; + +public enum CreateAndUpdateStepsEnum { + GENERAL("Generalstep"), + ICON("Iconstep"), + DEPLOYMENT_ARTIFACT("Deployment Artifactstep"), + INFORMATION_ARTIFACT("Information Artifactstep"), + PROPERTIES("Propertiesstep"), + ATTRIBUTES("Attributesstep"), + COMPOSITION("Compositionstep"), + DEPLOYMENT("Deploymentstep"), + REQUIREMENTS_AND_CAPABILITIES("Req. & Capabilitiesstep"), + INPUTS("Inputsstep"); + + private String value; + + public String getValue() { + return value; + } + + private CreateAndUpdateStepsEnum(String value) { + this.value = value; + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/DataTestIdEnum.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/DataTestIdEnum.java new file mode 100644 index 0000000000..2eb838281d --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/DataTestIdEnum.java @@ -0,0 +1,477 @@ +package org.openecomp.sdc.uici.tests.datatypes; + +public final class DataTestIdEnum { + private DataTestIdEnum() { + }; + + public enum MainMenue { + HOME("main-menu-button-home"), + CATALOG("main-menu-button-catalog"); + private String value; + + public String getValue() { + return value; + } + + private MainMenue(String value) { + this.value = value; + } + } + + public enum Dashboard { + IMPORT_AREA("importButtonsArea"), + BUTTON_ADD_VF("createResourceButton"), + BUTTON_ADD_SERVICE("createServiceButton"), + IMPORT_VFC("importVFCbutton"), + IMPORT_VF("importVFbutton"), + IMPORT_VFC_FILE("file-importVFCbutton"), + IMPORT_VF_FILE("file-importVFbutton"); + + private String value; + + public String getValue() { + return value; + } + + private Dashboard(String value) { + this.value = value; + } + } + + public enum LifeCyleChangeButtons { + CREATE("create/save"), + CHECK_IN("check_in"), + SUBMIT_FOR_TESTING("submit_for_testing"), + START_TESTING("start_testing"), + ACCEPT("accept"), + APPROVE("approve"), + DISTRIBUTE("distribute"); + + private String value; + + public String getValue() { + return value; + } + + private LifeCyleChangeButtons(String value) { + this.value = value; + } + } + + /** + * Artifacts Related Elements + * + * @author mshitrit + * + */ + public enum Artifatcs { + ADD_DEPLOYMENT_ARTIFACT("add-deployment-artifact-button"), + SELECT_ARTIFACT_DROPDOWN("selectArtifact"), + ARTIFACT_TYPE_DROPDOWN("artifacttype"), + BASE_CMUI_LAB1_ARTIFACT_ITEM("artifact-item-base-cmaui-lab1-06-27-2016-v1.yml"), + OPEN_EDIT_PROPERTIES_FORM_OF_BASE_CMUI_LAB1("edit-parameters-of-base-cmaui-lab1-06-27-2016-v1.yml"), + ARTIFACT_DESCRIPTION("description"), + ARTIFACT_LABEL("artifactLabel"), + BROWSE_BUTTON("browseButton"), + ADD_BUTTON("Add"); + + private String value; + + public String getValue() { + return value; + } + + private Artifatcs(String value) { + this.value = value; + } + + } + + public enum EnvParametersForm { + VALUE_FIELD_OF_AVAILABILITY_ZONE_0("value-field-of-availability_zone_0"), + VALUE_FIELD_OF_CMAUI_FLAVOR("value-field-of-cmaui_flavor"), + DELETE_AVAILABILITY_ZONE_0("delete-availability_zone_0"), + REVERET_CMAUI_FLAVOR("revert-cmaui_flavor"), + DEFAULT_VALUE_COLMN_OF_CMAUI_FLAVOR("default-value-of-cmaui_flavor"), + SAVE_BUTTON("Save"); + private String value; + + public String getValue() { + return value; + } + + private EnvParametersForm(String value) { + this.value = value; + } + + } + + public enum InformationalArtifatcs { + CLOUD_QUESTIONNAIRE("Cloud Questionnaire (completed)"), + FEATURES("Features"), + VENDOR_TEST_RESULT("Vendor Test Result"), + TEST_SCRIPTS("Test Scripts"), + HEAT_TEMPLATE_FROM_VENDOR("HEAT Template from Vendor"), + CAPACITY("Capacity"); + + private String value; + + public String getValue() { + return value; + } + + private InformationalArtifatcs(String value) { + this.value = value; + } + + } + + public enum ArtifactModal { + LABEL("artifactLabel"), TYPE("artifacttype"),; + + private String value; + + public String getValue() { + return value; + } + + private ArtifactModal(String value) { + this.value = value; + } + } + + public enum ModalItems { + BROWSE_BUTTON("browseButton"), + ADD("Add"), + DESCRIPTION("description"), + SUMBIT_FOR_TESTING_MESSAGE("changeLifeCycleMessage"), + OK("OK"), + CANCEL("Cancel"), + ACCEP_TESTING_MESSAGE("checkindialog"), + MESSAGE_TEXT("message"), + DONE("Done"); + + private String value; + + public String getValue() { + return value; + } + + private ModalItems(String value) { + this.value = value; + } + } + + public static final String LEFT_PANEL_PREFIX = "leftbar-section-content-item-"; + + public enum LeftPanelCanvasItems { + BLOCK_STORAGE(LEFT_PANEL_PREFIX + "BlockStorage"), + CINDER_VOLUME(LEFT_PANEL_PREFIX + "CinderVolume"), + COMPUTE(LEFT_PANEL_PREFIX + "Compute"), + LOAD_BALANCER(LEFT_PANEL_PREFIX + "LoadBalancer"), + NOVA_SERVER(LEFT_PANEL_PREFIX + "NovaServer"), + OBJECT_STORAGE(LEFT_PANEL_PREFIX + "ObjectStorage"), + // NEUTRON_PORT(LEFT_PANEL_PREFIX + "-NeutronPort"), + // PORT(LEFT_PANEL_PREFIX + "-Port"), + DATABASE(LEFT_PANEL_PREFIX + "-Database"); + + private String value; + + public String getValue() { + return value; + } + + private LeftPanelCanvasItems(String value) { + this.value = value; + } + } + + public enum RightBar { + PROPERTIES_AND_ATTRIBUTES("properties-and-attributes-tab"), + DEPLOYMENT_ARTIFACTS("deployment-artifact-tab"), + ARTIFACT_NAME("artifactName"), + ADD_ARTIFACT_BUTTON("add_Artifact_Button"), + DELETE_ARTIFACT_BUTTON("delete"), + MYATTR_ATTR_FROM_LIST("my_attr-attr"), + MYATTR_ATTR_VALUE_FROM_LIST("value-of-my_attr"),; + + private String value; + + public String getValue() { + return value; + } + + private RightBar(String value) { + this.value = value; + } + } + + + // for now we use index to work with the breadcrumbs + // any change in the breadcrumbs position will require an update here also + public enum BreadcrumbsButtonsEnum { + HOME("breadcrumbs-button-0"), + COMPONENT("breadcrumbs-button-1"); + + private String value; + + public String getValue() { + return value; + } + + private BreadcrumbsButtonsEnum(String value) { + this.value = value; + } + } + + public enum InputsEnum { + VF_INSTANCE("inputs-vf-instance-0"), + FIRST_INPUT_CHECKBOX("inputs-checkbox-0"), + SECOND_INPUT_CHECKBOX("inputs-checkbox-1"), + ADD_INPUTS_BUTTON("add-inputs-to-service-button"), + SERVICE_INPUT("service-input-0"), + DELETE_INPUT("delete-input-0"); + + private String value; + + public String getValue() { + return value; + } + + private InputsEnum(String value) { + this.value = value; + } + + } + + public enum TabsBar { + HIERARCHY_TAB("hierarchy-tab"), + SELECTED_TAB("selected-tab"), + TAB_HEADER("tab-header"), + TAB_SUB_HEADER("tab-sub-header"), + HIERARCHY_MODULE("hierarchy-module-0"), + HIERARCHY_MODULE_TITLE("hierarchy-module-0-title"), + HIERARCHY_SELECTED_MODULE_DATA("selected-module-data"), + HIERARCHY_SELECTED_MODULE_NAME("selected-module-name"), + HIERARCHY_SELECTED_MODULE_UUID("selected-module-group-uuid"), + HIERARCHY_SELECTED_MODULE_VERSION("selected-module-version"), + HIERARCHY_SELECTED_MODULE_IS_BASE("selected-module-is-base"), + HIERARCHY_SELECTED_MODULE_ARTIFACT_NAME("selected-module-artifact-name"), + HIERARCHY_SELECTED_MODULE_ARTIFACT_UUID("selected-module-artifact-uuid"), + HIERARCHY_SELECTED_MODULE_ARTIFACT_VERSION("selected-module-artifact-version"); + + private String value; + + public String getValue() { + return value; + } + + private TabsBar(String value) { + this.value = value; + } + } + + public enum UpdateNamePopover { + OPEN_POPOVER_ICON("edit-name-popover-icon"), + POPOVER_FORM("popover-form"), + POPOVER_SAVE_BUTTON("popover-save-button"), + POPOVER_INSTANCE_NAME("popover-vfinstance-name"), + POPOVER_HEAT_NAME("popover-heat-name"), + POPOVER_MODULE_NAME("popover-module-name"), + POPOVER_CLOSE_BUTTON("popover-close-button"), + POPOVER_X_BUTTON("popover-x-button"); + + private String value; + + public String getValue() { + return value; + } + + private UpdateNamePopover(String value) { + this.value = value; + } + } + + public enum LinkMenuItems { + CANCEL_BUTTON("link-menu-button-cancel"), + CONNECT_BUTTON("link-menu-button-connect"), + LINK_ITEM_CAP("link-item-capabilities"), + LINK_ITEM_REQ("link-item-requirements"), + LINK_MENU("link-menu-open"); + + private String value; + + public String getValue() { + return value; + } + + private LinkMenuItems(String value) { + this.value = value; + } + } + + public enum GeneralCanvasItems { + CANVAS("canvas"), + CANVAS_RIGHT_PANEL("w-sdc-designer-sidebar-head"), + DELETE_INSTANCE_BUTTON("e-sdc-small-icon-delete"); + + private String value; + + public String getValue() { + return value; + } + + private GeneralCanvasItems(String value) { + this.value = value; + } + } + + public enum AttributesSection { + TABLE_ROWS("attributes-table-row"), + EDIT_BUTTON_FOR_NETWORK_ATTR("edit_networks"), + DELETE_BUTTON_FOR_NETWORK_ATTR("delete_networks"), + ADD_BUTTON("add-attribute-button"); + + private String value; + + public String getValue() { + return value; + } + + private AttributesSection(String value) { + this.value = value; + } + } + + public enum AttributeForm { + NAME_FIELD("attributeName"), + DESCRIPTION_FIELD("description"), + TYPE_FIELD("type-field"), + DEFAULT_VAL_FIELD("defaultvalue"), + BOOL_DEFAULT_VAL_FIELD("booleantype"), + SCHEMA_FIELD("schema"), + BOOL_VALUE_FIELD("boolean-type-value"), + HIDDEN_FIELD("hidden"), + UPDATE_BUTTON("Update"), + DONE_BUTTON("Done"), + ADD_BUTTON("Add"); + + private String value; + + public String getValue() { + return value; + } + + private AttributeForm(String value) { + this.value = value; + } + } + + public enum PropertiesSection { + ADD_BUTTON("addGrey"),; + + private String value; + + public String getValue() { + return value; + } + + private PropertiesSection(String value) { + this.value = value; + } + } + + public enum PropertyForm { + FORM_CONTAINER("sdc-edit-property-container"), + NAME_FIELD("propertyName"), + DESCRIPTION_FIELD("description"), + TYPE_FIELD("propertyType"), + SCHEMA_FIELD("schema-type"), + SIMPLE_TYPE_DEFAULT_VAL_FIELD("defaultvalue"), + SIMPLE_TYPE_BOOL_DEFAULT_VAL_FIELD("booleantype"), + LIST_TYPE_DEFAULT_VAL_FIELD("listNewItem-1"), + MAP_TYPE_DEFAULT_VAL_KEY_FIELD_FOR_FIRST_ITEM("mapKey-10"), + MAP_TYPE_DEFAULT_VAL_VALUE_FIELD_FOR_FIRST_ITEM("mapValue-10"), + MAP_TYPE_DEFAULT_VAL_KEY_FIELD_FOR_SECOND_ITEM("mapKey-11"), + MAP_TYPE_DEFAULT_VAL_VALUE_FIELD_FOR_SECOND_ITEM("mapValue-11"), + ADD_ITEM_TO_LIST_BUTTON("add-list-item-1"), + ADD_ITEM_TO_MAP_BUTTON("add-map-item"), + DELETE_FIRST_ITEM_FROM_MAP_BUTTON("delete-map-item-10"), + START_PORT_FIELD_FOR_PORT_PAIRS_DT("-1start_port"), + SAVE_BUTTON("Save"); + + private String value; + + public String getValue() { + return value; + } + + private PropertyForm(String value) { + this.value = value; + } + } + + public enum GeneralSection { + BROWSE_BUTTON("browseButton"), FILE_NAME("filename"), NAME("name"), LOADER("tlv-loader"); + + private String value; + + public String getValue() { + return value; + } + + private GeneralSection(String value) { + this.value = value; + } + } + + public enum ReqAndCapabilitiesSection { + SEARCH_BOX("search-box"), CAP_TAB("cap-tab"), REQ_TAB("req-tab"); + + private String value; + + public String getValue() { + return value; + } + + private ReqAndCapabilitiesSection(String value) { + this.value = value; + } + } + + public enum DeploymentSection { + MODULE_PROPERTIES_HEADER_LIST("list-of-Properties"); + + private String value; + + public String getValue() { + return value; + } + + private DeploymentSection(String value) { + this.value = value; + } + } + + public enum OnBoardingTable { + OPEN_MODAL_BUTTON("repository-icon"), + VENDOR_HEADER_COL("Vendor"), + NAME_HEADER_COL("Name"), + CATEGORY_HEADER_COL("Category"), + VERSION_HEADER_COL("Version"), + IMPORT_ICON("import-csar"), + UPDATE_ICON("update-csar"), + CSAR_ROW("csar-row"), + ONBOARDING_SEARCH("onboarding-search"); + + private String value; + + public String getValue() { + return value; + } + + private OnBoardingTable(String value) { + this.value = value; + } + } +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/MenuOptionsEnum.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/MenuOptionsEnum.java new file mode 100644 index 0000000000..4c45858de0 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/MenuOptionsEnum.java @@ -0,0 +1,17 @@ +package org.openecomp.sdc.uici.tests.datatypes; + +public enum MenuOptionsEnum { + + EDIT("Edit"), CHECK_IN("Check in"), CHECK_OUT("Check out"), VIEW("View"), SUBMIT_FOR_TEST("Submit For Test"), ACCEPT("Accept"), REJECT("Reject"), START_TEST("Start test"), DISTREBUTE("Distribute"); + + private String value; + + public String getValue() { + return value; + } + + private MenuOptionsEnum(String value) { + this.value = value; + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/UserCredentials.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/UserCredentials.java new file mode 100644 index 0000000000..0d94529b89 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/datatypes/UserCredentials.java @@ -0,0 +1,29 @@ +package org.openecomp.sdc.uici.tests.datatypes; + +import org.openecomp.sdc.be.model.User; + +public class UserCredentials extends User { + + private String password; + + public UserCredentials(String userId, String password, String firstname, String lastname) { + super(); + setUserId(userId); + this.password = password; + setFirstName(firstname); + setLastName(lastname); + } + + public UserCredentials() { + super(); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/base/SetupCDTest.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/base/SetupCDTest.java new file mode 100644 index 0000000000..f9e294cbc7 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/base/SetupCDTest.java @@ -0,0 +1,419 @@ +package org.openecomp.sdc.uici.tests.execute.base; + +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.lang.NotImplementedException; +import org.apache.log4j.Logger; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.api.ComponentBaseTest; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.run.StartTest; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; +import org.openecomp.sdc.uici.tests.datatypes.CleanTypeEnum; +import org.openecomp.sdc.uici.tests.datatypes.UserCredentials; +import org.openecomp.sdc.uici.tests.utilities.FileHandling; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.testng.AssertJUnit; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Optional; +import org.testng.annotations.Parameters; + +import com.google.common.collect.Lists; +import com.thinkaurelius.titan.core.TitanGraph; + +public abstract class SetupCDTest extends ComponentBaseTest { + + private TitanSnapshot snapshot; + private static CleanTypeEnum cleanType; + + public SetupCDTest() { + super(new TestName(), SetupCDTest.class.getName()); + } + + public SetupCDTest(TestName name, String className) { + super(name, className); + } + + public static Logger logger = Logger.getLogger(SetupCDTest.class.getName()); + + /**************** CONSTANTS ****************/ + private static final String CREDENTIALS_FILE = "src/main/resources/ci/conf/credentials.yaml"; + public static final String SELENIUM_NODE_URL = "http://%s:%s/wd/hub"; + + /**************** PRIVATES ****************/ + public static Config config; + private Map credentialsYamlFileMap; + + private static String devUrl, cdUrl; + + @BeforeSuite(alwaysRun = true) + public static void openTitan() throws FileNotFoundException { + try { + openTitanLogic(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @AfterSuite(alwaysRun = true) + public static void shutdownTitan() { + shutdownTitanLogic(); + } + + @BeforeSuite(alwaysRun = true) + @Parameters({ "clean-type" }) + public void setEnvParameters(@Optional("PARTIAL") String cleanType) throws FileNotFoundException { + this.cleanType = CleanTypeEnum.findByName(cleanType); + System.out.println("setup before class"); + config = Utils.getConfig(); + loadCredentialsFile(); + setUrl(); + } + + @BeforeMethod(alwaysRun = true) + public void setBrowserBeforeTest() { + setBrowserBeforeTest(getRole()); + } + + /**************** AFTER ****************/ + @AfterMethod(alwaysRun = true) + public void quitAfterTest() { + System.out.println("closing browser"); + GeneralUIUtils.getDriver().quit(); + } + + @BeforeMethod(alwaysRun = true) + public void beforeState(java.lang.reflect.Method method) throws Exception { + CleanTypeEnum cleanType = getCleanMode(); + switch (cleanType) { + case FULL: { + super.performeClean(); + break; + } + case PARTIAL: { + takeTitanSnapshot(); + break; + } + case NONE: { + // No Clean Up + break; + } + default: { + throw new NotImplementedException("Enum Value:" + cleanType.name() + " Is not handled"); + } + } + + } + + @AfterMethod(alwaysRun = true) + public void afterState(ITestResult result) throws Exception { + CleanTypeEnum cleanType = getCleanMode(); + switch (cleanType) { + case FULL: { + super.performeClean(); + break; + } + case PARTIAL: { + resetToOriginalSnapshot(); + break; + } + case NONE: { + // No Clean Up + break; + } + default: { + throw new NotImplementedException("Enum Value:" + cleanType.name() + " Is not handled"); + } + } + + } + + private void takeTitanSnapshot() { + List edgeList = Lists.newArrayList(getTitanGraph().edges(null)); + List verList = Lists.newArrayList(getTitanGraph().vertices(null)); + setSnapshot(new TitanSnapshot(edgeList, verList)); + + } + + private static class TitanSnapshot { + List edges; + List vertices; + + public List getEdges() { + return edges; + } + + public List getVertices() { + return vertices; + } + + private TitanSnapshot(List edges, List vertices) { + super(); + this.edges = edges; + this.vertices = vertices; + } + } + + private void resetToOriginalSnapshot() { + + List joinedEdges = new ArrayList<>(); + List joinedVertices = new ArrayList<>(); + TitanSnapshot original = getSnapshot(); + takeTitanSnapshot(); + TitanSnapshot current = getSnapshot(); + + original.getEdges().stream().forEach(e -> addIfIdInList(e, current.getEdges(), joinedEdges, e2 -> e2.id())); + original.getVertices().stream() + .forEach(e -> addIfIdInList(e, current.getVertices(), joinedVertices, e2 -> e2.id())); + + List edgesToRemove = removeFromList(current.getEdges(), joinedEdges, e2 -> e2.id()); + List verticesToRemove = removeFromList(current.getVertices(), joinedVertices, e2 -> e2.id()); + + List edgesToAdd = removeFromList(original.getEdges(), joinedEdges, e2 -> e2.id()); + List verticesToAdd = removeFromList(original.getVertices(), joinedVertices, e2 -> e2.id()); + + if (edgesToAdd.isEmpty() && verticesToAdd.isEmpty()) { + edgesToRemove.stream().forEach(e -> e.remove()); + verticesToRemove.stream().forEach(v -> v.remove()); + } + + } + + private List removeFromList(List listToRemoveFrom, List elementsToRemove, + Function idGetter) { + Set idSet = new HashSet<>(); + // Fill The Set + elementsToRemove.stream().map(e -> idGetter.apply(e)).forEach(e2 -> idSet.add(e2)); + return listToRemoveFrom.stream().filter(p -> !idSet.contains(idGetter.apply(p))).collect(Collectors.toList()); + + } + + private void addIfIdInList(Element e, List listToCheck, List listToAddTo, + Function idGetter) { + Stream matchingElements = listToCheck.stream() + .filter(p -> idGetter.apply(e).equals(idGetter.apply(p))); + listToAddTo.addAll(matchingElements.collect(Collectors.toList())); + } + + /**************** MAIN ****************/ + public static void main(String[] args) { + System.out.println("---------------------"); + System.out.println("running test from CLI"); + System.out.println("---------------------"); + args = new String[] { "ui-ci.xml" }; + StartTest.main(args); + } + + /***********************************************************************************/ + + protected void setBrowserBeforeTest(UserRoleEnum role) { + System.out.println("setup before test"); + GeneralUIUtils.initDriver(); + setDevUrl(role); + loginWithUser(role); + } + + protected void setUrl() { + cdUrl = config.getUrl(); + setDevUrl(getRole()); + } + + private Map loadCredentialsFile() { + final String credintialsFile = (System.getProperty("credentials.file") != null) + ? System.getProperty("credentials.file") : CREDENTIALS_FILE; + System.out.println("credentials file is : " + credintialsFile); + FunctionalInterfaces.swallowException( + () -> credentialsYamlFileMap = (Map) FileHandling.parseYamlFile(credintialsFile)); + System.out.println(credentialsYamlFileMap.toString()); + return (Map) credentialsYamlFileMap; + } + + protected UserCredentials getUserCredentialsFromFile(String userRole) throws Exception { + Map credentialsMap = (Map) credentialsYamlFileMap.get(userRole); + String user = (String) credentialsMap.get("username"); + String password = (String) credentialsMap.get("password"); + String firstname = (String) credentialsMap.get("firstname"); + String lastname = (String) credentialsMap.get("lastname"); + + return new UserCredentials(user, password, firstname, lastname); + } + + public void navigateToUrl(String url) throws InterruptedException { + WebDriver driver = GeneralUIUtils.getDriver(); + System.out.println("navigating to URL :" + url); + driver.navigate().to(url); + driver.manage().window().maximize(); + driver.manage().deleteAllCookies(); + } + + protected void loginToSystem(UserCredentials credentials) throws Exception { + + sendUserAndPasswordKeys(credentials); + WebElement submitButton = GeneralUIUtils.getDriver().findElement(By.name("btnSubmit")); + submitButton.click(); + WebElement buttonOK = GeneralUIUtils.getDriver().findElement(By.name("successOK")); + AssertJUnit.assertTrue(buttonOK.isDisplayed()); + buttonOK.click(); + System.out.println("Entering to design studio"); + Thread.sleep(2000); + WebElement enterToUserWorkspaceButton = GeneralUIUtils.getDriver() + .findElement(By.xpath("//button[@data-tests-id='Design Studio']")); + enterToUserWorkspaceButton.click(); + } + + private void sendUserAndPasswordKeys(UserCredentials userId) { + System.out.println("Login to system with user : " + userId.getUserId()); + WebElement userNameTextbox = GeneralUIUtils.getDriver().findElement(By.name("userid")); + userNameTextbox.sendKeys(userId.getUserId()); + WebElement passwordTextbox = GeneralUIUtils.getDriver().findElement(By.name("password")); + passwordTextbox.sendKeys(userId.getPassword()); + } + + public String getUrl() { + String url; + final CleanTypeEnum workMode = getCleanMode(); + switch (workMode) { + case FULL: { + url = devUrl; + break; + } + case PARTIAL: { + url = devUrl; + break; + } + case NONE: { + url = cdUrl; + break; + } + default: { + throw new NotImplementedException(workMode.name()); + } + + } + return url; + } + + public static void setDevUrl(UserRoleEnum role) { + String url = SetupCDTest.devUrl; + switch (role) { + case ADMIN: { + url = "http://localhost:8181/sdc1/proxy-admin1#/dashboard"; + break; + } + case DESIGNER: { + url = "http://localhost:8181/sdc1/proxy-designer1#/dashboard"; + // url = "http://localhost:9000/#/dashboard"; + break; + } + case GOVERNOR: { + url = "http://localhost:8181/sdc1/proxy-governor1#/dashboard"; + break; + } + case OPS: { + url = "http://localhost:8181/sdc1/proxy-ops1#/dashboard"; + break; + } + case TESTER: { + url = "http://localhost:8181/sdc1/proxy-tester1#/dashboard"; + break; + } + default: { + break; + } + } + SetupCDTest.devUrl = url; + } + + public static Config getConfig() { + return config; + } + + private User user; + + public void loginWithUser(UserRoleEnum role) { + + setUser(role); + String url = getUrl(); + System.out.println("URL is : " + url); + try { + navigateToUrl(url); + if (url.contains("https://www.e-access.att.com")) { + System.out.println("going to update designer user to mechIDs form..."); + UserCredentials credentials = getUserCredentialsFromFile(role.name().toLowerCase()); + loginToSystem(credentials); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void setUser(UserRoleEnum role) { + user = new User(); + user.setUserId(role.getUserId()); + user.setFirstName(role.getFirstName()); + user.setRole(role.name()); + } + + /** + * Current User Role + * + * @return + */ + public UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + + /** + * To change clean type update configuration.
+ * Do not override this method. + * + * @return + */ + protected final CleanTypeEnum getCleanMode() { + return cleanType; + } + + public User getUser() { + return user; + } + + protected void quitAndReLogin(UserRoleEnum role) { + quitAfterTest(); + setBrowserBeforeTest(role); + GeneralUIUtils.waitForLoader(30); + } + + public TitanSnapshot getSnapshot() { + return snapshot; + } + + public void setSnapshot(TitanSnapshot snapshot) { + this.snapshot = snapshot; + } + + public static TitanGraph getTitanGraph() { + return titanGraph; + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/generalTests/GeneralTests.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/generalTests/GeneralTests.java new file mode 100644 index 0000000000..c3caa98c54 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/generalTests/GeneralTests.java @@ -0,0 +1,26 @@ +package org.openecomp.sdc.uici.tests.execute.generalTests; + +import static org.testng.AssertJUnit.assertTrue; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.testng.annotations.Test; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; + +public class GeneralTests extends SetupCDTest{ + + @Test + public void filterVFCMT() throws Exception { + Resource resource = AtomicOperationUtils.createResourcesByTypeNormTypeAndCatregory(ResourceTypeEnum.VFCMT, NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_CALL_CONTROL , UserRoleEnum.DESIGNER, true).left().value(); + assertTrue(!GeneralUIUtils.isElementPresent(resource.getName())); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.MainMenue.CATALOG.getValue()).click(); + assertTrue(!GeneralUIUtils.isElementPresent(resource.getName())); + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/service/ServiceBasicTests.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/service/ServiceBasicTests.java new file mode 100644 index 0000000000..e42de862b7 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/service/ServiceBasicTests.java @@ -0,0 +1,147 @@ +package org.openecomp.sdc.uici.tests.execute.service; + +import static org.testng.AssertJUnit.assertTrue; + +import java.util.Arrays; + +import org.apache.http.HttpStatus; +import org.openecomp.sdc.uici.tests.datatypes.CanvasElement; +import org.openecomp.sdc.uici.tests.datatypes.CanvasManager; +import org.openecomp.sdc.uici.tests.datatypes.CreateAndUpdateStepsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openecomp.sdc.uici.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.uici.tests.utilities.FileHandling; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.uici.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.uici.tests.utilities.RestCDUtils; +import org.openecomp.sdc.uici.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.uici.tests.verificator.ServiceVerificator; +import org.openecomp.sdc.uici.tests.verificator.VfVerificator; +import org.openqa.selenium.WebElement; +import org.testng.annotations.Test; + +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; + +public class ServiceBasicTests extends SetupCDTest { + + @Test + public void testCreateService() { + ServiceReqDetails createServiceInUI = ServiceUIUtils.createServiceInUI(getUser()); + ServiceVerificator.verifyServiceCreated(createServiceInUI, getUser()); + } + + @Test + public void testLinkTwoRI() { + + // create 1st VF + ResourceReqDetails resourceOne = ResourceUIUtils.createResourceInUI(getUser()); + assertTrue(RestCDUtils.getResource(resourceOne).getErrorCode() == HttpStatus.SC_OK); + // add LoadBalancer to resource + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + canvasManager.createElementOnCanvas(LeftPanelCanvasItems.OBJECT_STORAGE); + GeneralUIUtils.checkIn(); + + // create 2nd VF + ResourceReqDetails resourceTwo = ResourceUIUtils.createResourceInUI(getUser()); + assertTrue(RestCDUtils.getResource(resourceTwo).getErrorCode() == HttpStatus.SC_OK); + // add ObjectStorage to resource + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + canvasManager = CanvasManager.getCanvasManager(); + canvasManager.createElementOnCanvas(LeftPanelCanvasItems.LOAD_BALANCER); + GeneralUIUtils.checkIn(); + + // create service + ServiceReqDetails createServiceInUI = ServiceUIUtils.createServiceInUI(getUser()); + // Verify Service is Created + ServiceVerificator.verifyServiceCreated(createServiceInUI, getUser()); + + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + canvasManager = CanvasManager.getCanvasManager(); + + // adding two resource instances + CanvasElement vfOne = canvasManager.createElementOnCanvas(resourceOne.getName()); + + CanvasElement vfTwo = canvasManager.createElementOnCanvas(resourceTwo.getName()); + // link elements + canvasManager.linkElements(vfOne, vfTwo); + + // check results + ServiceVerificator.verifyServiceCreated(createServiceInUI, getUser()); + ServiceVerificator.verifyLinkCreated(createServiceInUI, getUser()); + + } + + /** + * This method tests the following:
+ * 1. Import of VF
+ * 2. Certification Of Vf
+ * 3. Adding deployment artifact to VF
+ * 4. Creation of Service
+ * 5. Adding Vf instance to Service
+ * 6. Service Certification
+ * 7. Approving Service to distribution by Governor
+ * 8. Making sure service is ready to distribute by ops
+ */ + @Test + public void testBuildServiceForDistribution() { + ResourceReqDetails importedVf = ResourceUIUtils.importVfInUI(getUser(), FileHandling.getResourcesFilesPath(), + "valid_vf.csar"); + GeneralUIUtils.waitForLoader(20); + // Verify Import + VfVerificator.verifyResourceIsCreated(importedVf); + + // Create Deployment Artifact + ArtifactUIUtils.createDeploymentArtifactOnVf(FileHandling.getResourcesFilesPath() + "myYang.xml", + ArtifactTypeEnum.YANG_XML); + VfVerificator.verifyResourceContainsDeploymentArtifacts(importedVf, + Arrays.asList(new ArtifactTypeEnum[] { ArtifactTypeEnum.YANG_XML })); + + // Submit For Testing Process VF + GeneralUIUtils.submitForTestingElement(importedVf.getName()); + + // Certify The VF + quitAndReLogin(UserRoleEnum.TESTER); + ResourceUIUtils.testAndAcceptElement(importedVf); + + // Verify Certification + GeneralUIUtils.waitForLoader(); + VfVerificator.verifyResourceIsCertified(importedVf); + + // Create Service + quitAndReLogin(UserRoleEnum.DESIGNER); + ServiceReqDetails createServiceInUI = ServiceUIUtils.createServiceInUI(getUser()); + ServiceVerificator.verifyServiceCreated(createServiceInUI, getUser()); + + // Drag the VF To the Service + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + canvasManager.createElementOnCanvas(importedVf.getName()); + + // Submit For Testing Process Service + GeneralUIUtils.submitForTestingElement(null); + + // Certify The Service + quitAndReLogin(UserRoleEnum.TESTER); + ResourceUIUtils.testAndAcceptElement(createServiceInUI); + ServiceVerificator.verifyServiceCertified(createServiceInUI, getUser()); + + // Approve with governor + quitAndReLogin(UserRoleEnum.GOVERNOR); + ServiceUIUtils.approveServiceForDistribution(createServiceInUI); + + // Log in with Ops and verify that can distribute + quitAndReLogin(UserRoleEnum.OPS); + GeneralUIUtils.getWebElementWaitForVisible(createServiceInUI.getName()).click(); + WebElement distributeWebElement = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.LifeCyleChangeButtons.DISTRIBUTE.getValue()); + assertTrue(distributeWebElement != null); + + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/service/ServiceInputsTests.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/service/ServiceInputsTests.java new file mode 100644 index 0000000000..b3e8e023ca --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/service/ServiceInputsTests.java @@ -0,0 +1,124 @@ +package org.openecomp.sdc.uici.tests.execute.service; + +import static org.testng.AssertJUnit.assertTrue; +import static org.testng.AssertJUnit.assertFalse; + +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.uici.tests.datatypes.CanvasElement; +import org.openecomp.sdc.uici.tests.datatypes.CanvasManager; +import org.openecomp.sdc.uici.tests.datatypes.CreateAndUpdateStepsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.BreadcrumbsButtonsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.InputsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.ModalItems; +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openecomp.sdc.uici.tests.utilities.FileHandling; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.uici.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.uici.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.uici.tests.verificator.ServiceVerificator; +import org.testng.annotations.Test; + +public class ServiceInputsTests extends SetupCDTest { + + public String serviceName = ""; + + @Test + private void testSelectingInputAndAddingItToTheService() { + ServiceInputsTestsSetUp(); + + assertTrue(GeneralUIUtils.getWebElementWaitForVisible(InputsEnum.FIRST_INPUT_CHECKBOX.getValue()).getAttribute("class").contains("disabled")); + assertTrue(GeneralUIUtils.isElementPresent(InputsEnum.SERVICE_INPUT.getValue())); + } + + @Test + private void testDeletingAnInputFromTheService() { + ServiceInputsTestsSetUp(); + + // clicking on the delete input button and accepting the delete + GeneralUIUtils.getWebElementWaitForClickable(InputsEnum.DELETE_INPUT.getValue()).click(); + GeneralUIUtils.getWebElementWaitForClickable(ModalItems.OK.getValue()).click(); + + assertFalse(GeneralUIUtils.getWebElementWaitForVisible(InputsEnum.FIRST_INPUT_CHECKBOX.getValue()).getAttribute("class").contains("disabled")); + assertFalse(GeneralUIUtils.isElementPresent(InputsEnum.SERVICE_INPUT.getValue())); + } + + @Test + private void testCheckingInTheServiceAndButtonsAreDisabled() throws Exception { + ServiceInputsTestsSetUp(); + + // Checking in the service and accessing it again in the home + GeneralUIUtils.checkIn(); + GeneralUIUtils.closeNotificatin(); + GeneralUIUtils.findComponentAndClick(serviceName); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.INPUTS); + GeneralUIUtils.getWebElementWaitForClickable(InputsEnum.VF_INSTANCE.getValue()).click(); + + assertTrue(GeneralUIUtils.getWebElementWaitForVisible(InputsEnum.FIRST_INPUT_CHECKBOX.getValue()).getAttribute("class").contains("disabled")); + assertTrue(GeneralUIUtils.getWebElementWaitForVisible(InputsEnum.SECOND_INPUT_CHECKBOX.getValue()).getAttribute("class").contains("disabled")); + assertTrue(GeneralUIUtils.getWebElementWaitForVisible(InputsEnum.DELETE_INPUT.getValue()).getAttribute("class").contains("disabled")); + } + + @Test + private void testInputsSanity() throws Exception { + ServiceInputsTestsSetUp(); + + assertTrue(GeneralUIUtils.getWebElementWaitForVisible(InputsEnum.FIRST_INPUT_CHECKBOX.getValue()).getAttribute("class").contains("disabled")); + assertTrue(GeneralUIUtils.isElementPresent(InputsEnum.SERVICE_INPUT.getValue())); + + // clicking on the delete input button and accepting the delete + GeneralUIUtils.getWebElementWaitForClickable(InputsEnum.DELETE_INPUT.getValue()).click(); + GeneralUIUtils.getWebElementWaitForClickable(ModalItems.OK.getValue()).click(); + + assertFalse(GeneralUIUtils.getWebElementWaitForVisible(InputsEnum.FIRST_INPUT_CHECKBOX.getValue()).getAttribute("class").contains("disabled")); + assertFalse(GeneralUIUtils.isElementPresent(InputsEnum.SERVICE_INPUT.getValue())); + + // adding the input to the service again + GeneralUIUtils.getWebElementWaitForClickable(InputsEnum.FIRST_INPUT_CHECKBOX.getValue()).click(); + GeneralUIUtils.getWebElementWaitForClickable(InputsEnum.ADD_INPUTS_BUTTON.getValue()).click(); + + // Checking in the service and accessing it again in the home + GeneralUIUtils.checkIn(); + GeneralUIUtils.closeNotificatin(); + GeneralUIUtils.findComponentAndClick(serviceName); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.INPUTS); + GeneralUIUtils.getWebElementWaitForClickable(InputsEnum.VF_INSTANCE.getValue()).click(); + + assertTrue(GeneralUIUtils.getWebElementWaitForVisible(InputsEnum.FIRST_INPUT_CHECKBOX.getValue()).getAttribute("class").contains("disabled")); + assertTrue(GeneralUIUtils.getWebElementWaitForVisible(InputsEnum.SECOND_INPUT_CHECKBOX.getValue()).getAttribute("class").contains("disabled")); + } + + private void ServiceInputsTestsSetUp() { + // create vf + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "service_with_inputs.csar"; + ResourceReqDetails importVfREsourceInUI = ResourceUIUtils.importVfInUIWithoutCheckin(getUser(), filePath, fileName); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.closeNotificatin(); + GeneralUIUtils.checkIn(); + GeneralUIUtils.closeNotificatin(); + + // create service + ServiceReqDetails createServiceInUI = ServiceUIUtils.createServiceInUI(getUser()); + ServiceVerificator.verifyServiceCreated(createServiceInUI, getUser()); + serviceName = createServiceInUI.getName(); + + // go to composition + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + + // drag vf into canvas + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement canvasElement = canvasManager.createElementOnCanvas(importVfREsourceInUI.getName()); + canvasManager.selectElementFromCanvas(canvasElement); + GeneralUIUtils.waitForLoader(); + + // moving to inputs view + GeneralUIUtils.getWebElementWaitForClickable(BreadcrumbsButtonsEnum.COMPONENT.getValue()).click(); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.INPUTS); + + // adding the input to the service + GeneralUIUtils.getWebElementWaitForClickable(InputsEnum.VF_INSTANCE.getValue()).click(); + GeneralUIUtils.getWebElementWaitForClickable(InputsEnum.FIRST_INPUT_CHECKBOX.getValue()).click(); + GeneralUIUtils.getWebElementWaitForClickable(InputsEnum.ADD_INPUTS_BUTTON.getValue()).click(); + } +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfBasicTests.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfBasicTests.java new file mode 100644 index 0000000000..d3bb8a1375 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfBasicTests.java @@ -0,0 +1,333 @@ +package org.openecomp.sdc.uici.tests.execute.vf; + +import static org.openecomp.sdc.common.datastructure.FunctionalInterfaces.retryMethodOnException; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.Callable; + +import org.apache.http.HttpStatus; +import org.openecomp.sdc.uici.tests.datatypes.CanvasElement; +import org.openecomp.sdc.uici.tests.datatypes.CanvasManager; +import org.openecomp.sdc.uici.tests.datatypes.CreateAndUpdateStepsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openecomp.sdc.uici.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.uici.tests.utilities.FileHandling; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.uici.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.uici.tests.utilities.RestCDUtils; +import org.openecomp.sdc.uici.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.uici.tests.verificator.ServiceVerificator; +import org.openecomp.sdc.uici.tests.verificator.VfVerificator; +import org.openqa.selenium.WebElement; +import org.testng.annotations.Test; + +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceRespJavaObject; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.general.Convertor; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; + +public class VfBasicTests extends SetupCDTest { + + @Test + public void testImportVfTableColumns() { + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.OPEN_MODAL_BUTTON.getValue()).click(); + + assertTrue(GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.VENDOR_HEADER_COL.getValue()) != null); + assertTrue(GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.NAME_HEADER_COL.getValue()) != null); + assertTrue(GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.CATEGORY_HEADER_COL.getValue()) != null); + + assertTrue(GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.VERSION_HEADER_COL.getValue()) != null); + } + + private void testsToChangeSomeParametersValues(){ + //open parameters form + GeneralUIUtils.moveToHTMLElementByDataTestId(DataTestIdEnum.Artifatcs.BASE_CMUI_LAB1_ARTIFACT_ITEM.getValue()); + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.Artifatcs.OPEN_EDIT_PROPERTIES_FORM_OF_BASE_CMUI_LAB1.getValue()).click(); + //edit values for parameter without default value and for parameter with default + String valueForFirstParam="111"; + String newValueForSecondParam="222"; + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.EnvParametersForm.VALUE_FIELD_OF_AVAILABILITY_ZONE_0.getValue()).sendKeys(valueForFirstParam); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.EnvParametersForm.VALUE_FIELD_OF_CMAUI_FLAVOR.getValue()).clear(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.EnvParametersForm.VALUE_FIELD_OF_CMAUI_FLAVOR.getValue()).sendKeys(newValueForSecondParam); + //save changes + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.EnvParametersForm.SAVE_BUTTON.getValue()).click(); + GeneralUIUtils.waitForLoader(); + //open form again + GeneralUIUtils.moveToHTMLElementByDataTestId(DataTestIdEnum.Artifatcs.BASE_CMUI_LAB1_ARTIFACT_ITEM.getValue()); + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.Artifatcs.OPEN_EDIT_PROPERTIES_FORM_OF_BASE_CMUI_LAB1.getValue()).click(); + //check if values were changed + assertTrue("The parameter value without default was not changed.", + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.EnvParametersForm.VALUE_FIELD_OF_AVAILABILITY_ZONE_0.getValue()).getAttribute("value").equals(valueForFirstParam)); + assertTrue("The parameter value with default was not changed.", + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.EnvParametersForm.VALUE_FIELD_OF_CMAUI_FLAVOR.getValue()).getAttribute("value").equals(newValueForSecondParam)); + //delete the value of the parameter without default + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.EnvParametersForm.DELETE_AVAILABILITY_ZONE_0.getValue()).click(); + boolean isThereDefaultValue=!GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.EnvParametersForm.DEFAULT_VALUE_COLMN_OF_CMAUI_FLAVOR.getValue()).getText().isEmpty(); + if(isThereDefaultValue){ + //revert the value of the parameter with default + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.EnvParametersForm.REVERET_CMAUI_FLAVOR.getValue()).click(); + } + //save changes + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.EnvParametersForm.SAVE_BUTTON.getValue()).click(); + GeneralUIUtils.waitForLoader(); + //open form again + GeneralUIUtils.moveToHTMLElementByDataTestId(DataTestIdEnum.Artifatcs.BASE_CMUI_LAB1_ARTIFACT_ITEM.getValue()); + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.Artifatcs.OPEN_EDIT_PROPERTIES_FORM_OF_BASE_CMUI_LAB1.getValue()).click(); + //check if values were changed + assertTrue("The parameter value without default was not deleted.", + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.EnvParametersForm.VALUE_FIELD_OF_AVAILABILITY_ZONE_0.getValue()).getAttribute("value").equals("")); + if(isThereDefaultValue){ + String theDefaultValue="m1.large"; + assertTrue("The parameter value with default was not reverted.", + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.EnvParametersForm.VALUE_FIELD_OF_CMAUI_FLAVOR.getValue()).getAttribute("value").equals(theDefaultValue)); + } + } + + @Test + public void testVFiUpdateHeatENVParameters() throws Exception { + // create vf + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "vmmc_work.csar"; + ResourceReqDetails importVfResourceInUI = ResourceUIUtils.importVfInUIWithoutCheckin(getUser(), filePath, + fileName); + GeneralUIUtils.closeNotificatin(); + GeneralUIUtils.checkIn(); + GeneralUIUtils.closeNotificatin(); + //create service + ServiceReqDetails createServiceInUI = ServiceUIUtils.createServiceInUI(getUser()); + ServiceVerificator.verifyServiceCreated(createServiceInUI, getUser()); + //go to composition + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + //drag vf into canvas + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement canvasElement = canvasManager.createElementOnCanvas(importVfResourceInUI.getName()); + canvasManager.selectElementFromCanvas(canvasElement); + GeneralUIUtils.waitForLoader(); + //go to deployment artifacts tab + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.RightBar.DEPLOYMENT_ARTIFACTS.getValue()).click(); + //test change parameters + testsToChangeSomeParametersValues(); + } + + @Test + public void testVFUpdateHeatENVParameters() throws Exception { + // create vf + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "vmmc_work.csar"; + ResourceReqDetails importVfResourceInUI = ResourceUIUtils.importVfInUIWithoutCheckin(getUser(), filePath, + fileName); + //go to deployment artifacts + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.DEPLOYMENT_ARTIFACT); + //test change parameters + testsToChangeSomeParametersValues(); + } + + @Test + public void testUpdateVfCreatedFromCsar() throws Exception { + // create vf + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "Sample_CSAR.csar"; + ResourceReqDetails importVfResourceInUI = ResourceUIUtils.importVfInUIWithoutCheckin(getUser(), filePath, + fileName); + // update csar + fileName = "Sample_CSAR2.csar"; + ResourceUIUtils.updateVfCsar(filePath, fileName); + VfVerificator.verifyNumOfComponentInstances(importVfResourceInUI, 4); + } + + @Test + public void testImportVf() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "Sample_CSAR.csar"; + ResourceReqDetails importVfResourceInUI = ResourceUIUtils.importVfInUI(getUser(), filePath, fileName); + GeneralUIUtils.waitForLoader(); + assertTrue(RestCDUtils.getResource(importVfResourceInUI).getErrorCode() == HttpStatus.SC_OK); + } + + @Test + public void testCreateVf() { + ResourceReqDetails createResourceInUI = ResourceUIUtils.createResourceInUI(getUser()); + assertTrue(RestCDUtils.getResource(createResourceInUI).getErrorCode() == HttpStatus.SC_OK); + } + + @Test + public void testDeleteInstanceFromCanvas() { + ResourceReqDetails createResourceInUI = ResourceUIUtils.createResourceInUI(getUser()); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + + canvasManager.createElementOnCanvas(LeftPanelCanvasItems.BLOCK_STORAGE); + CanvasElement computeElement = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.COMPUTE); + VfVerificator.verifyNumOfComponentInstances(createResourceInUI, 2); + canvasManager.deleteElementFromCanvas(computeElement); + VfVerificator.verifyNumOfComponentInstances(createResourceInUI, 1); + + } + + @Test + public void testUpdateInstanceAttributeValue() { + // creare vfc with attrs + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "VFCWithAttributes.yml"; + ResourceReqDetails importVfcResourceInUI = ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + GeneralUIUtils.checkIn(); + // create vf + ResourceReqDetails createResourceInUI = ResourceUIUtils.createResourceInUI(getUser()); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + // add vfc to canvas + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement canvasElement = canvasManager.createElementOnCanvas(importVfcResourceInUI.getName()); + canvasManager.selectElementFromCanvas(canvasElement); + // edit value of vfc attr + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.RightBar.PROPERTIES_AND_ATTRIBUTES.getValue()) + .click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.RightBar.MYATTR_ATTR_FROM_LIST.getValue()).click(); + + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributeForm.DEFAULT_VAL_FIELD.getValue()) + .sendKeys("2"); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributeForm.DONE_BUTTON.getValue()).click(); + String newValue = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.RightBar.MYATTR_ATTR_VALUE_FROM_LIST.getValue()).getText(); + assertEquals("2", newValue); + } + + @Test(enabled = false) + public void testAddInfomratinalArtifact() throws Exception { + ResourceReqDetails createResourceInUI = ResourceUIUtils.createResourceInUI(getUser()); + + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.INFORMATION_ARTIFACT); + + ArtifactReqDetails informationalArtifact = ElementFactory.getDefaultArtifact(); + final String FILE_PATH = System.getProperty("user.dir") + "\\src\\main\\resources\\Files\\"; + final String FILE_NAME = "Valid_tosca_Mycompute.yml"; + + ArtifactUIUtils.addInformationArtifact(informationalArtifact, FILE_PATH + FILE_NAME, + DataTestIdEnum.InformationalArtifatcs.FEATURES); + ArtifactUIUtils.addInformationArtifact(informationalArtifact, FILE_PATH + FILE_NAME, + DataTestIdEnum.InformationalArtifatcs.CAPACITY); + + RestResponse getResourceResponse = RestCDUtils.getResource(createResourceInUI); + assertEquals("Did not succeed to get resource after create", HttpStatus.SC_OK, + getResourceResponse.getErrorCode().intValue()); + + Map> artifactsListFromResponse = ArtifactUIUtils + .getArtifactsListFromResponse(getResourceResponse.getResponse(), "artifacts"); + Map map = artifactsListFromResponse.get("Features"); + + assertTrue(artifactsListFromResponse.size() >= 2); + + } + + @Test + public void testVfCertification() throws IOException { + // Create VF + ResourceReqDetails createResourceInUI = ResourceUIUtils.createResourceInUI(getUser()); + assertTrue(RestCDUtils.getResource(createResourceInUI).getErrorCode() == HttpStatus.SC_OK); + + // Submit For Testing Process + GeneralUIUtils.submitForTestingElement(createResourceInUI.getName()); + + // Tester + quitAndReLogin(UserRoleEnum.TESTER); + ResourceUIUtils.testAndAcceptElement(createResourceInUI); + + // Verification + GeneralUIUtils.waitForLoader(); + VfVerificator.verifyResourceIsCertified(createResourceInUI); + + } + + @Test + public void testDeploymentArtifactForVFi() { + User user = getUser(); + // create vf + ResourceReqDetails createResourceInUI = ResourceUIUtils.createResourceInUI(user); + GeneralUIUtils.checkIn(); + GeneralUIUtils.waitForLoader(); + // create service + GeneralUIUtils.clickOnCreateEntityFromDashboard(DataTestIdEnum.Dashboard.BUTTON_ADD_SERVICE.getValue()); + ResourceUIUtils.defineResourceName("serv"); + GeneralUIUtils.defineDescription("description"); + GeneralUIUtils.waitForLoader(); + ResourceUIUtils.defineResourceCategory("Mobility", "selectGeneralCategory"); + ResourceUIUtils.defineProjectCode("012345"); + GeneralUIUtils.clickSaveButton(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + GeneralUIUtils.waitForLoader(); + // add vf to canvas + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement canvasElement = canvasManager.createElementOnCanvas(createResourceInUI.getName()); + canvasManager.selectElementFromCanvas(canvasElement); + GeneralUIUtils.waitForLoader(); + // add artifact + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.RightBar.DEPLOYMENT_ARTIFACTS.getValue()).click(); + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.RightBar.ADD_ARTIFACT_BUTTON.getValue()).click(); + String newArtifactLabel = "newArtifact"; + ArtifactReqDetails details = new ArtifactReqDetails("new_atifact", "DCAE_INVENTORY_EVENT", "desc", "", + newArtifactLabel); + ResourceUIUtils.fillinDeploymentArtifactFormAndClickDone(details, + FileHandling.getResourcesFilesPath() + "yamlSample.yml"); + assertTrue(GeneralUIUtils.isElementPresent("artifact_Display_Name-" + newArtifactLabel)); + // edit artifact + GeneralUIUtils.getWebElementWaitForClickable("artifact_Display_Name-" + newArtifactLabel).click(); + String newFileName = "yamlSample2.yml"; + retryMethodOnException( + () -> GeneralUIUtils.getWebElementByDataTestId(DataTestIdEnum.GeneralSection.BROWSE_BUTTON.getValue()) + .sendKeys(FileHandling.getResourcesFilesPath() + newFileName)); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.DONE.getValue()).click(); + GeneralUIUtils.waitForLoader(); + assertEquals(newFileName, + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.RightBar.ARTIFACT_NAME.getValue()).getText()); + // delete artifact + GeneralUIUtils.moveToHTMLElementByDataTestId("artifact_Display_Name-" + newArtifactLabel); + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.RightBar.DELETE_ARTIFACT_BUTTON.getValue()).click(); + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.ModalItems.OK.getValue()).click(); + GeneralUIUtils.waitForLoader(); + assertTrue(!GeneralUIUtils.isElementPresent("artifact_Display_Name-" + newArtifactLabel)); + } + + @Test + public void testDisplayVfModuleProperies() { + //create vf with components instances properties + ResourceReqDetails importedVf = ResourceUIUtils.importVfInUI(getUser(), FileHandling.getResourcesFilesPath(), + "vmmc_work.csar"); + GeneralUIUtils.waitForLoader(40); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.DEPLOYMENT); + GeneralUIUtils.getWebElementWaitForClickable("hierarchy-module-0-title").click(); + assertTrue(GeneralUIUtils.isElementPresent(DataTestIdEnum.DeploymentSection.MODULE_PROPERTIES_HEADER_LIST.getValue())); + } + + protected ArtifactReqDetails defineInformationalArtifact() throws IOException, Exception { + return ElementFactory.getDefaultArtifact(); + } + + protected ResourceRespJavaObject buildResourceJavaObject(ResourceReqDetails resource, RestResponse restResponse, + User user) { + ResourceRespJavaObject resourceObject = new ResourceRespJavaObject(); + resourceObject = Convertor.constructFieldsForRespValidation(resource, resource.getVersion(), user); + resourceObject.setLifecycleState((LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT).toString()); + resourceObject.setAbstractt("false"); + resourceObject.setIcon(resource.getIcon().replace(" ", "")); + resourceObject.setUniqueId(ResponseParser.getUniqueIdFromResponse(restResponse)); + return resourceObject; + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfCanvasTests.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfCanvasTests.java new file mode 100644 index 0000000000..73b09666ae --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfCanvasTests.java @@ -0,0 +1,80 @@ +package org.openecomp.sdc.uici.tests.execute.vf; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.uici.tests.datatypes.CanvasElement; +import org.openecomp.sdc.uici.tests.datatypes.CanvasManager; +import org.openecomp.sdc.uici.tests.datatypes.CreateAndUpdateStepsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.uici.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.uici.tests.verificator.VfVerificator; +import org.testng.annotations.Test; + +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; + +public class VfCanvasTests extends SetupCDTest { + + @Test + public void testCanvasDrag() { + ResourceReqDetails createResourceInUI = ResourceUIUtils.createResourceInUI(getUser()); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement createElementOnCanvas = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.BLOCK_STORAGE); + + ImmutablePair preMovePos = ResourceUIUtils.getRIPosition(createResourceInUI, getUser()); + + canvasManager.moveElementOnCanvas(createElementOnCanvas); + + VfVerificator.verifyRILocationChanged(createResourceInUI, preMovePos, getUser()); + + } + + @Test + public void testCanvasConnectComponents() { + ResourceReqDetails createResourceInUI = ResourceUIUtils.createResourceInUI(getUser()); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement bsElement = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.BLOCK_STORAGE); + CanvasElement computeElement = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.COMPUTE); + + canvasManager.linkElements(bsElement, computeElement); + + VfVerificator.verifyLinkCreated(createResourceInUI); + + } + + @Test + public void testCanvasVFSanity() { + ResourceReqDetails createResourceInUI = ResourceUIUtils.createResourceInUI(getUser()); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.COMPOSITION); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + + CanvasElement bsElement = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.BLOCK_STORAGE); + CanvasElement compElement = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.COMPUTE); + + ImmutablePair preMovePos = ResourceUIUtils.getRIPosition(createResourceInUI, getUser()); + canvasManager.moveElementOnCanvas(bsElement); + canvasManager.moveElementOnCanvas(compElement); + + VfVerificator.verifyRILocationChanged(createResourceInUI, preMovePos, getUser()); + + CanvasElement bsElement2 = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.BLOCK_STORAGE); + + canvasManager.linkElements(bsElement2, compElement); + + VfVerificator.verifyLinkCreated(createResourceInUI); + + VfVerificator.verifyNumOfComponentInstances(createResourceInUI, 3); + + canvasManager.moveElementOnCanvas(compElement); + + canvasManager.deleteElementFromCanvas(bsElement); + + VfVerificator.verifyNumOfComponentInstances(createResourceInUI, 2); + + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfDeploymentTests.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfDeploymentTests.java new file mode 100644 index 0000000000..47344b7c68 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfDeploymentTests.java @@ -0,0 +1,340 @@ +package org.openecomp.sdc.uici.tests.execute.vf; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.util.regex.Pattern; + +import org.openecomp.sdc.uici.tests.datatypes.CreateAndUpdateStepsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openecomp.sdc.uici.tests.utilities.FileHandling; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.uici.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.uici.tests.utilities.RestCDUtils; +import org.openqa.selenium.WebElement; +import org.testng.annotations.Test; + +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; + +public class VfDeploymentTests extends SetupCDTest { + + // *****************************EditNamePopoverTests*****************************// + @Test + public void ClickingOnEditNamePopoverIconShouldOpenTheEditNamePopoverForm() { + EditNamePopoverTestsSetUp(); + + assertTrue(GeneralUIUtils.isElementPresent(DataTestIdEnum.UpdateNamePopover.POPOVER_FORM.getValue())); + } + + @Test + public void ModuleDataShouldBeDisplayedInTheEditNameForm() { + EditNamePopoverTestsSetUp(); + + WebElement instanceName = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_INSTANCE_NAME.getValue()); + WebElement heatName = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_HEAT_NAME.getValue()); + WebElement moduleName = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_MODULE_NAME.getValue()); + + String moduleNameToDivide = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()).getText(); + + String[] dividedModuleName = moduleNameToDivide.split(Pattern.quote("..")); + + assertEquals(dividedModuleName[0], instanceName.getText()); + assertEquals(dividedModuleName[1], heatName.getAttribute("value")); + assertEquals(dividedModuleName[2], moduleName.getText()); + + } + + @Test + public void CloseButtonShouldCloseThePopover() { + EditNamePopoverTestsSetUp(); + + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_CLOSE_BUTTON.getValue()) + .click(); + + assertFalse(GeneralUIUtils.isElementPresent(DataTestIdEnum.UpdateNamePopover.POPOVER_FORM.getValue())); + } + + @Test + public void XButtonShouldCloseThePopover() { + EditNamePopoverTestsSetUp(); + + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_X_BUTTON.getValue()) + .click(); + + assertFalse(GeneralUIUtils.isElementPresent(DataTestIdEnum.UpdateNamePopover.POPOVER_FORM.getValue())); + } + + @Test + public void SaveButtonShouldBeDisabledWhileTheNameHasNotBeenChanged() { + EditNamePopoverTestsSetUp(); + + WebElement popoverSaveButton = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_SAVE_BUTTON.getValue()); + + assertTrue(popoverSaveButton.getAttribute("class").contains("disabled")); + } + + @Test + public void ClickingOnTheSaveButtonShouldUpdateTheModuleName() { + EditNamePopoverTestsSetUp(); + + String newName = "testName"; + + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_HEAT_NAME.getValue()) + .clear(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_HEAT_NAME.getValue()) + .sendKeys(newName); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_SAVE_BUTTON.getValue()) + .click(); + + GeneralUIUtils.waitForLoader(); + + String moduleName = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()).getText(); + + String[] dividedModuleName = moduleName.split(Pattern.quote("..")); + + assertEquals(dividedModuleName[1], newName); + } + + @Test + public void testUpdateModuleNameSanity() { + EditNamePopoverTestsSetUp(); + + String newName = "testName"; + + WebElement instanceName = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_INSTANCE_NAME.getValue()); + WebElement heatName = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_HEAT_NAME.getValue()); + WebElement moduleName = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_MODULE_NAME.getValue()); + + String moduleNameToDivide = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()).getText(); + + String[] dividedModuleName = moduleNameToDivide.split(Pattern.quote("..")); + + assertEquals(dividedModuleName[0], instanceName.getText()); + assertEquals(dividedModuleName[1], heatName.getAttribute("value")); + assertEquals(dividedModuleName[2], moduleName.getText()); + + WebElement popoverSaveButton = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.POPOVER_SAVE_BUTTON.getValue()); + + assertTrue(popoverSaveButton.getAttribute("class").contains("disabled")); + + heatName.clear(); + heatName.sendKeys(newName); + + popoverSaveButton.click(); + + GeneralUIUtils.waitForLoader(); + + moduleNameToDivide = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()).getText(); + dividedModuleName = moduleNameToDivide.split(Pattern.quote("..")); + + assertEquals(dividedModuleName[1], newName); + } + + // *****************************DeploymentTabsTests*****************************// + + @Test + public void testTabIsBeingDisplayedAtDeploymentView() { + DeploymentTestsSetUp(); + + assertTrue(GeneralUIUtils.isElementPresent(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue())); + } + + @Test + public void testClickingOnTabSetsItAsSelected() { + DeploymentTestsSetUp(); + + WebElement hierarchyTab = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue()); + hierarchyTab.click(); + + assertTrue(hierarchyTab.getAttribute("class").contains("selected")); + } + + @Test + public void testTabNameIsBeingDisplayedInTheSelectedTabHeader() { + DeploymentTestsSetUp(); + + // select the hierarchy tab and check the header + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue()).click(); + WebElement tabHeader = GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.TAB_HEADER.getValue()); + + assertEquals(tabHeader.getText(), "HIERARCHY"); + } + + @Test + public void testSelectingModuleNameInTheHierarchyTabShouldSelectIt() { + DeploymentTestsSetUp(); + + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue()).click(); + WebElement hierarchyModule = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE_TITLE.getValue()); + + hierarchyModule.click(); + + assertTrue(hierarchyModule.getAttribute("class").contains("selected")); + } + + @Test + public void testSelectingModuleNameInTheHierarchyTabShouldExpandIt() { + DeploymentTestsSetUp(); + + // select hierarchy tab + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue()).click(); + WebElement hierarchyModule = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()); + + hierarchyModule.click(); + + assertTrue(hierarchyModule.getAttribute("class").contains("expanded")); + } + + @Test + public void testSelectingModuleNameInTheHierarchyTabShouldDisplayItsData() { + DeploymentTestsSetUp(); + + // select hierarchy tab + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue()).click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()).click(); + + assertTrue(GeneralUIUtils.isElementPresent(DataTestIdEnum.TabsBar.HIERARCHY_SELECTED_MODULE_DATA.getValue())); + } + + @Test(enabled = false) + public void testResourceNameIsBeingDisplayedInTheSelectedTabSubHeader() { + DeploymentTestsSetUp(); + + // select the hierarchy tab and check the header + // WebElement tabSubHeader = + // getWebElement(DataTestIdEnum.TabsBar.TAB_SUB_HEADER.getValue()); + + // assertEquals(tabSubHeader.getText(), vmmcCsar.getName()); + } + + @Test(enabled = false) + public void testSelectingModuleNameInTheHierarchyTabShouldDisplayItsInformation() throws IOException { + DeploymentTestsSetUp(); + + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue()).click(); + WebElement hierarchyModule = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()); + + // get the module + // String component = RestCDUtils.getResource(vmmcCsar).getResponse(); + // TODO idana fix test + /* + * GroupDefinitionInfo module = getModuleById(component, + * hierarchyModule.getText()); + * + * hierarchyModule.click(); + * + * assertModuleDetails(module, hierarchyModule); + */ + + } + + @Test(enabled = false) + public void testSelectingModuleNameInTheHierarchyTabShouldDisplayItsArtifacts() throws IOException { + DeploymentTestsSetUp(); + + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue()).click(); + WebElement hierarchyModule = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()); + + // TODO idana fix test + // Get the artifact from the module + /* + * String component = RestCDUtils.getResource(vmmcCsar, + * getUser()).getResponse(); GroupDefinitionInfo module = + * getModuleById(component, hierarchyModule.getText()); + * ArtifactDefinitionInfo artifact = module.getArtifacts().get(0); + * + * hierarchyModule.click(); + * + * assertModuleArtifactDetails(artifact); + */ + } + + @Test + public void testTabsViewSanity() throws IOException { + DeploymentTestsSetUp(); + + WebElement hierarchyTab = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue()); + + assertTrue(hierarchyTab != null); + + hierarchyTab.click(); + + assertTrue(hierarchyTab.getAttribute("class").contains("selected")); + + WebElement tabHeader = GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.TAB_HEADER.getValue()); + WebElement tabSubHeader = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.TAB_SUB_HEADER.getValue()); + + assertEquals(tabHeader.getText(), "HIERARCHY"); + // assertEquals(tabSubHeader.getText(), vmmcCsar.getName()); + + WebElement hierarchyModule = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()); + WebElement hierarchyModuleTitle = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE_TITLE.getValue()); + hierarchyModule.click(); + WebElement selectedModuleData = GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_SELECTED_MODULE_DATA.getValue()); + + assertTrue(hierarchyModuleTitle.getAttribute("class").contains("selected")); + assertTrue(hierarchyModule.getAttribute("class").contains("expanded")); + assertTrue(selectedModuleData.getAttribute("ng-if") != null); + // TODO idana fix test + /* + * String component = RestCDUtils.getResource(vmmcCsar, + * getUser()).getResponse(); GroupDefinitionInfo module = + * getModuleById(component, hierarchyModule.getText()); + * ArtifactDefinitionInfo artifact = module.getArtifacts().get(0); + * + * assertModuleDetails(module, hierarchyModule); + * + * assertModuleArtifactDetails(artifact); + */ + + } + + // ************************DeploymentTestsSetUpFunction************************// + + private void EditNamePopoverTestsSetUp() { + DeploymentTestsSetUp(); + + // clicking on a module and opening the edit name popover + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_TAB.getValue()).click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.TabsBar.HIERARCHY_MODULE.getValue()).click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.UpdateNamePopover.OPEN_POPOVER_ICON.getValue()) + .click(); + } + + private void DeploymentTestsSetUp() { + // import csar + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "vf_with_groups.csar"; + ResourceUIUtils.importVfInUI(getUser(), filePath, fileName); + + GeneralUIUtils.waitForLoader(20); + + // moving to deployment view + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.DEPLOYMENT); + } +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfOnboardingTests.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfOnboardingTests.java new file mode 100644 index 0000000000..a81d854630 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vf/VfOnboardingTests.java @@ -0,0 +1,63 @@ +package org.openecomp.sdc.uici.tests.execute.vf; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.uici.tests.utilities.OnboardUtility; +import org.openecomp.sdc.uici.tests.utilities.ResourceUIUtils; +import org.testng.annotations.Test; + +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import com.google.gson.GsonBuilder; + +public class VfOnboardingTests extends SetupCDTest { + + @Test + public void testUpdateVfCreatedOnBoarding() { + // create vf + ResourceReqDetails importVfResourceInUI = ResourceUIUtils.importVfFromOnBoardingModalWithoutCheckin(getUser(), + "mock_vf"); + // update vf + ResourceUIUtils.updateVfCsarFromOnBoarding(); + } + + @Test + public void createVfsFromOnboarding() throws IOException { + String folderPath = "C:\\onboardingTest\\onBoardingZips"; + File folder = new File(folderPath); + File[] listOfFiles = folder.listFiles(); + List zipFileNames = Arrays.asList(listOfFiles).stream().map(file -> file.getName()) + .filter(fileName -> fileName.endsWith(".zip")).collect(Collectors.toList()); + Map filesSuccessMap = new HashMap<>(); + for (String fileName : zipFileNames) { + try { + createSingleVfFromOnboarding(folderPath, fileName); + filesSuccessMap.put(fileName, "SUCCESS"); + } catch (Exception e) { + filesSuccessMap.put(fileName, "FAIL"); + } + } + Path file = Paths.get("RunResults.txt"); + String stringDataModel = new GsonBuilder().setPrettyPrinting().create().toJson(filesSuccessMap); + Files.write(file, stringDataModel.getBytes()); + } + + private static void createSingleVfFromOnboarding(String filePath, String zipFileName) { + String userId = UserRoleEnum.DESIGNER.getUserId(); + OnboardUtility.createVfFromOnboarding(userId, zipFileName, filePath); + GeneralUIUtils.submitForTestingElement("Vf From Onboarding"); + + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vfc/VfcBasicTests.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vfc/VfcBasicTests.java new file mode 100644 index 0000000000..eb4980e3a0 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/execute/vfc/VfcBasicTests.java @@ -0,0 +1,270 @@ +package org.openecomp.sdc.uici.tests.execute.vfc; + +import static org.testng.AssertJUnit.assertTrue; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.http.HttpStatus; +import org.openecomp.sdc.uici.tests.datatypes.CreateAndUpdateStepsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openecomp.sdc.uici.tests.utilities.FileHandling; +import org.openecomp.sdc.uici.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.uici.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.uici.tests.utilities.RestCDUtils; +import org.openecomp.sdc.uici.tests.verificator.VfVerificator; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Select; +import org.testng.annotations.Test; + +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; + +public class VfcBasicTests extends SetupCDTest { + + @Test + public void testRequirementsAndCapabilitiesSectionOfVfc() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "mycompute.yml"; + ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.REQUIREMENTS_AND_CAPABILITIES); + // all expected requirements + assertTrue("Not all expected requirements are displayed.", + GeneralUIUtils.isElementPresent("dependency") && GeneralUIUtils.isElementPresent("local_storage")); + // filter requirements + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ReqAndCapabilitiesSection.SEARCH_BOX.getValue()) + .sendKeys("root"); + Supplier supplier = () -> !GeneralUIUtils.isElementPresent("local_storage"); + Function resultVerifier = isNotPresent -> isNotPresent; + Boolean isFilteredRowNotPresent = FunctionalInterfaces.retryMethodOnResult(supplier, resultVerifier); + assertTrue("The new property was not inserted to the properties table.", isFilteredRowNotPresent); + assertTrue("Filter problem.", GeneralUIUtils.isElementPresent("dependency") && isFilteredRowNotPresent); + // move to cap tab + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ReqAndCapabilitiesSection.CAP_TAB.getValue()).click(); + GeneralUIUtils.getWebElementWaitForVisible("endpoint").click(); + GeneralUIUtils.getWebElementWaitForVisible("initiator").click(); + supplier = () -> GeneralUIUtils.isElementPresent(DataTestIdEnum.PropertyForm.FORM_CONTAINER.getValue()); + resultVerifier = isPresent -> isPresent; + Boolean isPopupOpen = FunctionalInterfaces.retryMethodOnResult(supplier, resultVerifier); + assertTrue("The update property popup was not opened.", isPopupOpen); + } + + @Test + public void testCreatePropertyTypeListForVfc() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "VFCWithAttributes.yml"; + ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.PROPERTIES); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertiesSection.ADD_BUTTON.getValue()).click(); + // fill in fields + String newPropName = "listProperty"; + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.NAME_FIELD.getValue()) + .sendKeys(newPropName); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.DESCRIPTION_FIELD.getValue()) + .sendKeys("desc"); + Select typeField = new Select( + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.TYPE_FIELD.getValue())); + typeField.selectByVisibleText("list"); + Select schemaTypeField = new Select( + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.SCHEMA_FIELD.getValue())); + schemaTypeField.selectByVisibleText("string"); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.LIST_TYPE_DEFAULT_VAL_FIELD.getValue()) + .sendKeys("first"); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.ADD_ITEM_TO_LIST_BUTTON.getValue()) + .click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.LIST_TYPE_DEFAULT_VAL_FIELD.getValue()) + .sendKeys("second"); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.ADD_ITEM_TO_LIST_BUTTON.getValue()) + .click(); + // save + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.SAVE_BUTTON.getValue()).click(); + Supplier supplier = () -> GeneralUIUtils.isElementPresent(newPropName); + Function resultVerifier = isPresent -> isPresent; + Boolean isPresent = FunctionalInterfaces.retryMethodOnResult(supplier, resultVerifier); + assertTrue("The new property was not inserted to the properties table.", isPresent); + } + + @Test + public void testCreatePropertyTypeMapForVfc() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "VFCWithAttributes.yml"; + ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.PROPERTIES); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertiesSection.ADD_BUTTON.getValue()).click(); + // fill in fields + String newPropName = "mapProperty"; + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.NAME_FIELD.getValue()) + .sendKeys(newPropName); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.DESCRIPTION_FIELD.getValue()) + .sendKeys("desc"); + Select typeField = new Select( + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.TYPE_FIELD.getValue())); + typeField.selectByVisibleText("map"); + Select schemaTypeField = new Select( + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.SCHEMA_FIELD.getValue())); + schemaTypeField.selectByVisibleText("string"); + // insert item to map + GeneralUIUtils + .getWebElementWaitForVisible( + DataTestIdEnum.PropertyForm.MAP_TYPE_DEFAULT_VAL_KEY_FIELD_FOR_FIRST_ITEM.getValue()) + .sendKeys("key1"); + GeneralUIUtils + .getWebElementWaitForVisible( + DataTestIdEnum.PropertyForm.MAP_TYPE_DEFAULT_VAL_VALUE_FIELD_FOR_FIRST_ITEM.getValue()) + .sendKeys("val1"); + // insert item to map + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.ADD_ITEM_TO_MAP_BUTTON.getValue()) + .click(); + GeneralUIUtils + .getWebElementWaitForVisible( + DataTestIdEnum.PropertyForm.MAP_TYPE_DEFAULT_VAL_KEY_FIELD_FOR_SECOND_ITEM.getValue()) + .sendKeys("key2"); + GeneralUIUtils + .getWebElementWaitForVisible( + DataTestIdEnum.PropertyForm.MAP_TYPE_DEFAULT_VAL_VALUE_FIELD_FOR_SECOND_ITEM.getValue()) + .sendKeys("val2"); + // delete item from map + GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.DELETE_FIRST_ITEM_FROM_MAP_BUTTON.getValue()) + .click(); + // save + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.SAVE_BUTTON.getValue()).click(); + Supplier supplier = () -> GeneralUIUtils.isElementPresent(newPropName); + Function resultVerifier = isPresent -> isPresent; + Boolean isPresent = FunctionalInterfaces.retryMethodOnResult(supplier, resultVerifier); + assertTrue("The new property was not inserted to the properties table.", isPresent); + } + + @Test + public void testCreatePropertyTypeDTForVfc() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "VFCWithAttributes.yml"; + ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.PROPERTIES); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertiesSection.ADD_BUTTON.getValue()).click(); + // fill in fields + String newPropName = "dt"; + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.NAME_FIELD.getValue()) + .sendKeys(newPropName); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.DESCRIPTION_FIELD.getValue()) + .sendKeys("desc"); + Select typeField = new Select( + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.TYPE_FIELD.getValue())); + typeField.selectByValue("org.openecomp.datatypes.heat.contrail.network.rule.PortPairs"); + GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.START_PORT_FIELD_FOR_PORT_PAIRS_DT.getValue()) + .sendKeys("first"); + // save + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.PropertyForm.SAVE_BUTTON.getValue()).click(); + Supplier supplier = () -> GeneralUIUtils.isElementPresent(newPropName); + Function resultVerifier = isPresent -> isPresent; + Boolean isPresent = FunctionalInterfaces.retryMethodOnResult(supplier, resultVerifier); + assertTrue("The new property was not inserted to the properties table.", isPresent); + } + + @Test + public void testViewAttributesTabForVfc() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "VFCWithAttributes.yml"; + ResourceReqDetails importVfcResourceInUI = ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.ATTRIBUTES); + + List attributesRows = GeneralUIUtils + .getWebElementsListWaitForVisible(DataTestIdEnum.AttributesSection.TABLE_ROWS.getValue()); + assertTrue("There is not any row in the table.", !CollectionUtils.isEmpty(attributesRows)); + // display editable buttons + assertTrue("The Add button is not dispaly.", + GeneralUIUtils.isElementPresent(DataTestIdEnum.AttributesSection.ADD_BUTTON.getValue())); + assertTrue("The Edit button is not dispaly for 'network' attribute.", GeneralUIUtils + .isElementPresent(DataTestIdEnum.AttributesSection.EDIT_BUTTON_FOR_NETWORK_ATTR.getValue())); + assertTrue("The Remove button is not dispaly for 'network' attribute.", GeneralUIUtils + .isElementPresent(DataTestIdEnum.AttributesSection.DELETE_BUTTON_FOR_NETWORK_ATTR.getValue())); + // click checkin + GeneralUIUtils.checkIn(); + // enter again + GeneralUIUtils.getWebElementWaitForVisible(importVfcResourceInUI.getName()).click(); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.ATTRIBUTES); + // the editable buttons disappear + assertTrue("The Add button is not dispaly.", + !GeneralUIUtils.isElementPresent(DataTestIdEnum.AttributesSection.ADD_BUTTON.getValue())); + assertTrue("The Edit button is not dispaly for 'network' attribute.", !GeneralUIUtils + .isElementPresent(DataTestIdEnum.AttributesSection.EDIT_BUTTON_FOR_NETWORK_ATTR.getValue())); + assertTrue("The Remove button is not dispaly for 'network' attribute.", !GeneralUIUtils + .isElementPresent(DataTestIdEnum.AttributesSection.DELETE_BUTTON_FOR_NETWORK_ATTR.getValue())); + } + + @Test + public void testCreateAttributeForVfc() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "VFCWithAttributes.yml"; + ResourceReqDetails importVfcResourceInUI = ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.ATTRIBUTES); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributesSection.ADD_BUTTON.getValue()).click(); + // fill in fields + String newAttrName = "attr"; + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributeForm.NAME_FIELD.getValue()) + .sendKeys(newAttrName); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributeForm.DESCRIPTION_FIELD.getValue()) + .sendKeys("desc"); + Select typeField = new Select( + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributeForm.TYPE_FIELD.getValue())); + typeField.selectByVisibleText("integer"); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributeForm.DEFAULT_VAL_FIELD.getValue()) + .sendKeys("2"); + // click ok + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributeForm.DONE_BUTTON.getValue()).click(); + Supplier supplier = () -> GeneralUIUtils.isElementPresent(newAttrName); + Function resultVerifier = isPresent -> isPresent; + Boolean isPresent = FunctionalInterfaces.retryMethodOnResult(supplier, resultVerifier); + assertTrue("The new attribute was not inserted to the attributes table.", isPresent); + } + + @Test + public void testUpdateTypeForAttributeOfVfc() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "VFCWithAttributes.yml"; + ResourceReqDetails importVfcResourceInUI = ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + VfVerificator.verifyResourceIsCreated(importVfcResourceInUI); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.ATTRIBUTES); + GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.AttributesSection.EDIT_BUTTON_FOR_NETWORK_ATTR.getValue()) + .click(); + // fill in fields + Select typeField = new Select( + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributeForm.TYPE_FIELD.getValue())); + typeField.selectByVisibleText("float"); + // click ok + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.AttributeForm.DONE_BUTTON.getValue()).click(); + Supplier supplier = () -> GeneralUIUtils.isElementPresent("float"); + Function resultVerifier = isPresent -> isPresent; + Boolean isPresent = FunctionalInterfaces.retryMethodOnResult(supplier, resultVerifier); + assertTrue("The attribute type was not updated.", isPresent); + } + + @Test + public void testDeleteAttributeForVfc() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "VFCWithAttributes.yml"; + ResourceReqDetails importVfcResourceInUI = ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.ATTRIBUTES); + GeneralUIUtils + .getWebElementWaitForVisible(DataTestIdEnum.AttributesSection.DELETE_BUTTON_FOR_NETWORK_ATTR.getValue()) + .click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.OK.getValue()).click(); + GeneralUIUtils.waitForLoader(); + Boolean retryResult = FunctionalInterfaces + .retryMethodOnResult(() -> !GeneralUIUtils.isElementPresent("networks"), boolResult -> boolResult); + assertTrue("The attribute is shown in the attributes table.", retryResult); + } + + @Test + public void testImportVfc() { + String filePath = FileHandling.getResourcesFilesPath(); + String fileName = "CP.yml"; + ResourceReqDetails importVfcResourceInUI = ResourceUIUtils.importVfcInUI(getUser(), filePath, fileName); + assertTrue(RestCDUtils.getResource(importVfcResourceInUI).getErrorCode() == HttpStatus.SC_OK); + } +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/run/StartTest.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/run/StartTest.java new file mode 100644 index 0000000000..25cf4749c5 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/run/StartTest.java @@ -0,0 +1,252 @@ +package org.openecomp.sdc.uici.tests.run; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.apache.log4j.Logger; +import org.apache.log4j.PropertyConfigurator; +import org.testng.TestNG; + +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.utils.Utils; + +public class StartTest { + + public static long timeOfTest = 0; + + public static boolean debug = false; + + public static AtomicBoolean loggerInitialized = new AtomicBoolean(false); + + protected static Logger logger = null; + + public static void main(String[] args) { + // TODO ui-ci add jar building + String debugEnabled = System.getProperty("debug"); + if (debugEnabled != null && debugEnabled.equalsIgnoreCase("true")) { + debug = true; + } + System.out.println("Debug mode is " + (debug ? "enabled" : "disabled")); + + enableLogger(); + + Config config = null; + try { + config = Utils.getConfig(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (config == null) { + logger.error("Failed to configuration file of ci tests."); + System.exit(1); + } + + TestNG testng = new TestNG(); + + List suites = new ArrayList(); + suites.add("testSuites/" + args[0]); + testng.setTestSuites(suites); + // testng.setUseDefaultListeners(true); + testng.setOutputDirectory("target/"); + + testng.run(); + + } + + public StartTest() { + logger = Logger.getLogger(StartTest.class.getName()); + } + + public static void enableLogger() { + + if (false == loggerInitialized.get()) { + + loggerInitialized.set(true); + + String log4jPropsFile = System.getProperty("log4j.configuration"); + if (System.getProperty("os.name").contains("Windows")) { + String logProps = "src/main/resources/ci/conf/log4j.properties"; + if (log4jPropsFile == null) { + System.setProperty("targetlog", "target/"); + log4jPropsFile = logProps; + } + + } + PropertyConfigurator.configureAndWatch(log4jPropsFile); + + } + } + + private List getClassesForPackage(String pkgname) { + + List classes = new ArrayList(); + + // Get a File object for the package + File directory = null; + String fullPath; + String relPath = pkgname.replace('.', '/'); + + // System.out.println("ClassDiscovery: Package: " + pkgname + + // " becomes Path:" + relPath); + + URL resource = ClassLoader.getSystemClassLoader().getResource(relPath); + + // System.out.println("ClassDiscovery: Resource = " + resource); + if (resource == null) { + throw new RuntimeException("No resource for " + relPath); + } + fullPath = resource.getFile(); + // System.out.println("ClassDiscovery: FullPath = " + resource); + + if (debug) { + System.out.println("fullPath is " + fullPath); + } + + try { + directory = new File(resource.toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException( + pkgname + " (" + resource + + ") does not appear to be a valid URL / URI. Strange, since we got it from the system...", + e); + } catch (IllegalArgumentException e) { + directory = null; + } + // System.out.println("ClassDiscovery: Directory = " + directory); + + if (directory != null && directory.exists()) { + + // Get the list of the files contained in the package + String[] files = directory.list(); + for (int i = 0; i < files.length; i++) { + + // we are only interested in .class files + if (files[i].endsWith(".class") && false == files[i].contains("$")) { + + // removes the .class extension + String className = pkgname + '.' + files[i].substring(0, files[i].length() - 6); + + // System.out.println("ClassDiscovery: className = " + + // className); + + if (debug) { + System.out.println("ClassDiscovery: className = " + className); + } + + try { + Class clas = Class.forName(className); + boolean isAddToRun = false; + Method[] methods = clas.getMethods(); + for (Method method : methods) { + Annotation[] anns = method.getAnnotations(); + for (Annotation an : anns) { + if (an.annotationType().getSimpleName().equalsIgnoreCase("Test")) { + isAddToRun = true; + break; + } + } + } + if (isAddToRun) + classes.add(clas); + } catch (ClassNotFoundException e) { + throw new RuntimeException("ClassNotFoundException loading " + className); + } + } + } + } else { + try { + String jarPath = fullPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", ""); + + if (debug) { + System.out.println("jarPath is " + jarPath); + } + + JarFile jarFile = new JarFile(jarPath); + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String entryName = entry.getName(); + if (entryName.startsWith(relPath) && entryName.length() > (relPath.length() + "/".length())) { + + // System.out.println("ClassDiscovery: JarEntry: " + + // entryName); + String className = entryName.replace('/', '.').replace('\\', '.').replace(".class", ""); + + // System.out.println("ClassDiscovery: className = " + + // className); + + if (false == className.contains("$")) { + + if (debug) { + System.out.println("ClassDiscovery: className = " + className); + } + + try { + Class clas = Class.forName(className); + boolean isAddToRun = false; + Method[] methods = clas.getMethods(); + for (Method method : methods) { + Annotation[] anns = method.getAnnotations(); + for (Annotation an : anns) { + if (an.annotationType().getSimpleName().equalsIgnoreCase("Test")) { + isAddToRun = true; + break; + } + } + } + if (isAddToRun) + classes.add(clas); + } catch (ClassNotFoundException e) { + throw new RuntimeException("ClassNotFoundException loading " + className); + } + } + } + } + jarFile.close(); + + } catch (IOException e) { + throw new RuntimeException(pkgname + " (" + directory + ") does not appear to be a valid package", e); + } + } + return classes; + } + + private void addTableHead(StringBuilder results) { + results.append(""); + results.append("").append("Unit Test").append(""); + results.append("").append("Result").append(""); + results.append(""); + } + + // private void addUnitTestResult(StringBuilder results, + // Class testClass, Result unitTestResult) { + // + // boolean isSuccess = unitTestResult.wasSuccessful(); + // + // String result = (isSuccess) ? "success" : "fail"; + // String fileName = FileUtils.getFileName(testClass.getName()); + // results.append(""); + // // + // results.append("").append(FileUtils.getFileName(testClass.getName())).append(""); + // results.append("") + // .append("" + // + fileName + "").append(""); + // results.append("").append(result) + // .append(""); + // results.append(""); + // } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ArtifactUIUtils.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ArtifactUIUtils.java new file mode 100644 index 0000000000..91c9c07da8 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ArtifactUIUtils.java @@ -0,0 +1,70 @@ +package org.openecomp.sdc.uici.tests.utilities; + +import static org.openecomp.sdc.common.datastructure.FunctionalInterfaces.retryMethodOnException; + +import java.util.Map; + +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.uici.tests.datatypes.CreateAndUpdateStepsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.Artifatcs; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.InformationalArtifatcs; +import org.openqa.selenium.WebElement; + +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; + +public final class ArtifactUIUtils { + + private ArtifactUIUtils() { + throw new UnsupportedOperationException(); + } + + public static void addInformationArtifact(ArtifactReqDetails artifact, String filePath, + final InformationalArtifatcs dataTestEnum) { + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.sleep(2000); + GeneralUIUtils.getWebElementWaitForVisible(dataTestEnum.getValue()).click(); + + final WebElement browseWebElement = FunctionalInterfaces.retryMethodOnException( + () -> GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.BROWSE_BUTTON.getValue())); + browseWebElement.sendKeys(filePath); + + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.DESCRIPTION.getValue()) + .sendKeys(artifact.getDescription()); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.DONE.getValue()).click(); + + } + + public static Map> getArtifactsListFromResponse(String jsonResponse, + String fieldOfArtifactList) { + JSONObject object = (JSONObject) JSONValue.parse(jsonResponse); + Map> map = (Map>) object.get(fieldOfArtifactList); + return map; + } + + /** + * Creates a deployment artifact on the vf.
+ * Moves automatically to DeploymentArtifact Section + * + * @param artifactPayloadPath + * @param artifactType + */ + public static void createDeploymentArtifactOnVf(final String artifactPayloadPath, + final ArtifactTypeEnum artifactType) { + GeneralUIUtils.moveToStep(CreateAndUpdateStepsEnum.DEPLOYMENT_ARTIFACT); + GeneralUIUtils.getWebElementWaitForClickable(Artifatcs.ADD_DEPLOYMENT_ARTIFACT.getValue()).click(); + GeneralUIUtils.getSelectList("Create New Artifact", Artifatcs.SELECT_ARTIFACT_DROPDOWN.getValue()); + GeneralUIUtils.getSelectList(artifactType.getType(), Artifatcs.ARTIFACT_TYPE_DROPDOWN.getValue()); + GeneralUIUtils.getWebElementWaitForVisible(Artifatcs.ARTIFACT_DESCRIPTION.getValue()) + .sendKeys("Artifact Description"); + GeneralUIUtils.getWebElementWaitForVisible(Artifatcs.ARTIFACT_LABEL.getValue()).sendKeys("MyArtifactLabel"); + retryMethodOnException(() -> GeneralUIUtils.getWebElementByDataTestId(Artifatcs.BROWSE_BUTTON.getValue()) + .sendKeys(artifactPayloadPath)); + GeneralUIUtils.getWebElementWaitForVisible(Artifatcs.ADD_BUTTON.getValue()).click(); + GeneralUIUtils.waitForLoader(); + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/FileHandling.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/FileHandling.java new file mode 100644 index 0000000000..b1549741ed --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/FileHandling.java @@ -0,0 +1,30 @@ +package org.openecomp.sdc.uici.tests.utilities; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.Map; + +import org.yaml.snakeyaml.Yaml; + +public class FileHandling { + + public static Map parseYamlFile(String filePath) throws FileNotFoundException { + Yaml yaml = new Yaml(); + File file = new File(filePath); + InputStream inputStream = new FileInputStream(file); + Map map = (Map) yaml.load(inputStream); + return map; + } + + public static String getBasePath() { + return System.getProperty("user.dir"); + } + + public static String getResourcesFilesPath() { + return getBasePath() + File.separator + "src" + File.separator + "main" + File.separator + "resources" + + File.separator + "Files" + File.separator; + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/GeneralUIUtils.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/GeneralUIUtils.java new file mode 100644 index 0000000000..42aab187ea --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/GeneralUIUtils.java @@ -0,0 +1,344 @@ +package org.openecomp.sdc.uici.tests.utilities; + +import static org.openecomp.sdc.common.datastructure.FunctionalInterfaces.retryMethodOnException; +import static org.openecomp.sdc.common.datastructure.FunctionalInterfaces.retryMethodOnResult; +import static org.openecomp.sdc.common.datastructure.FunctionalInterfaces.swallowException; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.openecomp.sdc.uici.tests.datatypes.CreateAndUpdateStepsEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.Dashboard; +import org.openecomp.sdc.uici.tests.execute.base.SetupCDTest; +import org.openqa.selenium.By; +import org.openqa.selenium.Platform; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.ui.ExpectedCondition; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.Select; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.testng.Assert; + +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; + +public final class GeneralUIUtils { + + private static final int DEFAULT_WAIT_TIME_IN_SECONDS = 10; + /**************** DRIVERS ****************/ + private static WebDriver driver; + + private GeneralUIUtils() { + throw new UnsupportedOperationException(); + } + + /** + * Finding a component in the home screen by name and clicks on it + * Uses the search + * + * @param componentName + * @throws Exception + */ + public static void findComponentAndClick(String componentName) throws Exception { + getWebElementWaitForVisible("main-menu-input-search").sendKeys(componentName); + try { + getWebElementWaitForClickable(componentName).click(); + GeneralUIUtils.waitForLoader(); + getWebElementWaitForVisible("formlifecyclestate"); + } catch (Exception e) { + String msg = String.format("DID NOT FIND A COMPONENT NAMED %s", componentName); + System.out.println(msg); + Assert.fail(msg); + } + } + + public static WebElement getWebElementWaitForVisible(String dataTestId) { + return getWebElementWaitForVisible(dataTestId, DEFAULT_WAIT_TIME_IN_SECONDS); + } + + public static WebElement getWebElementWaitForVisible(String dataTestId, int time) { + WebDriverWait wait = new WebDriverWait(getDriver(), time); + ExpectedCondition visibilityOfElementLocated = ExpectedConditions + .visibilityOfElementLocated(builDataTestIdLocator(dataTestId)); + WebElement webElement = wait.until(visibilityOfElementLocated); + return webElement; + } + + public static WebElement getWebElementWaitForClickable(String dataTestId) { + WebDriverWait wait = new WebDriverWait(getDriver(), DEFAULT_WAIT_TIME_IN_SECONDS); + ExpectedCondition condition = ExpectedConditions + .elementToBeClickable(builDataTestIdLocator(dataTestId)); + WebElement webElement = wait.until(condition); + return webElement; + } + + private static By builDataTestIdLocator(String dataTestId) { + return By.xpath("//*[@data-tests-id='" + dataTestId + "']"); + + } + + /** + * Returns A list of Web Elements When they are all visible + * + * @param dataTestId + * @return + */ + public static List getWebElementsListWaitForVisible(String dataTestId) { + WebDriverWait wait = new WebDriverWait(getDriver(), DEFAULT_WAIT_TIME_IN_SECONDS); + ExpectedCondition> visibilityOfAllElementsLocatedBy = ExpectedConditions + .visibilityOfAllElementsLocatedBy(builDataTestIdLocator(dataTestId)); + return wait.until(visibilityOfAllElementsLocatedBy); + } + + /** + * @deprecated Do not use. use {@link #getWebElementWaitForVisible(String)} + * @param dataTestId + * @return + */ + public static WebElement getWebElementByDataTestId(String dataTestId) { + return driver.findElement(builDataTestIdLocator(dataTestId)); + } + + /** + * Checks if element is present with given dataTestsId + * + * @param dataTestId + * @return + */ + public static boolean isElementPresent(String dataTestId) { + final boolean isPresent = !driver.findElements(builDataTestIdLocator(dataTestId)).isEmpty(); + return isPresent; + } + + public static void clickOnCreateEntityFromDashboard(String buttonId) { + Supplier addVfButtonSipplier = () -> { + // TODO ui-ci replace with data-test-id + GeneralUIUtils.moveToHTMLElementByClassName("w-sdc-dashboard-card-new"); + return GeneralUIUtils.getWebElementByDataTestId(buttonId); + }; + WebElement addVfButton = FunctionalInterfaces.retryMethodOnException(addVfButtonSipplier); + addVfButton.click(); + } + + // this function located select list by the data-test-id value and the item + // to be selected.. + public static Select getSelectList(String item, String dataTestId) { + Select selectlist = new Select(driver.findElement(builDataTestIdLocator(dataTestId))); + if (item != null) { + selectlist.selectByVisibleText(item); + } + return selectlist; + } + + // Define description area . + public static String defineDescription(String descriptionText) { + + WebElement resourceDescriptionTextbox = GeneralUIUtils.getWebElementWaitForVisible("description"); + resourceDescriptionTextbox.clear(); + resourceDescriptionTextbox.sendKeys(descriptionText); + + return descriptionText; + } + + /** + * Clicks on the create button waits for the create to finish and the check + * in button to appear + */ + public static void clickCreateButton() { + GeneralUIUtils.waitForLoader(); + getWebElementWaitForClickable(DataTestIdEnum.LifeCyleChangeButtons.CREATE.getValue()).click(); + GeneralUIUtils.waitForLoader(); + closeNotificatin(); + getWebElementWaitForVisible(DataTestIdEnum.LifeCyleChangeButtons.CHECK_IN.getValue()); + } + + public static void closeNotificatin() { + WebElement notification = driver.findElement(By.className("ui-notification")); + if (notification != null) { + notification.click(); + } + } + + public static void clickSaveButton() { + WebElement createButton = getWebElementWaitForClickable(DataTestIdEnum.LifeCyleChangeButtons.CREATE.getValue()); + createButton.click(); + } + + public static void checkIn() { + waitForLoader(); + getWebElementWaitForVisible(DataTestIdEnum.LifeCyleChangeButtons.CHECK_IN.getValue()).click(); + getWebElementWaitForVisible(DataTestIdEnum.ModalItems.ACCEP_TESTING_MESSAGE.getValue()).sendKeys("Check in !"); + getWebElementWaitForVisible(DataTestIdEnum.ModalItems.OK.getValue()).click(); + waitForLoader(); + } + + public static void moveToStep(CreateAndUpdateStepsEnum Stepname) { + waitForLoader(); + getWebElementWaitForClickable(Stepname.getValue()).click(); + waitForLoader(); + } + + public static void sleep(int duration) { + swallowException(() -> Thread.sleep(duration)); + } + + public static WebDriver getDriver() { + return driver; + } + + public static void initDriver() { + try { + System.out.println("opening browser"); + WebDriver webDriver; + boolean remoteTesting = SetupCDTest.config.isRemoteTesting(); + if (!remoteTesting) { + webDriver = new FirefoxDriver(); + } else { + String remoteEnvIP = SetupCDTest.config.getRemoteTestingMachineIP(); + String remoteEnvPort = SetupCDTest.config.getRemoteTestingMachinePort(); + DesiredCapabilities cap = new DesiredCapabilities(); + cap = DesiredCapabilities.firefox(); + cap.setPlatform(Platform.WINDOWS); + cap.setBrowserName("firefox"); + + String remoteNodeUrl = String.format(SetupCDTest.SELENIUM_NODE_URL, remoteEnvIP, remoteEnvPort); + webDriver = new RemoteWebDriver(new URL(remoteNodeUrl), cap); + + } + driver = webDriver; + + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + + } + + /** + * waits until either loader finishes or 10 seconds has passed.
+ * If 10 seconds has passed and loader didn't finish throws + * LoaderStuckException.
+ */ + public static void waitForLoader() { + waitForLoader(10); + } + + /** + * waits until either loader finishes or maxWaitTimeInSeconds has + * passed.
+ * If maxWaitTimeInSeconds has passed and loader didn't finish throws + * LoaderStuckException.
+ * + * @param maxWaitTimeInSeconds + */ + public static void waitForLoader(int maxWaitTimeInSeconds) { + long maxWaitTimeMS = maxWaitTimeInSeconds * 1000L; + Boolean loaderIsRunning = retryMethodOnResult( + () -> isElementPresent(DataTestIdEnum.GeneralSection.LOADER.getValue()), + isLoaderPresent -> !isLoaderPresent, maxWaitTimeMS, 50); + if (loaderIsRunning) { + throw new LoaderStuckException( + "UI Loader is stuck, max wait time of " + maxWaitTimeInSeconds + " seconds has passed."); + } + + } + + private static class LoaderStuckException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private LoaderStuckException(String message) { + super(message); + } + } + + /** + * Move to HTML element by class name. When moving to the HTML element, it + * will raise hover event. + * + * @param className + */ + public static void moveToHTMLElementByClassName(String className) { + Actions actions = new Actions(getDriver()); + final WebElement createButtonsArea = getDriver().findElement(By.className(className)); + actions.moveToElement(createButtonsArea).perform(); + } + + /** + * Move to HTML element by element id. When moving to the HTML element, it + * will raise hover event. + * + * @param className + */ + public static void moveToHTMLElementByDataTestId(String dataTestId) { + Actions actions = new Actions(getDriver()); + final WebElement createButtonsArea = getWebElementByDataTestId(dataTestId); + actions.moveToElement(createButtonsArea).perform(); + } + + public static void defineVendorName(String resourceVendorName) { + // TODO ui-ci replace with Enum + WebElement resourceVendorNameTextbox = getWebElementWaitForVisible("vendorName"); + resourceVendorNameTextbox.clear(); + resourceVendorNameTextbox.sendKeys(resourceVendorName); + } + + public static String defineUserId(String UserId) { + // TODO ui-ci replace with Enum + WebElement resourceTagsTextbox = getWebElementWaitForVisible("contactId"); + resourceTagsTextbox.clear(); + resourceTagsTextbox.sendKeys(UserId); + return UserId; + } + + public static void clickAddComponent(Dashboard componentType) { + Runnable clickAddTask = () -> { + // TODO ui-ci replace with data-test-id + moveToHTMLElementByClassName("w-sdc-dashboard-card-new"); + WebElement addVfButton = getWebElementByDataTestId(componentType.getValue()); + addVfButton.click(); + }; + retryMethodOnException(clickAddTask); + } + + /** + * This method perform submit for testing process for existing service or + * resource.
+ * It assumes it is activated when in the resource screen and the Submit For + * Testing button is available. + * + * @param componentNameForMessage + * TODO + */ + public static void submitForTestingElement(String componentNameForMessage) { + waitForLoader(); + getWebElementWaitForVisible(DataTestIdEnum.LifeCyleChangeButtons.SUBMIT_FOR_TESTING.getValue()).click(); + waitForLoader(); + getWebElementWaitForVisible(DataTestIdEnum.ModalItems.SUMBIT_FOR_TESTING_MESSAGE.getValue()) + .sendKeys("Submit for testing for " + componentNameForMessage); + waitForLoader(); + getWebElementWaitForClickable(DataTestIdEnum.ModalItems.OK.getValue()).click(); + waitForLoader(); + waitForElementToDisappear(DataTestIdEnum.ModalItems.OK.getValue()); + + } + + /** + * Waits Until elements disappears or until 10 seconds pass + * + * @param dataTestId + */ + public static void waitForElementToDisappear(String dataTestId) { + Supplier elementPresenseChecker = () -> GeneralUIUtils.isElementPresent(dataTestId); + Function verifier = isElementPresent -> !isElementPresent; + FunctionalInterfaces.retryMethodOnResult(elementPresenseChecker, verifier); + + } + +} \ No newline at end of file diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/MethodManipulationUtils.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/MethodManipulationUtils.java new file mode 100644 index 0000000000..28b39e86f3 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/MethodManipulationUtils.java @@ -0,0 +1,15 @@ +package org.openecomp.sdc.uici.tests.utilities; + +/** + * Class For manipulations on method + * + * @author mshitrit + * + */ +public final class MethodManipulationUtils { + + private MethodManipulationUtils() { + throw new IllegalAccessError(); + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/OnboardUtility.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/OnboardUtility.java new file mode 100644 index 0000000000..3d21539e86 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/OnboardUtility.java @@ -0,0 +1,477 @@ +package org.openecomp.sdc.uici.tests.utilities; + +import static org.testng.AssertJUnit.assertTrue; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.nio.file.FileSystems; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; + +import javax.validation.constraints.AssertTrue; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.json.JSONObject; +import org.junit.Test; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; + +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; + +/** + * Utility Class For Onboarding + * + * @author mshitrit + * + */ +public final class OnboardUtility { + + private OnboardUtility() { + throw new UnsupportedOperationException(); + } + + private static final class Constants { + private static final String VENDOR_SOFTWARE_PRODUCTS = "vendor-software-products"; + private static final String VENDOR_LICENSE_MODELS = "vendor-license-models"; + + private static final String VSP_ID = "vspId"; + private static final String VALUE = "value"; + + enum Actions { + CHECK_IN("Checkin"), SUBMIT("Submit"), CREATE_PACKAGE("Create_Package"); + + private String value; + + private Actions(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + }; + } + + /** + * @param heatFileName + * @param filepath + * @param userId + * @param vld + * @return + * @throws Exception + */ + public static void createVendorSoftwareProduct(String heatFileName, String filepath, String userId, + VendorLicenseDetails vld) { + RestResponse createNewVendorSoftwareProduct = FunctionalInterfaces + .swallowException(() -> createNewVendorSoftwareProduct(vld, userId)); + assertTrue(createNewVendorSoftwareProduct.getErrorCode() == HttpStatus.SC_OK); + String vspid = ResponseParser.getValueFromJsonResponse(createNewVendorSoftwareProduct.getResponse(), + Constants.VSP_ID); + + RestResponse response = FunctionalInterfaces + .swallowException(() -> uploadHeatPackage(filepath, heatFileName, vspid, userId)); + assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + + response = actionOnComponent(vspid, Constants.Actions.CHECK_IN.getValue(), Constants.VENDOR_SOFTWARE_PRODUCTS, + userId); + assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + + response = actionOnComponent(vspid, Constants.Actions.SUBMIT.getValue(), Constants.VENDOR_SOFTWARE_PRODUCTS, + userId); + assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + + response = actionOnComponent(vspid, Constants.Actions.CREATE_PACKAGE.getValue(), + Constants.VENDOR_SOFTWARE_PRODUCTS, userId); + assertTrue(response.getErrorCode() == HttpStatus.SC_OK); + + } + + /** + * Contains Details Relevant to Vendor License + * + * @author mshitrit + * + */ + public static final class VendorLicenseDetails { + private final String vendorId; + private final String vendorLicenseName; + private final String vendorLicenseAgreementId; + private final String featureGroupId; + private final String vendorSoftwareProduct; + + private VendorLicenseDetails(String vendorId, String vendorLicenseName, String vendorLicenseAgreementId, + String featureGroupId) { + super(); + this.vendorId = vendorId; + this.vendorLicenseName = vendorLicenseName; + this.vendorLicenseAgreementId = vendorLicenseAgreementId; + this.featureGroupId = featureGroupId; + vendorSoftwareProduct = UUID.randomUUID().toString().split("-")[0]; + } + + public String getVendorId() { + return vendorId; + } + + public String getVendorLicenseName() { + return vendorLicenseName; + } + + public String getVendorLicenseAgreementId() { + return vendorLicenseAgreementId; + } + + public String getFeatureGroupId() { + return featureGroupId; + } + + public String getVendorSoftwareProduct() { + return vendorSoftwareProduct; + } + + } + + /** + * Creates Vendor License + * + * @param userId + * @return + * @throws Exception + */ + public static VendorLicenseDetails createVendorLicense(String userId) { + final String fieldNameValue = Constants.VALUE; + String vendorLicenseName = UUID.randomUUID().toString().split("-")[0]; + RestResponse vendorLicenseResponse = FunctionalInterfaces + .swallowException(() -> createVendorLicenseModels(vendorLicenseName, userId)); + assertTrue(vendorLicenseResponse.getErrorCode() == HttpStatus.SC_OK); + + String vendorId = ResponseParser.getValueFromJsonResponse(vendorLicenseResponse.getResponse(), fieldNameValue); + + RestResponse vendorKeyGroupsResponse = FunctionalInterfaces + .swallowException(() -> createVendorKeyGroups(vendorId, userId)); + assertTrue(vendorKeyGroupsResponse.getErrorCode() == HttpStatus.SC_OK); + String keyGroupId = ResponseParser.getValueFromJsonResponse(vendorKeyGroupsResponse.getResponse(), + fieldNameValue); + + RestResponse vendorEntitlementPool = FunctionalInterfaces + .swallowException(() -> createVendorEntitlementPool(vendorId, userId)); + assertTrue(vendorEntitlementPool.getErrorCode() == HttpStatus.SC_OK); + String entitlementPoolId = ResponseParser.getValueFromJsonResponse(vendorEntitlementPool.getResponse(), + fieldNameValue); + + RestResponse vendorLicenseFeatureGroups = FunctionalInterfaces.swallowException( + () -> createVendorLicenseFeatureGroups(vendorId, keyGroupId, entitlementPoolId, userId)); + assertTrue(vendorLicenseFeatureGroups.getErrorCode() == HttpStatus.SC_OK); + String featureGroupId = ResponseParser.getValueFromJsonResponse(vendorLicenseFeatureGroups.getResponse(), + fieldNameValue); + + RestResponse vendorLicenseAgreement = FunctionalInterfaces + .swallowException(() -> createVendorLicenseAgreement(vendorId, featureGroupId, userId)); + assertTrue(vendorLicenseAgreement.getErrorCode() == HttpStatus.SC_OK); + String vendorLicenseAgreementId = ResponseParser.getValueFromJsonResponse(vendorLicenseAgreement.getResponse(), + fieldNameValue); + + RestResponse actionOnComponent = actionOnComponent(vendorId, Constants.Actions.CHECK_IN.getValue(), + Constants.VENDOR_LICENSE_MODELS, userId); + assertTrue(actionOnComponent.getErrorCode() == HttpStatus.SC_OK); + + actionOnComponent = actionOnComponent(vendorId, Constants.Actions.SUBMIT.getValue(), + Constants.VENDOR_LICENSE_MODELS, userId); + assertTrue(actionOnComponent.getErrorCode() == HttpStatus.SC_OK); + + return new VendorLicenseDetails(vendorId, vendorLicenseName, vendorLicenseAgreementId, featureGroupId); + } + + private static RestResponse actionOnComponent(String vspid, String action, String onboardComponent, String userId) { + Config config = FunctionalInterfaces.swallowException(() -> Utils.getConfig()); + String url = String.format("http://%s:%s/onboarding-api/v1.0/%s/%s/actions", config.getCatalogBeHost(), + config.getCatalogBePort(), onboardComponent, vspid); + + JSONObject jObject = new JSONObject(); + FunctionalInterfaces.swallowException(() -> jObject.put("action", action)); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = FunctionalInterfaces + .swallowException(() -> http.httpSendPut(url, jObject.toString(), headersMap)); + return response; + } + + private static RestResponse createVendorLicenseModels(String name, String userId) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models", config.getCatalogBeHost(), + config.getCatalogBePort()); + + JSONObject jObject = new JSONObject(); + jObject.put("vendorName", name); + jObject.put("description", "new vendor license model"); + jObject.put("iconRef", "icon"); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObject.toString(), headersMap); + return response; + + } + + private static RestResponse createVendorLicenseAgreement(String vspid, String featureGroupId, String userId) + throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models/%s/license-agreements", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + + JSONObject licenseTermpObject = new JSONObject(); + licenseTermpObject.put("choice", "Fixed_Term"); + licenseTermpObject.put("other", ""); + + JSONObject jObjectBody = new JSONObject(); + jObjectBody.put("name", "abc"); + jObjectBody.put("description", "new vendor license agreement"); + jObjectBody.put("requirementsAndConstrains", "abc"); + jObjectBody.put("licenseTerm", licenseTermpObject); + jObjectBody.put("addedFeatureGroupsIds", Arrays.asList(featureGroupId).toArray()); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObjectBody.toString(), headersMap); + return response; + } + + private static RestResponse createVendorLicenseFeatureGroups(String vspid, String licenseKeyGroupId, + String entitlementPoolId, String userId) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models/%s/feature-groups", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + + JSONObject jObject = new JSONObject(); + jObject.put("name", "xyz"); + jObject.put("description", "new vendor license feature groups"); + jObject.put("partNumber", "123abc456"); + jObject.put("addedLicenseKeyGroupsIds", Arrays.asList(licenseKeyGroupId).toArray()); + jObject.put("addedEntitlementPoolsIds", Arrays.asList(entitlementPoolId).toArray()); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObject.toString(), headersMap); + return response; + + } + + private static RestResponse createVendorEntitlementPool(String vspid, String userId) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models/%s/entitlement-pools", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + + JSONObject jEntitlementMetricObject = new JSONObject(); + jEntitlementMetricObject.put("choice", "CPU"); + jEntitlementMetricObject.put("other", ""); + + JSONObject jAggregationFunctionObject = new JSONObject(); + jAggregationFunctionObject.put("choice", "Peak"); + jAggregationFunctionObject.put("other", ""); + + JSONObject jOperationalScope = new JSONObject(); + jOperationalScope.put("choices", Arrays.asList("Availability_Zone").toArray()); + jOperationalScope.put("other", ""); + + JSONObject jTimeObject = new JSONObject(); + jTimeObject.put("choice", "Hour"); + jTimeObject.put("other", ""); + + JSONObject jObjectBody = new JSONObject(); + jObjectBody.put("name", "def"); + jObjectBody.put("description", "new vendor license entitlement pool"); + jObjectBody.put("thresholdValue", "23"); + jObjectBody.put("thresholdUnits", "Absolute"); + jObjectBody.put("entitlementMetric", jEntitlementMetricObject); + jObjectBody.put("increments", "abcd"); + jObjectBody.put("aggregationFunction", jAggregationFunctionObject); + jObjectBody.put("operationalScope", jOperationalScope); + jObjectBody.put("time", jTimeObject); + jObjectBody.put("manufacturerReferenceNumber", "123aaa"); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObjectBody.toString(), headersMap); + return response; + } + + private static RestResponse createVendorKeyGroups(String vspid, String userId) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models/%s/license-key-groups", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + + JSONObject jOperationalScope = new JSONObject(); + jOperationalScope.put("choices", Arrays.asList("Tenant").toArray()); + jOperationalScope.put("other", ""); + + JSONObject jObjectBody = new JSONObject(); + jObjectBody.put("name", "keyGroup"); + jObjectBody.put("description", "new vendor license key group"); + jObjectBody.put("operationalScope", jOperationalScope); + jObjectBody.put("type", "Universal"); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObjectBody.toString(), headersMap); + return response; + } + + private static RestResponse createNewVendorSoftwareProduct(VendorLicenseDetails vld, String userId) + throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products", + config.getCatalogBeHost(), config.getCatalogBePort()); + + JSONObject jlicensingDataObj = new JSONObject(); + jlicensingDataObj.put("licenseAgreement", vld.getVendorLicenseAgreementId()); + jlicensingDataObj.put("featureGroups", Arrays.asList(vld.getFeatureGroupId()).toArray()); + + JSONObject jObject = new JSONObject(); + jObject.put("name", vld.getVendorSoftwareProduct()); + jObject.put("description", "new VSP description"); + jObject.put("category", "resourceNewCategory.generic"); + jObject.put("subCategory", "resourceNewCategory.generic.database"); + jObject.put("licensingVersion", "1.0"); + jObject.put("vendorName", vld.getVendorLicenseName()); + jObject.put("vendorId", vld.getVendorId()); + jObject.put("icon", "icon"); + jObject.put("licensingData", jlicensingDataObj); + + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + + RestResponse response = http.httpSendPost(url, jObject.toString(), headersMap); + + return response; + } + + private static RestResponse uploadHeatPackage(String filepath, String filename, String vspid, String userId) + throws Exception { + Config config = Utils.getConfig(); + CloseableHttpResponse response = null; + + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + mpBuilder.addPart("resourceZip", new FileBody(getTestZipFile(filepath, filename))); + + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products/%s/upload", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + + Map headersMap = prepareHeadersMap(userId); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "multipart/form-data"); + + CloseableHttpClient client = HttpClients.createDefault(); + try { + HttpPost httpPost = new HttpPost(url); + RestResponse restResponse = new RestResponse(); + + Iterator iterator = headersMap.keySet().iterator(); + while (iterator.hasNext()) { + String key = iterator.next(); + String value = headersMap.get(key); + httpPost.addHeader(key, value); + } + httpPost.setEntity(mpBuilder.build()); + response = client.execute(httpPost); + HttpEntity entity = response.getEntity(); + String responseBody = null; + if (entity != null) { + InputStream instream = entity.getContent(); + StringWriter writer = new StringWriter(); + IOUtils.copy(instream, writer); + responseBody = writer.toString(); + try { + + } finally { + instream.close(); + } + } + + restResponse.setErrorCode(response.getStatusLine().getStatusCode()); + restResponse.setResponse(responseBody); + + return restResponse; + + } finally { + closeResponse(response); + closeHttpClient(client); + + } + } + + private static void closeResponse(CloseableHttpResponse response) { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + System.out.println(String.format("failed to close client or response: %s", e.getMessage())); + } + } + + private static void closeHttpClient(CloseableHttpClient client) { + try { + if (client != null) { + client.close(); + } + } catch (IOException e) { + System.out.println(String.format("failed to close client or response: %s", e.getMessage())); + } + } + + private static File getTestZipFile(String filepath, String filename) throws IOException { + Config config = Utils.getConfig(); + String sourceDir = config.getImportResourceTestsConfigDir(); + java.nio.file.Path filePath = FileSystems.getDefault().getPath(filepath + File.separator + filename); + return filePath.toFile(); + } + + protected static Map prepareHeadersMap(String userId) { + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), userId); + return headersMap; + } + + public static void createVfFromOnboarding(String userID, String zipFile, String filepath) { + VendorLicenseDetails vld = createVendorLicense(userID); + createVendorSoftwareProduct(zipFile, filepath, userID, vld); + + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.OPEN_MODAL_BUTTON.getValue()).click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.ONBOARDING_SEARCH.getValue()) + .sendKeys(vld.getVendorSoftwareProduct()); + + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.sleep(1000); + GeneralUIUtils.getWebElementWaitForClickable(vld.getVendorSoftwareProduct()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.IMPORT_ICON.getValue()).click(); + GeneralUIUtils.getWebElementWaitForClickable(DataTestIdEnum.LifeCyleChangeButtons.CREATE.getValue()).click(); + GeneralUIUtils.waitForLoader(300); + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ResourceUIUtils.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ResourceUIUtils.java new file mode 100644 index 0000000000..149912944e --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ResourceUIUtils.java @@ -0,0 +1,299 @@ +package org.openecomp.sdc.uici.tests.utilities; + +import static org.openecomp.sdc.common.datastructure.FunctionalInterfaces.retryMethodOnException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.Dashboard; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; + +public final class ResourceUIUtils { + public static final String RESOURCE_NAME_PREFIX = "ResourceCDTest-"; + protected static final boolean IS_BEFORE_TEST = true; + public static final String INITIAL_VERSION = "0.1"; + public static final String ICON_RESOURCE_NAME = "call_controll"; + protected static final String UPDATED_RESOURCE_ICON_NAME = "objectStorage"; + + private ResourceUIUtils() { + } + + public static void defineResourceName(String resourceName) { + + WebElement resourceNameTextbox = GeneralUIUtils.getDriver().findElement(By.name("componentName")); + resourceNameTextbox.clear(); + resourceNameTextbox.sendKeys(resourceName); + } + + public static void defineResourceCategory(String category, String datatestsid) { + + GeneralUIUtils.getSelectList(category, datatestsid); + } + + public static void importFileWithSendKeyBrowse(String FilePath, String FileName) throws Exception { + WebElement browsebutton = GeneralUIUtils.getWebElementWaitForVisible("browseButton"); + browsebutton.sendKeys(FilePath + FileName); + } + + public static void defineTagsList(ResourceReqDetails resource, String[] resourceTags) { + List taglist = new ArrayList(); + ; + WebElement resourceTagsTextbox = GeneralUIUtils.getWebElementWaitForVisible("i-sdc-tag-input"); + for (String tag : resourceTags) { + resourceTagsTextbox.clear(); + resourceTagsTextbox.sendKeys(tag); + resourceTagsTextbox.sendKeys(Keys.ENTER); + taglist.add(tag); + } + resource.setTags(taglist); + } + + public static void defineVendorRelease(String resourceVendorRelease) { + + WebElement resourceVendorReleaseTextbox = GeneralUIUtils.getWebElementWaitForVisible("vendorRelease"); + resourceVendorReleaseTextbox.clear(); + resourceVendorReleaseTextbox.sendKeys(resourceVendorRelease); + } + + public static void defineProjectCode(String projectCode) { + + WebElement resourceNameTextbox = GeneralUIUtils.getDriver().findElement(By.name("projectCode")); + resourceNameTextbox.clear(); + resourceNameTextbox.sendKeys(projectCode); + } + + public static void clickButton(String selectButton) { + + WebElement clickButton = GeneralUIUtils.getDriver() + .findElement(By.xpath("//*[@data-tests-id='" + selectButton + "']")); + clickButton.click(); + } + + public static WebElement Waitfunctionforbuttons(String element, int timeout) { + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), timeout); + return wait.until(ExpectedConditions.elementToBeClickable(By.xpath(element))); + } + + // coded by teddy + public static void fillGeneralInformationPage(ResourceReqDetails resource, User user) { + try { + resource.setContactId(user.getUserId()); + resource.setCreatorUserId(user.getUserId()); + resource.setCreatorFullName(user.getFullName()); + defineResourceName(resource.getName()); + defineResourceCategory(resource.getCategories().get(0).getSubcategories().get(0).getName(), + "selectGeneralCategory"); + GeneralUIUtils.defineDescription(resource.getDescription()); + GeneralUIUtils.defineVendorName(resource.getVendorName()); + defineVendorRelease(resource.getVendorRelease()); + defineTagsList(resource, new String[] { resource.getName() }); + GeneralUIUtils.defineUserId(resource.getCreatorUserId()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static ResourceReqDetails createResourceInUI(User user) { + ResourceReqDetails defineResourceDetails = defineResourceDetails(); + GeneralUIUtils.clickAddComponent(DataTestIdEnum.Dashboard.BUTTON_ADD_VF); + + GeneralUIUtils.waitForLoader(); + fillGeneralInformationPage(defineResourceDetails, user); + GeneralUIUtils.clickCreateButton(); + return defineResourceDetails; + + } + + @SuppressWarnings("deprecation") + private static void openImportWithFile(String filePath, String fileName, Dashboard elementType) { + Runnable openImportTask = () -> { + GeneralUIUtils.moveToHTMLElementByDataTestId(Dashboard.IMPORT_AREA.getValue()); + WebElement imoprtVFButton = GeneralUIUtils.getWebElementByDataTestId(elementType.getValue()); + imoprtVFButton.sendKeys(filePath + fileName); + }; + retryMethodOnException(openImportTask); + + } + + public static ResourceReqDetails importVfcInUI(User user, String filePath, String fileName) { + ResourceReqDetails defineResourceDetails = defineResourceDetails(); + openImportWithFile(filePath, fileName, DataTestIdEnum.Dashboard.IMPORT_VFC_FILE); + // Fill the general page fields. + GeneralUIUtils.waitForLoader(); + fillGeneralInformationPage(defineResourceDetails, user); + GeneralUIUtils.clickCreateButton(); + return defineResourceDetails; + } + + /** + * Import VF + * + * @param user + * @param filePath + * @param fileName + * @return + */ + public static ResourceReqDetails importVfInUI(User user, String filePath, String fileName) { + ResourceReqDetails defineResourceDetails = defineResourceDetails(); + openImportWithFile(filePath, fileName, DataTestIdEnum.Dashboard.IMPORT_VF_FILE); + // Fill the general page fields. + GeneralUIUtils.waitForLoader(); + fillGeneralInformationPage(defineResourceDetails, user); + + GeneralUIUtils.clickSaveButton(); + + return defineResourceDetails; + } + + public static ResourceReqDetails importVfInUIWithoutCheckin(User user, String filePath, String fileName) { + ResourceReqDetails defineResourceDetails = defineResourceDetails(); + openImportWithFile(filePath, fileName, DataTestIdEnum.Dashboard.IMPORT_VF_FILE); + // Fill the general page fields. + GeneralUIUtils.waitForLoader(); + fillGeneralInformationPage(defineResourceDetails, user); + GeneralUIUtils.clickSaveButton(); + GeneralUIUtils.waitForLoader(40); + // String okButtonId=DataTestIdEnum.ModalItems.OK.getValue(); + // ResourceUIUtils.clickButton(okButtonId); + // ResourceUIUtils.Waitfunctionforbuttons("//*[@data-tests-id='"+okButtonId+"']",10); + // ResourceUIUtils.clickButton(okButtonId); + return defineResourceDetails; + } + + public static ResourceReqDetails importVfFromOnBoardingModalWithoutCheckin(User user, String fileName) { + ResourceReqDetails defineResourceDetails = defineResourceDetails(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.OPEN_MODAL_BUTTON.getValue()).click(); + GeneralUIUtils.getWebElementWaitForVisible(fileName).click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.IMPORT_ICON.getValue()).click(); + + // Fill the general page fields. + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.clickSaveButton(); + GeneralUIUtils.waitForLoader(); + return defineResourceDetails; + } + + @SuppressWarnings("deprecation") + public static void updateVfCsar(String filePath, String fileName) { + retryMethodOnException( + () -> GeneralUIUtils.getWebElementByDataTestId(DataTestIdEnum.GeneralSection.BROWSE_BUTTON.getValue()) + .sendKeys(filePath + fileName)); + GeneralUIUtils.clickSaveButton(); + GeneralUIUtils.waitForLoader(); + } + + public static void updateVfCsarFromOnBoarding() { + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.GeneralSection.BROWSE_BUTTON.getValue()).click(); + GeneralUIUtils.getWebElementsListWaitForVisible(DataTestIdEnum.OnBoardingTable.CSAR_ROW.getValue()).get(0) + .click(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.OnBoardingTable.UPDATE_ICON.getValue()).click(); + GeneralUIUtils.clickSaveButton(); + GeneralUIUtils.waitForLoader(); + } + + public static ResourceReqDetails defineResourceDetails() { + ResourceReqDetails resource = new ResourceReqDetails(); + resource = ElementFactory.getDefaultResource(NormativeTypesEnum.ROOT, + ResourceCategoryEnum.GENERIC_NETWORK_ELEMENTS); + resource.setVersion(INITIAL_VERSION); + resource.setIcon(ICON_RESOURCE_NAME); + resource.setResourceType(ResourceTypeEnum.VF.toString()); + resource.setName(getRandomComponentName(RESOURCE_NAME_PREFIX)); + + return resource; + } + + protected static String getRandomComponentName(String prefix) { + return prefix + new Random().nextInt(10000); + } + + public static ImmutablePair getRIPosition(ResourceReqDetails createResourceInUI, User user) { + GeneralUIUtils.sleep(1000); + String responseAfterDrag = RestCDUtils.getResource(createResourceInUI).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + String xPosPostDrag = (String) ((JSONObject) ((JSONArray) jsonResource.get("componentInstances")).get(0)) + .get("posX"); + String yPosPostDrag = (String) ((JSONObject) ((JSONArray) jsonResource.get("componentInstances")).get(0)) + .get("posY"); + return new ImmutablePair(xPosPostDrag, yPosPostDrag); + + } + + public static void fillinDeploymentArtifactFormAndClickDone( + org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails details, String filePath) { + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ArtifactModal.LABEL.getValue()) + .sendKeys(details.getArtifactLabel()); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.DESCRIPTION.getValue()) + .sendKeys(details.getDescription()); + GeneralUIUtils.getSelectList(details.getArtifactType(), DataTestIdEnum.ArtifactModal.TYPE.getValue()); + retryMethodOnException(() -> GeneralUIUtils + .getWebElementByDataTestId(DataTestIdEnum.GeneralSection.BROWSE_BUTTON.getValue()).sendKeys(filePath)); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.DONE.getValue()).click(); + GeneralUIUtils.waitForLoader(); + } + + /** + * Tests and Accept resource or service + * + * @param createResourceInUI + */ + public static void testAndAcceptElement(ComponentReqDetails createResourceInUI) { + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(createResourceInUI.getName()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.LifeCyleChangeButtons.START_TESTING.getValue()) + .click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.LifeCyleChangeButtons.ACCEPT.getValue()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.ACCEP_TESTING_MESSAGE.getValue()) + .sendKeys("resource " + createResourceInUI.getName() + " tested successfuly"); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.OK.getValue()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.waitForElementToDisappear(DataTestIdEnum.ModalItems.OK.getValue()); + } + + /** + * Waits Until resource changed to requested lifeCycle State + * + * @param createResourceInUI + * @param requestedLifeCycleState + * @return + */ + public static Resource waitForState(ResourceReqDetails createResourceInUI, + LifecycleStateEnum requestedLifeCycleState) { + Supplier resourceGetter = () -> { + String resourceString = RestCDUtils.getResource(createResourceInUI).getResponse(); + return ResponseParser.convertResourceResponseToJavaObject(resourceString); + }; + Function verifier = res -> res.getLifecycleState() == requestedLifeCycleState; + return FunctionalInterfaces.retryMethodOnResult(resourceGetter, verifier); + + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/RestCDUtils.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/RestCDUtils.java new file mode 100644 index 0000000000..8b602e305d --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/RestCDUtils.java @@ -0,0 +1,167 @@ +package org.openecomp.sdc.uici.tests.utilities; + +import static org.openecomp.sdc.common.datastructure.FunctionalInterfaces.retryMethodOnResult; +import static org.openecomp.sdc.common.datastructure.FunctionalInterfaces.swallowException; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.apache.http.HttpStatus; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONObject; + +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; + +public class RestCDUtils { + + private static void setResourceUniqueIdAndUUID(ComponentReqDetails element, RestResponse getResourceResponse) { + element.setUniqueId(ResponseParser.getUniqueIdFromResponse(getResourceResponse)); + element.setUUID(ResponseParser.getUuidFromResponse(getResourceResponse)); + } + + public static RestResponse getResourceByNameAndVersionRetryOnFail(String userId, String resourceName, + String resourceVersion) { + Supplier resourceGetter = () -> swallowException( + () -> ResourceRestUtils.getResourceByNameAndVersion(userId, resourceName, resourceVersion)); + Function validator = restRes -> restRes.getErrorCode() == HttpStatus.SC_OK; + return retryMethodOnResult(resourceGetter, validator); + } + + public static RestResponse getResource(ResourceReqDetails resource) { + try { + System.out.println("trying to get resource"); + RestResponse getResourceResponse = null; + String reourceUniqueId = resource.getUniqueId(); + + if (reourceUniqueId != null) { + GeneralUIUtils.sleep(1000); + getResourceResponse = ResourceRestUtils.getResource(reourceUniqueId); + if (getResourceResponse.getErrorCode().intValue() == HttpStatus.SC_OK) { + System.out.println("succeeded to get resource"); + } + return getResourceResponse; + } + JSONObject getResourceJSONObject = null; + getResourceResponse = getResourceByNameAndVersionRetryOnFail(UserRoleEnum.ADMIN.getUserId(), + resource.getName(), resource.getVersion()); + if (getResourceResponse.getErrorCode().intValue() == HttpStatus.SC_OK) { + JSONArray jArray = new JSONArray(getResourceResponse.getResponse()); + for (int i = 0; i < jArray.length(); i++) { + getResourceJSONObject = jArray.getJSONObject(i); + String resourceType = ResponseParser.getValueFromJsonResponse(getResourceJSONObject.toString(), + "resourceType"); + if (resourceType.equals(resource.getResourceType())) { + getResourceResponse.setResponse(getResourceJSONObject.toString()); + setResourceUniqueIdAndUUID(resource, getResourceResponse); + System.out.println("succeeded to get resource"); + return getResourceResponse; + } + } + } + + return getResourceResponse; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static RestResponse getService(ServiceReqDetails service, User user) { + Supplier serviceFetcher = () -> swallowException( + () -> ServiceRestUtils.getServiceByNameAndVersion(user, service.getName(), service.getVersion())); + Function verifier = restResponse -> restResponse.getErrorCode() + .intValue() == HttpStatus.SC_OK; + RestResponse getServiceResponse = retryMethodOnResult(serviceFetcher, verifier); + + if (getServiceResponse.getErrorCode().intValue() == HttpStatus.SC_OK) { + setResourceUniqueIdAndUUID(service, getServiceResponse); + } + return getServiceResponse; + } + + public static RestResponse getProduct(ProductReqDetails product, User user) throws Exception { + Thread.sleep(3500); + RestResponse getProductResponse = ProductRestUtils.getProductByNameAndVersion(product.getName(), + product.getVersion(), user.getUserId()); + if (getProductResponse.getErrorCode().intValue() == 200) { + setResourceUniqueIdAndUUID(product, getProductResponse); + } + return getProductResponse; + } + + public static Map getAllElementVersionsFromResponse(RestResponse getResource) throws Exception { + Map versionsMap = new HashMap(); + try { + ObjectMapper mapper = new ObjectMapper(); + + JSONObject object = new JSONObject(getResource.getResponse()); + versionsMap = mapper.readValue(object.get("allVersions").toString(), Map.class); + + } catch (Exception e) { + e.printStackTrace(); + return versionsMap; + + } + + return versionsMap; + } + + public static void deleteElementVersions(Map elementVersions, boolean isBeforeTest, Object clazz, + User user) throws Exception { + Iterator iterator = elementVersions.keySet().iterator(); + while (iterator.hasNext()) { + String singleVersion = iterator.next(); + String uniqueId = elementVersions.get(singleVersion); + RestResponse deleteResponse = null; + if (clazz instanceof ServiceReqDetails) { + deleteResponse = ServiceRestUtils.deleteServiceById(uniqueId, user.getUserId()); + } else if (clazz instanceof ResourceReqDetails) { + deleteResponse = ResourceRestUtils.deleteResource(uniqueId, user.getUserId()); + } else if (clazz instanceof ProductReqDetails) { + deleteResponse = ProductRestUtils.deleteProduct(uniqueId, user.getUserId()); + } + + if (isBeforeTest) { + assertTrue(deleteResponse.getErrorCode().intValue() == 204 + || deleteResponse.getErrorCode().intValue() == 404); + } else { + assertTrue(deleteResponse.getErrorCode().intValue() == 204); + } + } + } + + public static void deleteAllResourceVersionsAfterTest(ComponentReqDetails componentDetails, + RestResponse getObjectResponse, User user) throws Exception { + deleteAllComponentVersion(false, componentDetails, getObjectResponse, user); + } + + public static void deleteAllResourceVersionsBeforeTest(ComponentReqDetails componentDetails, + RestResponse getObjectResponse, User user) throws Exception { + deleteAllComponentVersion(true, componentDetails, getObjectResponse, user); + } + + public static void deleteAllComponentVersion(boolean isBeforeTest, ComponentReqDetails componentDetails, + RestResponse getObjectResponse, User user) throws Exception { + if (getObjectResponse.getErrorCode().intValue() == 404) + return; + Map componentVersionsMap = getAllElementVersionsFromResponse(getObjectResponse); + System.out.println("deleting..."); + deleteElementVersions(componentVersionsMap, isBeforeTest, componentDetails, user); + componentDetails.setUniqueId(null); + } + +} \ No newline at end of file diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ServiceUIUtils.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ServiceUIUtils.java new file mode 100644 index 0000000000..0130b710a0 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/utilities/ServiceUIUtils.java @@ -0,0 +1,147 @@ +package org.openecomp.sdc.uici.tests.utilities; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.uici.tests.datatypes.DataTestIdEnum.GeneralSection; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Select; + +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; + +public final class ServiceUIUtils { + + public static final String SERVICE_NAME_PREFIX = "ServiceCDTest-"; + public static final String INITIAL_VERSION = "0.1"; + public static final String ICON_SERVICE_NAME = "mobility"; + + private ServiceUIUtils() { + throw new UnsupportedOperationException(); + } + + public static String defineServiceName(String serviceName) { + WebElement serviceNameElement = GeneralUIUtils.getWebElementWaitForVisible(GeneralSection.NAME.getValue()); + serviceNameElement.clear(); + serviceNameElement.sendKeys(serviceName); + return serviceName; + } + + public static void defineTagsList(ServiceReqDetails service, String[] serviceTags) { + List taglist = new ArrayList(); + ; + WebElement serviceTagsTextbox = GeneralUIUtils.getWebElementWaitForVisible("i-sdc-tag-input"); + for (String tag : serviceTags) { + serviceTagsTextbox.clear(); + serviceTagsTextbox.sendKeys(tag); + serviceTagsTextbox.sendKeys(Keys.ENTER); + taglist.add(tag); + } + taglist.add(0, service.getName()); + service.setTags(taglist); + } + + public static Select defineServiceCategory(String category) { + + return GeneralUIUtils.getSelectList(category, "selectGeneralCategory"); + } + + private static void defineServiceProjectCode(String projectCode) { + WebElement attProjectCodeTextbox = GeneralUIUtils.getWebElementWaitForVisible("projectCode"); + attProjectCodeTextbox.clear(); + attProjectCodeTextbox.sendKeys(projectCode); + } + + private static void fillServiceGeneralPage(ServiceReqDetails service, User user) { + service.setContactId(user.getUserId()); + service.setCreatorUserId(user.getUserId()); + service.setCreatorFullName(user.getFullName()); + defineServiceName(service.getName()); + defineServiceCategory(service.getCategories().get(0).getName()); + GeneralUIUtils.defineDescription(service.getDescription()); + defineTagsList(service, + new String[] { service.getName(), "This-is-tag", "another-tag", "Test-automation-tag" }); + GeneralUIUtils.defineUserId(service.getCreatorUserId()); + defineServiceProjectCode(service.getProjectCode()); + + } + + public static ServiceReqDetails createServiceInUI(User user) { + + ServiceReqDetails defineServiceetails = defineServiceDetails(user); + GeneralUIUtils.clickAddComponent(DataTestIdEnum.Dashboard.BUTTON_ADD_SERVICE); + + GeneralUIUtils.waitForLoader(); + fillServiceGeneralPage(defineServiceetails, user); + + GeneralUIUtils.clickCreateButton(); + + return defineServiceetails; + + } + + public static ServiceReqDetails defineServiceDetails(User user) { + ServiceReqDetails service = new ServiceReqDetails(); + service = ElementFactory.getDefaultService(ServiceCategoriesEnum.MOBILITY, user); + service.setVersion(INITIAL_VERSION); + service.setIcon(ICON_SERVICE_NAME); + service.setName(getRandomComponentName(SERVICE_NAME_PREFIX)); + + return service; + } + + protected static String getRandomComponentName(String prefix) { + return prefix + new Random().nextInt(10000); + } + + /** + * Waits Until service changed to requested lifeCycle State + * + * @param createServiceInUI + * @param requestedLifeCycleState + * @param user + * @return + */ + public static Service waitForState(ServiceReqDetails createServiceInUI, LifecycleStateEnum requestedLifeCycleState, + User user) { + Supplier serviceGetter = () -> { + String resourceString = RestCDUtils.getService(createServiceInUI, user).getResponse(); + return ResponseParser.convertServiceResponseToJavaObject(resourceString); + }; + Function verifier = res -> res.getLifecycleState() == requestedLifeCycleState; + return FunctionalInterfaces.retryMethodOnResult(serviceGetter, verifier); + + } + + /** + * This Method Approves service for distribution
+ * It assumes governor role is already logged in + * + * @param createServiceInUI + */ + public static void approveServiceForDistribution(ServiceReqDetails createServiceInUI) { + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(createServiceInUI.getName()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.LifeCyleChangeButtons.APPROVE.getValue()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.ACCEP_TESTING_MESSAGE.getValue()) + .sendKeys("Service " + createServiceInUI.getName() + " Approved For Distribution"); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementWaitForVisible(DataTestIdEnum.ModalItems.OK.getValue()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.waitForElementToDisappear(DataTestIdEnum.ModalItems.OK.getValue()); + } + +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/ServiceVerificator.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/ServiceVerificator.java new file mode 100644 index 0000000000..0306df0638 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/ServiceVerificator.java @@ -0,0 +1,55 @@ +package org.openecomp.sdc.uici.tests.verificator; + +import static org.testng.AssertJUnit.assertTrue; + +import java.util.function.Function; +import java.util.function.Supplier; + +import org.apache.http.HttpStatus; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.uici.tests.utilities.RestCDUtils; + +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; + +public class ServiceVerificator { + public static void verifyNumOfComponentInstances(ServiceReqDetails createServiceInUI, int numOfVFC, User user) { + String responseAfterDrag = RestCDUtils.getService(createServiceInUI, user).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + int size = ((JSONArray) jsonResource.get("componentInstances")).size(); + assertTrue(size == numOfVFC); + } + + public static void verifyLinkCreated(ServiceReqDetails createServiceInUI, User user) { + String responseAfterDrag = RestCDUtils.getService(createServiceInUI, user).getResponse(); + JSONObject jsonService = (JSONObject) JSONValue.parse(responseAfterDrag); + assertTrue(((JSONArray) jsonService.get("componentInstancesRelations")).size() == 1); + + } + + public static void verifyServiceCreated(ServiceReqDetails createServiceInUI, User user) { + assertTrue(RestCDUtils.getService(createServiceInUI, user).getErrorCode() == HttpStatus.SC_OK); + + } + + /** + * Verifies service is certified with version 1.0 + * + * @param createServiceInUI + * @param user + */ + public static void verifyServiceCertified(ServiceReqDetails createServiceInUI, User user) { + Supplier serviceGetter = () -> FunctionalInterfaces.swallowException( + () -> ServiceRestUtils.getServiceByNameAndVersion(user, createServiceInUI.getName(), "1.0")); + Function serviceVerificator = restResp -> restResp.getErrorCode() == HttpStatus.SC_OK; + RestResponse certifiedResourceResopnse = FunctionalInterfaces.retryMethodOnResult(serviceGetter, + serviceVerificator); + assertTrue(certifiedResourceResopnse.getErrorCode() == HttpStatus.SC_OK); + + } +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/VerificatorUtil.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/VerificatorUtil.java new file mode 100644 index 0000000000..9e983b44d3 --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/VerificatorUtil.java @@ -0,0 +1,27 @@ +package org.openecomp.sdc.uici.tests.verificator; + +import static org.testng.AssertJUnit.assertTrue; + +import java.util.function.Function; +import java.util.function.Supplier; + +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; + +/** + * Util Class For Verificators + * + * @author mshitrit + * + */ +public final class VerificatorUtil { + + private VerificatorUtil() { + throw new IllegalAccessError(); + } + + public static void verifyWithRetry(Supplier verificator) { + Function retryVerificationLogic = isVerified -> isVerified; + Boolean isVerifiedAfterRetries = FunctionalInterfaces.retryMethodOnResult(verificator, retryVerificationLogic); + assertTrue(isVerifiedAfterRetries); + } +} diff --git a/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/VfVerificator.java b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/VfVerificator.java new file mode 100644 index 0000000000..a1c7ca002b --- /dev/null +++ b/ui-ci-dev/src/main/java/org/openecomp/sdc/uici/tests/verificator/VfVerificator.java @@ -0,0 +1,143 @@ +package org.openecomp.sdc.uici.tests.verificator; + +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.http.HttpStatus; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.uici.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.uici.tests.utilities.RestCDUtils; + +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.datastructure.FunctionalInterfaces; + +/** + * Class to hold Test Verifications relevant for VF + * + * @author mshitrit + * + */ +public final class VfVerificator { + private VfVerificator() { + throw new UnsupportedOperationException(); + } + + /** + * Verifies that the resource contains a certain number of component + * instances + * + * @param createResourceInUI + * @param numOfVFC + */ + public static void verifyNumOfComponentInstances(ResourceReqDetails createResourceInUI, int numOfVFC) { + Supplier verificator = () -> { + String responseAfterDrag = RestCDUtils.getResource(createResourceInUI).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + int size = ((JSONArray) jsonResource.get("componentInstances")).size(); + return size == numOfVFC; + }; + VerificatorUtil.verifyWithRetry(verificator); + } + + /** + * Verifies That the createResourceInUI is different that prevRIPos. + * + * @param createResourceInUI + * @param prevRIPos + * @param user + */ + public static void verifyRILocationChanged(ResourceReqDetails createResourceInUI, + ImmutablePair prevRIPos, User user) { + Supplier verificator = () -> { + ImmutablePair currRIPos = ResourceUIUtils.getRIPosition(createResourceInUI, user); + final boolean isXLocationChanged = !prevRIPos.left.equals(currRIPos.left); + final boolean isYLocationChange = !prevRIPos.right.equals(currRIPos.right); + return isXLocationChanged || isYLocationChange; + }; + VerificatorUtil.verifyWithRetry(verificator); + } + + /** + * Verifies That resource contains two connected instances + * + * @param createResourceInUI + */ + public static void verifyLinkCreated(ResourceReqDetails createResourceInUI) { + Supplier verificator = () -> { + String responseAfterDrag = RestCDUtils.getResource(createResourceInUI).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + return ((JSONArray) jsonResource.get("componentInstancesRelations")).size() == 1; + }; + VerificatorUtil.verifyWithRetry(verificator); + + } + + /** + * Verifies That the VF is certified to version 1.0 + * + * @param vfToVerify + */ + public static void verifyResourceIsCertified(ResourceReqDetails vfToVerify) { + RestResponse certifiedResourceResopnse = RestCDUtils + .getResourceByNameAndVersionRetryOnFail(UserRoleEnum.ADMIN.getUserId(), vfToVerify.getName(), "1.0"); + assertTrue(certifiedResourceResopnse.getErrorCode().equals(HttpStatus.SC_OK)); + + } + + /** + * Verifies That the VF exist + * + * @param vfToVerify + */ + public static void verifyResourceIsCreated(ResourceReqDetails vfToVerify) { + assertTrue(RestCDUtils.getResource(vfToVerify).getErrorCode() == HttpStatus.SC_OK); + } + + /** + * Verify the resource contains the deployment artifacts in the list + * + * @param vfToVerify + * @param artifactTypeEnums + */ + public static void verifyResourceContainsDeploymentArtifacts(ResourceReqDetails vfToVerify, + List artifactTypeEnums) { + String resourceString = RestCDUtils.getResource(vfToVerify).getResponse(); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(resourceString); + List foundArtifacts = new ArrayList<>(); + if (resource.getDeploymentArtifacts() != null) { + foundArtifacts = resource.getDeploymentArtifacts().values().stream() + .map(artifact -> artifact.getArtifactType()).collect(Collectors.toList()); + } + List excpectedArtifacts = artifactTypeEnums.stream().map(e -> e.getType()).collect(Collectors.toList()); + assertTrue(foundArtifacts.containsAll(excpectedArtifacts)); + + } + + /** + * Verifies The life cycle State of the resource + * + * @param createResourceInUI + * @param requestedLifeCycleState + */ + public static void verifyState(ResourceReqDetails createResourceInUI, LifecycleStateEnum requestedLifeCycleState) { + Resource resource = ResourceUIUtils.waitForState(createResourceInUI, requestedLifeCycleState); + assertTrue(resource.getLifecycleState() == requestedLifeCycleState); + + } + +} diff --git a/ui-ci-dev/src/main/resources/ci/conf/attsdc-packages.yaml b/ui-ci-dev/src/main/resources/ci/conf/attsdc-packages.yaml new file mode 100644 index 0000000000..dcb78eefc1 --- /dev/null +++ b/ui-ci-dev/src/main/resources/ci/conf/attsdc-packages.yaml @@ -0,0 +1,2 @@ +packages: + - org.openecomp.sdc.ci.tests.execute.resourceui \ No newline at end of file diff --git a/ui-ci-dev/src/main/resources/ci/conf/attsdc.yaml b/ui-ci-dev/src/main/resources/ci/conf/attsdc.yaml new file mode 100644 index 0000000000..8cd8068d08 --- /dev/null +++ b/ui-ci-dev/src/main/resources/ci/conf/attsdc.yaml @@ -0,0 +1,80 @@ +outputFolder: target +reportName: index.html +catalogBeHost: behost +catalogFeHost: fehost +esHost: eshost +disributionClientHost: disClient +catalogFePort: 8181 +catalogBePort: 8080 +disributionClientPort: 8181 +esPort: 9200 +neoHost: neoHost +neoPort: 7474 +neoDBusername: neo4j +neoDBpassword: 123456 +url: http://localhost:8181/sdc1/proxy-designer1#/dashboard +webSealSimulatorUrl: http://localhost:8285/sdc1 +remoteTestingMachineIP: localhost +remoteTestingMachinePort: 5555 +remoteTesting: false + +resourceConfigDir: src/test/resources/CI/tests +componentsConfigDir: src/test/resources/CI/components +importResourceConfigDir: ../catalog-be/src/main/resources/import/tosca/capability-types +importResourceTestsConfigDir: src/test/resources/CI/importResourceTests +errorConfigurationFile: ../catalog-be/src/main/resources/config/error-configuration.yaml +configurationFile: ../catalog-be/src/main/resources/config/configuration.yaml +importTypesConfigDir: src/test/resources/CI/importTypesTest + + +titanPropertiesFile: src/main/resources/ci/conf/titan.properties +cassandraHost: 127.0.0.1 +cassandraAuthenticate: false +cassandraUsername: koko +cassandraPassword: bobo +cassandraSsl: false +cassandraTruststorePath : /path/path +cassandraTruststorePassword : 123123 +cassandraAuditKeySpace: sdcaudit +cassandraArtifactKeySpace: sdcartifact + +stopOnClassFailure: false + +#List of non-abstract resources to keep during titan cleanup between tests +#Only 1.0 version will be kept +resourcesNotToDelete: + - Compute + - Database + - ObjectStorage + - BlockStorage + - LoadBalancer + - Port + - Network + - Root + - ContainerApplication + - ContainerRuntime + - DBMS + - SoftwareComponent + - WebApplication + - WebServer + - CinderVolume + - ContrailVirtualNetwork + - NeutronNet + - NeutronPort + - NovaServer +#Resource categories to keep (including all their subcategories) +resourceCategoriesNotToDelete: + - Generic + - Network L2-3 + - Network L4+ + - Application L4+ + - Network Connectivity + - Template + - Allotted Resource + +#Service categories to keep +serviceCategoriesNotToDelete: + - Mobility + - Network L1-3 + - Network L4 + - VoIP Call Control \ No newline at end of file diff --git a/ui-ci-dev/src/main/resources/ci/conf/credentials.yaml b/ui-ci-dev/src/main/resources/ci/conf/credentials.yaml new file mode 100644 index 0000000000..63a4280264 --- /dev/null +++ b/ui-ci-dev/src/main/resources/ci/conf/credentials.yaml @@ -0,0 +1,48 @@ + designer: { + username: m99121, + password: 66-Percent, + firstname: ASDC, + lastname: KASPIN + } + admin: { + username: m99122, + password: 98-Degrees, + firstname: ASDC, + lastname: KASPIN + } + ops: { + username: m99123, + password: 17-Diameter, + firstname: ASDC, + lastname: KASPIN + } + tester: { + username: m99124, + password: 802-NotaGroup, + firstname: ASDC, + lastname: KASPIN + } + governor: { + username: m99125, + password: 142-Officiant, + firstname: ASDC, + lastname: KASPIN + } + product_strategist: { + username: m99126, + password: 1910-FruitGum, + firstname: ASDC, + lastname: KASPIN + } + product_manager: { + username: m99127, + password: 747-Airplane, + firstname: ASDC, + lastname: KASPIN + } + product_local: { + username: pm0001, + password: 123123a, + firstname: ASDC, + lastname: KASPIN + } \ No newline at end of file diff --git a/ui-ci-dev/src/main/resources/ci/conf/log4j.properties b/ui-ci-dev/src/main/resources/ci/conf/log4j.properties new file mode 100644 index 0000000000..3e159ec8df --- /dev/null +++ b/ui-ci-dev/src/main/resources/ci/conf/log4j.properties @@ -0,0 +1,34 @@ +# Define the root logger with appender file +log4j.rootLogger = DEBUG, FILE, stdout + +# Define the file appender +log4j.appender.FILE=org.apache.log4j.RollingFileAppender +log4j.appender.FILE.File=${targetlog}logs/ci-log.out + +# Define the layout for file appender +log4j.appender.FILE.layout=org.apache.log4j.PatternLayout +log4j.appender.FILE.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p [%10c] : %m%n + +# Set the maximum file size before rollover +log4j.appender.FILE.maxFileSize=5MB + +# Set the the backup index +log4j.appender.FILE.maxBackupIndex=10 + + +############################################################# + +# Direct log messages to stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %10c:%L - %m%n + +log4j.logger.org.apache.cassandra.service.StorageProxy=DEBUG +log4j.logger.com.thinkaurelius.titan.diskstorage.cassandra.CassandraTransaction=INFO, FILE, stdout + +log4j.logger.org.openecomp.sdc.ci.tests.utils=TRACE, FILE, stdout +log4j.additivity.org.openecomp.sdc.ci.tests.utils=false + + diff --git a/ui-ci-dev/src/main/resources/ci/conf/titan.properties b/ui-ci-dev/src/main/resources/ci/conf/titan.properties new file mode 100644 index 0000000000..94d12cfba0 --- /dev/null +++ b/ui-ci-dev/src/main/resources/ci/conf/titan.properties @@ -0,0 +1,7 @@ +storage.backend=cassandra +storage.hostname=cassandrahost +storage.port=9160 + +cache.db-cache-clean-wait = 20 +cache.db-cache-time = 180000 +cache.db-cache-size = 0.5 \ No newline at end of file diff --git a/ui-ci-dev/src/main/resources/ci/scripts/startTest.sh b/ui-ci-dev/src/main/resources/ci/scripts/startTest.sh new file mode 100644 index 0000000000..cc58bc22c5 --- /dev/null +++ b/ui-ci-dev/src/main/resources/ci/scripts/startTest.sh @@ -0,0 +1,123 @@ +#!/bin/bash + +TOMCAT_DIR=/home/apache-tomcat-7.0.41/webapps/sdc-ci + +function usage { + echo "Usage: $0 " +} + +function exitOnError() { + if [ $1 -ne 0 ] + then + echo "Failed running task $2" + exit 2 + fi +} + +if [ $# -lt 1 ] +then + usage + exit 2 +fi + +CURRENT_DIR=`pwd` +BASEDIR=$(dirname $0) + +if [ ${BASEDIR:0:1} = "/" ] +then + FULL_PATH=$BASEDIR +else + FULL_PATH=$CURRENT_DIR/$BASEDIR +fi + +LOGS_PROP_FILE=file:${FULL_PATH}/../conf/log4j.properties +############################################# +TARGET_DIR=${FULL_PATH}/../target +TARGET_LOG_DIR="${TARGET_DIR}/" +CONF_FILE=${FULL_PATH}/../conf/attsdc.yaml +DEBUG=true +MainClass=org.openecomp.sdc.ci.tests.run.StartTest + +JAR_FILE=$1 + +#TARGET_DIR=`echo ${TARGET_DIR} | sed 's/\//\//g'` +#echo $TARGET_DIR + +TESTS_DIR=/opt/app/sdc/ci/resources/tests +COMPONENTS_DIR=/opt/app/sdc/ci/resources/components + + +sed -i 's#\(outputFolder:\).*#\1 '${TARGET_DIR}'#g' $CONF_FILE +sed -i 's#\(resourceConfigDir:\).*#\1 '${TESTS_DIR}'#g' $CONF_FILE +sed -i 's#\(componentsConfigDir:\).*#\1 '${COMPONENTS_DIR}'#g' $CONF_FILE + + + +mkdir -p ${TARGET_DIR} +if [ -d ${TARGET_DIR} ] +then + rm -rf ${TARGET_DIR}/* + exitOnError $? "Failed_to_delete_target_dir" +fi + + +debug_port=8800 +#JAVA_OPTION="-javaagent:/var/tmp/jacoco/lib/jacocoagent.jar=destfile=jacoco-it.exec" +JAVA_OPTION="" +case "$2" in + -debug) echo "Debug mode, Listen on port $debug_port"; JAVA_OPTION="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${debug_port}" ;; + "") echo "Standard mode";; + *) echo "USAGE: startTest.sh [-debug]";; +esac + +#cmd="java $JAVA_OPTION -Dconfig.resource=attodlit.conf -Dlog4j.configuration=file:./conf/log4j.properties -cp #att-odl-it_0.0.1-SNAPSHOT-jar-with-dependencies.jar org.openecomp.d2.it.StartTest" + +#cmd="java $JAVA_OPTION -Dconfig.resource=attsdc.conf -Ddebug=true -Dlog4j.configuration=file:./conf/log4j.properties -cp uber-ci-1.0.0-SNAPSHOT.jar org.openecomp.sdc.ci.tests.run.StartTest" + + +cmd="java $JAVA_OPTION -DdisplayException=true -Dtargetlog=${TARGET_LOG_DIR} -Dconfig.resource=${CONF_FILE} -Ddebug=${DEBUG} -Dlog4j.configuration=${LOGS_PROP_FILE} -cp $JAR_FILE ${MainClass}" + +#echo $cmd +#console=`$cmd` + + + +if [ $DEBUG == "true" ] +then + $cmd +else + $cmd >> /dev/null +fi +status=`echo $?` + +#echo "console=$console" +#echo "status=$status" +#tomcat=`ps -ef | grep tomcat | grep java | wc -l` + +#if [ $tomcat == 0 ]; then +# echo "Bring tomcat up" +# apache-tomcat-7.0.41/bin/startup.sh +#fi + +#`rm -rf ./html/*.html` +#`mv *.html ./html/` + + +if [ -d ${TOMCAT_DIR} ] +then + + cp ${TARGET_DIR}/*.html ${TOMCAT_DIR} + mv ${TOMCAT_DIR}/SDC-testReport.html ${TOMCAT_DIR}/index.html +fi + +#echo "tomcat=$tomcat" +#ip=`ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p' | grep 172.20` + +#echo "Report url: http://$ip:8090/att-odl-it/" + +echo "##################################################" +echo "################# status is $status " +echo "##################################################" + +exit $status + diff --git a/ui-ci-dev/src/main/resources/ci/testSuites/fullTests.xml b/ui-ci-dev/src/main/resources/ci/testSuites/fullTests.xml new file mode 100644 index 0000000000..9f912e58b8 --- /dev/null +++ b/ui-ci-dev/src/main/resources/ci/testSuites/fullTests.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ci-dev/src/main/resources/ci/testSuites/sanity.xml b/ui-ci-dev/src/main/resources/ci/testSuites/sanity.xml new file mode 100644 index 0000000000..99e8765038 --- /dev/null +++ b/ui-ci-dev/src/main/resources/ci/testSuites/sanity.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ci-dev/src/main/resources/images/gizmorambo.jpg b/ui-ci-dev/src/main/resources/images/gizmorambo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c9a8fe8a646eadd42bdf645449a5bef231a25e1e GIT binary patch literal 16605 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 literal 0 HcmV?d00001 diff --git a/ui-ci-dev/src/test/Completetheform.js b/ui-ci-dev/src/test/Completetheform.js new file mode 100644 index 0000000000..7e8b7572cc --- /dev/null +++ b/ui-ci-dev/src/test/Completetheform.js @@ -0,0 +1,3 @@ +/** + * New node file + */ diff --git a/ui-ci/.gitignore b/ui-ci/.gitignore new file mode 100644 index 0000000000..6405eb7c05 --- /dev/null +++ b/ui-ci/.gitignore @@ -0,0 +1,2 @@ +/bin/ +test-output/ \ No newline at end of file diff --git a/ui-ci/hs_err_pid10052.log b/ui-ci/hs_err_pid10052.log new file mode 100644 index 0000000000..3475f9250a --- /dev/null +++ b/ui-ci/hs_err_pid10052.log @@ -0,0 +1,389 @@ +# +# A fatal error has been detected by the Java Runtime Environment: +# +# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006f70a0a5, pid=10052, tid=0x0000000000001f50 +# +# JRE version: Java(TM) SE Runtime Environment (8.0_101-b13) (build 1.8.0_101-b13) +# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.101-b13 mixed mode windows-amd64 compressed oops) +# Problematic frame: +# V [jvm.dll+0x12a0a5] +# +# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows +# +# If you would like to submit a bug report, please visit: +# http://bugreport.java.com/bugreport/crash.jsp +# + +--------------- T H R E A D --------------- + +Current thread (0x000000001d458800): JavaThread "JDWP Transport Listener: dt_socket" daemon [_thread_in_vm, id=8016, stack(0x000000001e150000,0x000000001e250000)] + +siginfo: ExceptionCode=0xc0000005, reading address 0xffffffffffffffff + +Registers: +RAX=0x000000001e24f201, RBX=0x000000001d458800, RCX=0x293b676e69727453, RDX=0x0000000000000000 +RSP=0x000000001e24f290, RBP=0x293b676e69727453, RSI=0x000000001e24f3a8, RDI=0x000000000237c720 +R8 =0x000000001d458800, R9 =0x000000000000ff00, R10=0x0000000000000000, R11=0x004e596502bc0041 +R12=0x0000000000000000, R13=0x000000001d451788, R14=0x0000000000000000, R15=0x0000000000000000 +RIP=0x000000006f70a0a5, EFLAGS=0x0000000000010206 + +Top of Stack: (sp=0x000000001e24f290) +0x000000001e24f290: 000000001d458800 000000001fbdbe40 +0x000000001e24f2a0: 000000001e24f358 000000006f912f0b +0x000000001e24f2b0: 000000001d458800 000000006f92f76d +0x000000001e24f2c0: 0000000000000000 0000000055559155 +0x000000001e24f2d0: 000000001f30efd8 000000005556291e +0x000000001e24f2e0: 000000001d458800 0000000000000000 +0x000000001e24f2f0: 0000000000000000 0000000000000000 +0x000000001e24f300: 293b676e69727453 0000000055561a15 +0x000000001e24f310: 000000001e24f3a8 000000001e24f380 +0x000000001e24f320: 0000000000000001 000000001f30efd8 +0x000000001e24f330: 293b676e69727453 00000000555453b3 +0x000000001e24f340: 000000001e24f470 0000000000000001 +0x000000001e24f350: 0000000000000001 000000001f30efd8 +0x000000001e24f360: 00000000f000100a 0000000000000000 +0x000000001e24f370: 0000000000000000 0000000000000000 +0x000000001e24f380: 0000000000000001 0000000055545571 + +Instructions: (pc=0x000000006f70a0a5) +0x000000006f70a085: cc cc cc cc cc cc cc cc cc cc cc 48 83 ec 28 48 +0x000000006f70a095: 85 c9 75 07 33 c0 48 83 c4 28 c3 48 89 5c 24 20 +0x000000006f70a0a5: 48 8b 19 48 85 db 74 20 48 83 fb 37 74 1a 48 8b +0x000000006f70a0b5: 13 48 8b cb ff 52 10 84 c0 74 0d 48 8b c3 48 8b + + +Register to memory mapping: + +RAX=0x000000001e24f201 is pointing into the stack for thread: 0x000000001d458800 +RBX=0x000000001d458800 is a thread +RCX=0x293b676e69727453 is an unknown value +RDX=0x0000000000000000 is an unknown value +RSP=0x000000001e24f290 is pointing into the stack for thread: 0x000000001d458800 +RBP=0x293b676e69727453 is an unknown value +RSI=0x000000001e24f3a8 is pointing into the stack for thread: 0x000000001d458800 +RDI=0x000000000237c720 is an unknown value +R8 =0x000000001d458800 is a thread +R9 =0x000000000000ff00 is an unknown value +R10=0x0000000000000000 is an unknown value +R11=0x004e596502bc0041 is an unknown value +R12=0x0000000000000000 is an unknown value +R13=0x000000001d451788 is an unknown value +R14=0x0000000000000000 is an unknown value +R15=0x0000000000000000 is an unknown value + + +Stack: [0x000000001e150000,0x000000001e250000], sp=0x000000001e24f290, free space=1020k +Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) +V [jvm.dll+0x12a0a5] +V [jvm.dll+0x34f76d] +C [jdwp.dll+0x21a15] +C [jdwp.dll+0x53b3] +C [jdwp.dll+0x5571] +C [jdwp.dll+0xf0a8] +C [jdwp.dll+0x1f2d5] +C [jdwp.dll+0x1f4aa] +V [jvm.dll+0x1bd258] +V [jvm.dll+0x2451a4] +V [jvm.dll+0x29c18a] +C [msvcr100.dll+0x21d9f] +C [msvcr100.dll+0x21e3b] +C [kernel32.dll+0x159cd] +C [ntdll.dll+0x2a2e1] + + +--------------- P R O C E S S --------------- + +Java Threads: ( => current thread ) + 0x000000001f2a0000 JavaThread "Thread-25" daemon [_thread_in_native, id=11400, stack(0x0000000024be0000,0x0000000024ce0000)] + 0x000000001f29f000 JavaThread "Thread-24" daemon [_thread_in_native, id=1112, stack(0x00000000243d0000,0x00000000244d0000)] + 0x000000001f29e800 JavaThread "Thread-23" [_thread_in_native, id=2452, stack(0x0000000022cc0000,0x0000000022dc0000)] + 0x000000001f93d000 JavaThread "ReaderThread" [_thread_in_native, id=11720, stack(0x0000000021250000,0x0000000021350000)] + 0x000000001d4e8800 JavaThread "Service Thread" daemon [_thread_blocked, id=10596, stack(0x000000001e6f0000,0x000000001e7f0000)] + 0x000000001d474800 JavaThread "C1 CompilerThread2" daemon [_thread_blocked, id=8028, stack(0x000000001e3d0000,0x000000001e4d0000)] + 0x000000001d471000 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=5140, stack(0x000000001e4f0000,0x000000001e5f0000)] + 0x000000001d46d000 JavaThread "C2 CompilerThread0" daemon [_thread_blocked, id=12216, stack(0x000000001dd90000,0x000000001de90000)] + 0x000000001d45f800 JavaThread "JDWP Command Reader" daemon [_thread_in_native, id=7520, stack(0x000000001e2d0000,0x000000001e3d0000)] + 0x000000001d45e000 JavaThread "JDWP Event Helper Thread" daemon [_thread_blocked, id=2652, stack(0x000000001df60000,0x000000001e060000)] +=>0x000000001d458800 JavaThread "JDWP Transport Listener: dt_socket" daemon [_thread_in_vm, id=8016, stack(0x000000001e150000,0x000000001e250000)] + 0x000000001d444800 JavaThread "Attach Listener" daemon [_thread_blocked, id=7364, stack(0x000000001d200000,0x000000001d300000)] + 0x000000001bfff000 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=9460, stack(0x000000001d850000,0x000000001d950000)] + 0x000000001bfe6800 JavaThread "Finalizer" daemon [_thread_blocked, id=7944, stack(0x000000001d340000,0x000000001d440000)] + 0x000000001bf9d000 JavaThread "Reference Handler" daemon [_thread_blocked, id=6028, stack(0x000000001d080000,0x000000001d180000)] + 0x0000000002381000 JavaThread "main" [_thread_blocked, id=12148, stack(0x0000000002480000,0x0000000002580000)] + +Other Threads: + 0x000000001bf95800 VMThread [stack: 0x000000001cf80000,0x000000001d080000] [id=8456] + 0x000000001d537000 WatcherThread [stack: 0x000000001e840000,0x000000001e940000] [id=5808] + +VM state:not at safepoint (normal execution) + +VM Mutex/Monitor currently owned by a thread: None + +Heap: + PSYoungGen total 144896K, used 11229K [0x000000076c700000, 0x0000000776d80000, 0x00000007c0000000) + eden space 143360K, 6% used [0x000000076c700000,0x000000076d087050,0x0000000775300000) + from space 1536K, 95% used [0x0000000775d00000,0x0000000775e70540,0x0000000775e80000) + to space 9216K, 0% used [0x0000000776480000,0x0000000776480000,0x0000000776d80000) + ParOldGen total 93184K, used 6916K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5ac1178,0x00000006caf00000) + Metaspace used 26524K, capacity 27092K, committed 27264K, reserved 1073152K + class space used 3209K, capacity 3367K, committed 3456K, reserved 1048576K + +Card table byte_map: [0x0000000011cf0000,0x00000000124d0000] byte_map_base: 0x000000000e6c6000 + +Marking Bits: (ParMarkBitMap*) 0x000000006fdfa6d0 + Begin Bits: [0x00000000130c0000, 0x0000000016f70000) + End Bits: [0x0000000016f70000, 0x000000001ae20000) + +Polling page: 0x0000000000370000 + +CodeCache: size=245760Kb used=14912Kb max_used=14912Kb free=230848Kb + bounds [0x0000000002930000, 0x00000000037d0000, 0x0000000011930000] + total_blobs=4013 nmethods=3595 adapters=338 + compilation: enabled + +Compilation events (10 events): +Event: 131.300 Thread 0x000000001d474800 4189 ! 3 com.google.gson.JsonParser::parse (100 bytes) +Event: 131.302 Thread 0x000000001d474800 nmethod 4189 0x00000000037cce10 code [0x00000000037cd120, 0x00000000037ceb08] +Event: 131.303 Thread 0x000000001d474800 4190 ! 3 com.google.gson.internal.Streams::parse (68 bytes) +Event: 131.304 Thread 0x000000001d474800 nmethod 4190 0x00000000037a77d0 code [0x00000000037a79e0, 0x00000000037a81d8] +Event: 131.304 Thread 0x000000001d474800 4191 3 com.google.gson.internal.bind.TypeAdapters$25::read (6 bytes) +Event: 131.304 Thread 0x000000001d474800 nmethod 4191 0x00000000037a7390 code [0x00000000037a7500, 0x00000000037a7728] +Event: 131.313 Thread 0x000000001d474800 4192 1 java.lang.StackTraceElement::getClassName (5 bytes) +Event: 131.313 Thread 0x000000001d474800 nmethod 4192 0x00000000037a4c90 code [0x00000000037a4de0, 0x00000000037a4ef0] +Event: 131.313 Thread 0x000000001d474800 4193 ! 3 sun.nio.cs.StreamEncoder::flushBuffer (42 bytes) +Event: 131.313 Thread 0x000000001d474800 nmethod 4193 0x00000000037a6910 code [0x00000000037a6ac0, 0x00000000037a7098] + +GC Heap History (10 events): +Event: 98.293 GC heap before +{Heap before GC invocations=12 (full 1): + PSYoungGen total 169472K, used 169111K [0x000000076c700000, 0x0000000778200000, 0x00000007c0000000) + eden space 167424K, 100% used [0x000000076c700000,0x0000000776a80000,0x0000000776a80000) + from space 2048K, 82% used [0x0000000778000000,0x00000007781a5ff0,0x0000000778200000) + to space 10752K, 0% used [0x0000000776d00000,0x0000000776d00000,0x0000000777780000) + ParOldGen total 93184K, used 6900K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5abd178,0x00000006caf00000) + Metaspace used 26364K, capacity 26900K, committed 27008K, reserved 1073152K + class space used 3204K, capacity 3367K, committed 3456K, reserved 1048576K +Event: 98.299 GC heap after +Heap after GC invocations=12 (full 1): + PSYoungGen total 164352K, used 1859K [0x000000076c700000, 0x0000000778080000, 0x00000007c0000000) + eden space 162304K, 0% used [0x000000076c700000,0x000000076c700000,0x0000000776580000) + from space 2048K, 90% used [0x0000000776d00000,0x0000000776ed0fe0,0x0000000776f00000) + to space 10752K, 0% used [0x0000000777600000,0x0000000777600000,0x0000000778080000) + ParOldGen total 93184K, used 6900K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5abd178,0x00000006caf00000) + Metaspace used 26364K, capacity 26900K, committed 27008K, reserved 1073152K + class space used 3204K, capacity 3367K, committed 3456K, reserved 1048576K +} +Event: 112.449 GC heap before +{Heap before GC invocations=13 (full 1): + PSYoungGen total 164352K, used 164163K [0x000000076c700000, 0x0000000778080000, 0x00000007c0000000) + eden space 162304K, 100% used [0x000000076c700000,0x0000000776580000,0x0000000776580000) + from space 2048K, 90% used [0x0000000776d00000,0x0000000776ed0fe0,0x0000000776f00000) + to space 10752K, 0% used [0x0000000777600000,0x0000000777600000,0x0000000778080000) + ParOldGen total 93184K, used 6900K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5abd178,0x00000006caf00000) + Metaspace used 26410K, capacity 26964K, committed 27264K, reserved 1073152K + class space used 3204K, capacity 3367K, committed 3456K, reserved 1048576K +Event: 112.470 GC heap after +Heap after GC invocations=13 (full 1): + PSYoungGen total 158720K, used 1461K [0x000000076c700000, 0x0000000777780000, 0x00000007c0000000) + eden space 157184K, 0% used [0x000000076c700000,0x000000076c700000,0x0000000776080000) + from space 1536K, 95% used [0x0000000777600000,0x000000077776d550,0x0000000777780000) + to space 10240K, 0% used [0x0000000776380000,0x0000000776380000,0x0000000776d80000) + ParOldGen total 93184K, used 6900K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5abd178,0x00000006caf00000) + Metaspace used 26410K, capacity 26964K, committed 27264K, reserved 1073152K + class space used 3204K, capacity 3367K, committed 3456K, reserved 1048576K +} +Event: 114.140 GC heap before +{Heap before GC invocations=14 (full 1): + PSYoungGen total 158720K, used 158645K [0x000000076c700000, 0x0000000777780000, 0x00000007c0000000) + eden space 157184K, 100% used [0x000000076c700000,0x0000000776080000,0x0000000776080000) + from space 1536K, 95% used [0x0000000777600000,0x000000077776d550,0x0000000777780000) + to space 10240K, 0% used [0x0000000776380000,0x0000000776380000,0x0000000776d80000) + ParOldGen total 93184K, used 6900K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5abd178,0x00000006caf00000) + Metaspace used 26418K, capacity 26964K, committed 27264K, reserved 1073152K + class space used 3204K, capacity 3367K, committed 3456K, reserved 1048576K +Event: 114.143 GC heap after +Heap after GC invocations=14 (full 1): + PSYoungGen total 154624K, used 1655K [0x000000076c700000, 0x0000000777680000, 0x00000007c0000000) + eden space 152576K, 0% used [0x000000076c700000,0x000000076c700000,0x0000000775c00000) + from space 2048K, 80% used [0x0000000776380000,0x000000077651dff0,0x0000000776580000) + to space 9728K, 0% used [0x0000000776d00000,0x0000000776d00000,0x0000000777680000) + ParOldGen total 93184K, used 6908K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5abf178,0x00000006caf00000) + Metaspace used 26418K, capacity 26964K, committed 27264K, reserved 1073152K + class space used 3204K, capacity 3367K, committed 3456K, reserved 1048576K +} +Event: 115.355 GC heap before +{Heap before GC invocations=15 (full 1): + PSYoungGen total 154624K, used 154231K [0x000000076c700000, 0x0000000777680000, 0x00000007c0000000) + eden space 152576K, 100% used [0x000000076c700000,0x0000000775c00000,0x0000000775c00000) + from space 2048K, 80% used [0x0000000776380000,0x000000077651dff0,0x0000000776580000) + to space 9728K, 0% used [0x0000000776d00000,0x0000000776d00000,0x0000000777680000) + ParOldGen total 93184K, used 6908K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5abf178,0x00000006caf00000) + Metaspace used 26418K, capacity 26964K, committed 27264K, reserved 1073152K + class space used 3204K, capacity 3367K, committed 3456K, reserved 1048576K +Event: 115.360 GC heap after +Heap after GC invocations=15 (full 1): + PSYoungGen total 150016K, used 1591K [0x000000076c700000, 0x0000000776f00000, 0x00000007c0000000) + eden space 147968K, 0% used [0x000000076c700000,0x000000076c700000,0x0000000775780000) + from space 2048K, 77% used [0x0000000776d00000,0x0000000776e8dff0,0x0000000776f00000) + to space 9216K, 0% used [0x0000000775d00000,0x0000000775d00000,0x0000000776600000) + ParOldGen total 93184K, used 6908K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5abf178,0x00000006caf00000) + Metaspace used 26418K, capacity 26964K, committed 27264K, reserved 1073152K + class space used 3204K, capacity 3367K, committed 3456K, reserved 1048576K +} +Event: 127.014 GC heap before +{Heap before GC invocations=16 (full 1): + PSYoungGen total 150016K, used 149559K [0x000000076c700000, 0x0000000776f00000, 0x00000007c0000000) + eden space 147968K, 100% used [0x000000076c700000,0x0000000775780000,0x0000000775780000) + from space 2048K, 77% used [0x0000000776d00000,0x0000000776e8dff0,0x0000000776f00000) + to space 9216K, 0% used [0x0000000775d00000,0x0000000775d00000,0x0000000776600000) + ParOldGen total 93184K, used 6908K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5abf178,0x00000006caf00000) + Metaspace used 26464K, capacity 27028K, committed 27264K, reserved 1073152K + class space used 3205K, capacity 3367K, committed 3456K, reserved 1048576K +Event: 127.033 GC heap after +Heap after GC invocations=16 (full 1): + PSYoungGen total 144896K, used 1473K [0x000000076c700000, 0x0000000776d80000, 0x00000007c0000000) + eden space 143360K, 0% used [0x000000076c700000,0x000000076c700000,0x0000000775300000) + from space 1536K, 95% used [0x0000000775d00000,0x0000000775e70540,0x0000000775e80000) + to space 9216K, 0% used [0x0000000776480000,0x0000000776480000,0x0000000776d80000) + ParOldGen total 93184K, used 6916K [0x00000006c5400000, 0x00000006caf00000, 0x000000076c700000) + object space 93184K, 7% used [0x00000006c5400000,0x00000006c5ac1178,0x00000006caf00000) + Metaspace used 26464K, capacity 27028K, committed 27264K, reserved 1073152K + class space used 3205K, capacity 3367K, committed 3456K, reserved 1048576K +} + +Deoptimization events (10 events): +Event: 116.483 Thread 0x0000000002381000 Uncommon trap: reason=range_check action=none pc=0x0000000003181274 method=sun.reflect.generics.parser.SignatureParser.current()C @ 34 +Event: 116.483 Thread 0x0000000002381000 Uncommon trap: reason=range_check action=none pc=0x0000000003181274 method=sun.reflect.generics.parser.SignatureParser.current()C @ 34 +Event: 116.483 Thread 0x0000000002381000 Uncommon trap: reason=range_check action=none pc=0x0000000003181274 method=sun.reflect.generics.parser.SignatureParser.current()C @ 34 +Event: 116.483 Thread 0x0000000002381000 Uncommon trap: reason=range_check action=none pc=0x0000000003181274 method=sun.reflect.generics.parser.SignatureParser.current()C @ 34 +Event: 116.483 Thread 0x0000000002381000 Uncommon trap: reason=range_check action=none pc=0x0000000003181274 method=sun.reflect.generics.parser.SignatureParser.current()C @ 34 +Event: 116.483 Thread 0x0000000002381000 Uncommon trap: reason=range_check action=none pc=0x0000000003181274 method=sun.reflect.generics.parser.SignatureParser.current()C @ 34 +Event: 116.483 Thread 0x0000000002381000 Uncommon trap: reason=range_check action=none pc=0x0000000003181274 method=sun.reflect.generics.parser.SignatureParser.current()C @ 34 +Event: 116.483 Thread 0x0000000002381000 Uncommon trap: reason=range_check action=none pc=0x0000000003181274 method=sun.reflect.generics.parser.SignatureParser.current()C @ 34 +Event: 116.483 Thread 0x0000000002381000 Uncommon trap: reason=range_check action=none pc=0x00000000032857bc method=sun.reflect.generics.parser.SignatureParser.current()C @ 34 +Event: 131.311 Thread 0x0000000002381000 Uncommon trap: reason=unstable_if action=reinterpret pc=0x0000000003324434 method=org.codehaus.jackson.impl.ReaderBasedParser.nextToken()Lorg/codehaus/jackson/JsonToken; @ 37 + +Internal exceptions (10 events): +Event: 116.483 Thread 0x0000000002381000 Exception (0x0000000774722590) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp, line 366] +Event: 116.483 Thread 0x0000000002381000 Exception (0x0000000774723398) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp, line 366] +Event: 116.483 Thread 0x0000000002381000 Exception (0x0000000774724040) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp, line 366] +Event: 116.483 Thread 0x0000000002381000 Exception (0x0000000774724d40) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp, line 366] +Event: 116.483 Thread 0x0000000002381000 Exception (0x00000007747259e8) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp, line 366] +Event: 116.483 Thread 0x0000000002381000 Exception (0x00000007747266e0) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp, line 366] +Event: 116.483 Thread 0x0000000002381000 Exception (0x0000000774727458) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp, line 366] +Event: 116.483 Thread 0x0000000002381000 Exception (0x0000000774728060) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp, line 366] +Event: 116.483 Thread 0x0000000002381000 Exception (0x0000000774728c58) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp, line 366] +Event: 119.647 Thread 0x0000000002381000 Exception (0x0000000774aedd18) thrown at [C:\re\workspace\8-2-build-windows-amd64-cygwin\jdk8u101\7261\hotspot\src\share\vm\prims\jni.cpp, line 735] + +Events (10 events): +Event: 2632.158 Executing VM operation: EnterInterpOnlyMode +Event: 2632.158 Executing nested VM operation: Deoptimize +Event: 2632.159 Executing nested VM operation: Deoptimize done +Event: 2632.159 Executing VM operation: EnterInterpOnlyMode done +Event: 2632.159 Executing VM operation: ChangeSingleStep +Event: 2632.159 Executing VM operation: ChangeSingleStep done +Event: 2632.160 Executing VM operation: ChangeSingleStep +Event: 2632.160 Executing VM operation: ChangeSingleStep done +Event: 2632.193 Executing VM operation: RedefineClasses +Event: 2632.229 Executing VM operation: RedefineClasses done + + +Dynamic libraries: +0x000000013fd10000 - 0x000000013fd47000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\javaw.exe +0x0000000077510000 - 0x00000000776ba000 C:\WINDOWS\SYSTEM32\ntdll.dll +0x00000000773f0000 - 0x000000007750f000 C:\WINDOWS\system32\kernel32.dll +0x000007fefd2e0000 - 0x000007fefd34a000 C:\WINDOWS\system32\KERNELBASE.dll +0x000007fefd600000 - 0x000007fefd6db000 C:\WINDOWS\system32\ADVAPI32.dll +0x000007fefe3e0000 - 0x000007fefe47f000 C:\WINDOWS\system32\msvcrt.dll +0x000007fefe480000 - 0x000007fefe49f000 C:\WINDOWS\SYSTEM32\sechost.dll +0x000007fefe510000 - 0x000007fefe63d000 C:\WINDOWS\system32\RPCRT4.dll +0x00000000772f0000 - 0x00000000773ea000 C:\WINDOWS\system32\USER32.dll +0x000007fefe4a0000 - 0x000007fefe507000 C:\WINDOWS\system32\GDI32.dll +0x000007feff730000 - 0x000007feff73e000 C:\WINDOWS\system32\LPK.dll +0x000007fefe820000 - 0x000007fefe8ea000 C:\WINDOWS\system32\USP10.dll +0x000007fefb4c0000 - 0x000007fefb6b4000 C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.18837_none_fa3b1e3d17594757\COMCTL32.dll +0x000007fefd9e0000 - 0x000007fefda51000 C:\WINDOWS\system32\SHLWAPI.dll +0x000007fefd9b0000 - 0x000007fefd9de000 C:\WINDOWS\system32\IMM32.DLL +0x000007fefdff0000 - 0x000007fefe0f9000 C:\WINDOWS\system32\MSCTF.dll +0x000007fef9c10000 - 0x000007fef9c9a000 C:\WINDOWS\system32\VSMAPIMon.dll +0x000007fef27e0000 - 0x000007fef2887000 C:\Program Files\McAfee\Host Intrusion Prevention\HcApi.dll +0x00000000705b0000 - 0x00000000705bb000 C:\Program Files\McAfee\Host Intrusion Prevention\HcThe.dll +0x0000000055580000 - 0x0000000055652000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\msvcr100.dll +0x000000006f5e0000 - 0x000000006fe7a000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\server\jvm.dll +0x000007fefbda0000 - 0x000007fefbda9000 C:\WINDOWS\system32\WSOCK32.dll +0x000007feff6e0000 - 0x000007feff72d000 C:\WINDOWS\system32\WS2_32.dll +0x000007fefdfc0000 - 0x000007fefdfc8000 C:\WINDOWS\system32\NSI.dll +0x000007fefaee0000 - 0x000007fefaf1b000 C:\WINDOWS\system32\WINMM.dll +0x000007fefc5f0000 - 0x000007fefc5fc000 C:\WINDOWS\system32\VERSION.dll +0x00000000776e0000 - 0x00000000776e7000 C:\WINDOWS\system32\PSAPI.DLL +0x00000000711e0000 - 0x00000000711ef000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\verify.dll +0x0000000065240000 - 0x0000000065269000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\java.dll +0x0000000055540000 - 0x0000000055575000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\jdwp.dll +0x00000000711d0000 - 0x00000000711d8000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\npt.dll +0x00000000003b0000 - 0x00000000003c6000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\zip.dll +0x000007fefe8f0000 - 0x000007feff67a000 C:\WINDOWS\system32\SHELL32.dll +0x000007fefdae0000 - 0x000007fefdce3000 C:\WINDOWS\system32\ole32.dll +0x000007fefd240000 - 0x000007fefd24f000 C:\WINDOWS\system32\profapi.dll +0x00000000711c0000 - 0x00000000711c9000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\dt_socket.dll +0x000007fefaa20000 - 0x000007fefaa35000 C:\WINDOWS\system32\NLAapi.dll +0x000007fef7bc0000 - 0x000007fef7bd5000 C:\WINDOWS\system32\napinsp.dll +0x000007fef7ba0000 - 0x000007fef7bb9000 C:\WINDOWS\system32\pnrpnsp.dll +0x000007fefca20000 - 0x000007fefca75000 C:\WINDOWS\System32\mswsock.dll +0x000007fefc8a0000 - 0x000007fefc8fb000 C:\WINDOWS\system32\DNSAPI.dll +0x000007fef7b90000 - 0x000007fef7b9b000 C:\WINDOWS\System32\winrnr.dll +0x000007fef7b80000 - 0x000007fef7b90000 C:\WINDOWS\system32\wshbth.dll +0x000007fefa330000 - 0x000007fefa357000 C:\WINDOWS\system32\IPHLPAPI.DLL +0x000007fefa320000 - 0x000007fefa32b000 C:\WINDOWS\system32\WINNSI.DLL +0x000007fef95a0000 - 0x000007fef95f3000 C:\WINDOWS\System32\fwpuclnt.dll +0x000007fef7010000 - 0x000007fef7018000 C:\WINDOWS\system32\rasadhlp.dll +0x000007fefc2d0000 - 0x000007fefc2d7000 C:\WINDOWS\System32\wshtcpip.dll +0x000000006f380000 - 0x000000006f39a000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\net.dll +0x000007fefca10000 - 0x000007fefca17000 C:\WINDOWS\System32\wship6.dll +0x000007fefca80000 - 0x000007fefca98000 C:\WINDOWS\system32\CRYPTSP.dll +0x000007fefc780000 - 0x000007fefc7c7000 C:\WINDOWS\system32\rsaenh.dll +0x000007fefd400000 - 0x000007fefd41e000 C:\WINDOWS\system32\USERENV.dll +0x000007fefd180000 - 0x000007fefd18f000 C:\WINDOWS\system32\CRYPTBASE.dll +0x000007fef9550000 - 0x000007fef9561000 C:\WINDOWS\system32\dhcpcsvc6.DLL +0x000007fef98c0000 - 0x000007fef98d8000 C:\WINDOWS\system32\dhcpcsvc.DLL +0x000000006f300000 - 0x000000006f311000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\nio.dll +0x000007fefd120000 - 0x000007fefd177000 C:\WINDOWS\system32\apphelp.dll +0x0000000051ba0000 - 0x0000000051bc4000 C:\Program Files\Java\jdk1.8.0_101\jre\bin\sunec.dll +0x000007fef68d0000 - 0x000007fef69f5000 C:\WINDOWS\system32\dbghelp.dll + +VM Arguments: +jvm_args: -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:65399 -ea -Dlogback.configurationFile=src/test/resources/logback-test.xml -Dfile.encoding=Cp1252 +java_command: org.testng.remote.RemoteTestNG -serport 65394 -protocol json -d C:\Users\md9897\Projects\d2-sdnc\ui-ci\test-output C:\Users\md9897\AppData\Local\Temp\testng-eclipse-914658768\testng-customsuite.xml +java_class_path (initial): C:\Users\md9897\Desktop\eclipse\plugins\org.testng.eclipse_6.9.13.201609291640\lib\testng-remote.jar;C:\Users\md9897\Projects\d2-sdnc\ui-ci\target\test-classes;C:\Users\md9897\Projects\d2-sdnc\ui-ci\target\classes;C:\Users\md9897\.m2\repository\org\seleniumhq\selenium\selenium-java\2.45.0\selenium-java-2.45.0.jar;C:\Users\md9897\.m2\repository\org\seleniumhq\selenium\selenium-chrome-driver\2.45.0\selenium-chrome-driver-2.45.0.jar;C:\Users\md9897\.m2\repository\org\seleniumhq\selenium\selenium-remote-driver\2.45.0\selenium-remote-driver-2.45.0.jar;C:\Users\md9897\.m2\repository\cglib\cglib-nodep\2.1_3\cglib-nodep-2.1_3.jar;C:\Users\md9897\.m2\repository\org\seleniumhq\selenium\selenium-api\2.45.0\selenium-api-2.45.0.jar;C:\Users\md9897\.m2\repository\org\seleniumhq\selenium\selenium-htmlunit-driver\2.45.0\selenium-htmlunit-driver-2.45.0.jar;C:\Users\md9897\.m2\repository\net\sourceforge\htmlunit\htmlunit\2.15\htmlunit-2.15.jar;C:\Users\md9897\.m2\repository\xalan\xalan\2.7.1\xalan-2.7.1.jar;C:\Users\md9897\.m2\repository\xalan\serializer\2.7.1\serializer-2.7.1.jar;C:\Users\md9897\.m2\repository\net\sourceforge\htmlunit\htmlunit-core-js\2.15\htmlunit-core-js-2.15.jar;C:\Users\md9897\.m2\repository\xerces\xercesImpl\2.11.0\xercesImpl-2.11.0.jar;C:\Users\md9897\.m2\repository\net\sourceforge\nekohtml\nekohtml\1.9.21\nekohtml-1.9.21.jar;C:\Users\md9897\.m2\repository\net\sourceforge\cssparser\cssparser\0.9.14\cssparser-0.9.14.jar;C:\Users\md9897\.m2\repository\org\w3c\css\sac\1.3\sac-1.3.jar;C:\Users\md9897\.m2\repository\org\eclipse\jetty\jetty-websocket\8.1.15.v20140411\jetty-websocket-8.1.15.v20140411.jar;C:\Users\md9897\.m2\repository\org\eclipse\jetty\jetty-util\8.1.15.v20140411\jetty-util-8.1.15.v20140411.jar;C:\Users\md9897\.m2\repository\org\eclipse\jetty\jetty-io\8.1.15.v20140411\jetty-io-8.1.15.v20140411.jar;C:\Users\md9897\.m2\repository\org\eclipse\jetty\jetty-http\8.1.15.v20140411\jetty-http-8.1.15.v20140411.jar;C:\Users\md9897\. +Launcher Type: SUN_STANDARD + +Environment Variables: +PATH=C:\Program Files\Java\jdk1.8.0_101\jre\bin;C:/Program Files/Java/jre1.8.0_101/bin/server;C:/Program Files/Java/jre1.8.0_101/bin;C:/Program Files/Java/jre1.8.0_101/lib/amd64;C:\ProgramData\Oracle\Java\javapath;C:\Program Files (x86)\RSA SecurID Token Common;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Git\cmd;C:\Program Files (x86)\GitExtensions\;C:\HashiCorp\Vagrant\bin;C:\Program Files (x86)\WinSCP\;C:\Program Files (x86)\PuTTY\;C:\Program Files\nodejs\;C:\Users\md9897\AppData\Roaming\npm;C:\Users\md9897\Desktop\eclipse; +USERNAME=md9897 +OS=Windows_NT +PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 78 Stepping 3, GenuineIntel + + + +--------------- S Y S T E M --------------- + +OS: Windows 7 , 64 bit Build 7601 (6.1.7601.23543) + +CPU:total 4 (2 cores per cpu, 2 threads per core) family 6 model 78 stepping 3, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt, avx, avx2, aes, clmul, erms, rtm, 3dnowpref, lzcnt, ht, tsc, tscinvbit, bmi1, bmi2, adx + +Memory: 4k page, physical 16432244k(7214352k free), swap 32862628k(23040548k free) + +vm_info: Java HotSpot(TM) 64-Bit Server VM (25.101-b13) for windows-amd64 JRE (1.8.0_101-b13), built on Jun 22 2016 01:21:29 by "java_re" with MS VC++ 10.0 (VS2010) + +time: Wed Nov 09 17:56:52 2016 +elapsed time: 2632 seconds (0d 0h 43m 52s) + diff --git a/ui-ci/pom.xml b/ui-ci/pom.xml new file mode 100644 index 0000000000..072a610360 --- /dev/null +++ b/ui-ci/pom.xml @@ -0,0 +1,357 @@ + + + 4.0.0 + + ui-ci + Selenium tests for the SDnC Application + + + org.openecomp.sdc + sdc-main + 1.1.0-SNAPSHOT + + + + + com.google.guava + guava + ${guava.version} + compile + + + + org.seleniumhq.selenium + selenium-java + 2.53.1 + + + + org.seleniumhq.selenium + selenium-server + 2.53.1 + runtime + + + + commons-net + commons-net + 3.3 + compile + + + + commons-io + commons-io + 2.4 + compile + + + + org.openecomp.sdc + test-apis-ci + ${project.version} + + compile + + + + org.yaml + snakeyaml + ${snakeyaml.version} + compile + + + org.functionaljava + functionaljava + ${functionaljava.version} + compile + + + + com.google.code.gson + gson + ${gson.version} + compile + + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + compile + + + + org.apache.httpcomponents + httpmime + ${httpclient.version} + compile + + + + commons-logging + commons-logging + ${commons-logging} + compile + + + + org.slf4j + slf4j-api + ${slf4j-api.version} + compile + + + + ch.qos.logback + logback-classic + ${logback.version} + compile + + + + ch.qos.logback + logback-core + ${logback.version} + compile + + + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + compile + + + + + com.thinkaurelius.titan + titan-core + ${titan.version} + compile + + + + com.thinkaurelius.titan + titan-cassandra + ${titan.version} + compile + + + + org.codehaus.jackson + jackson-mapper-asl + 1.9.2 + compile + + + + com.fasterxml.jackson.core + jackson-databind + 2.3.1 + compile + + + + com.fasterxml.jackson.core + jackson-core + 2.3.1 + compile + + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.annotations.version} + compile + + + + org.openecomp.sdc.sdc-distribution-client + sdc-distribution-client + 1.1.9-SNAPSHOT + compile + + + + junit + junit + ${junit.version} + compile + + + + org.testng + testng + ${testng.version} + compile + + + + xml-apis + xml-apis + 1.4.01 + compile + + + + com.googlecode.json-simple + json-simple + ${json-simple.version} + compile + + + + org.apache.commons + commons-jci-core + ${commons-jci-core.version} + compile + + + + org.sikuli + sikuli-api + 1.2.0 + + + + org.sikuli + sikuli-core + 1.2.2 + + + + commons-codec + commons-codec + ${commons-codec} + compile + + + + com.aventstack + extentreports + 3.0.6 + compile + + + + net.lightbody.bmp + + browsermob-core + 2.1.4 + + + + com.github.markusbernhardt + proxy-vole + 1.0.2 + + + + com.paulhammant + ngwebdriver + 0.9.7 + compile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.7 + + true + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.5.5 + + + create.jar.with.dependencies + package + + single + + + + + org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest + + + + jar-with-dependencies + + + + + + + + + + + Fortify + + false + + + + + + + + + + com.fortify.ps.maven.plugin + sca-maven-plugin + 4.30 + + false + true + + + + + + + diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/AddComponentInstancesArtifactsInCsar.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/AddComponentInstancesArtifactsInCsar.java new file mode 100644 index 0000000000..a8e6501dff --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/AddComponentInstancesArtifactsInCsar.java @@ -0,0 +1,415 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.devCI.ArtifactFromCsar; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.ToscaArtifactsPage; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; +import com.clearspring.analytics.util.Pair; + + +public class AddComponentInstancesArtifactsInCsar extends SetupCDTest { + + private String filePath; + @BeforeClass + public void beforeClass(){ + filePath = System.getProperty("filepath"); + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath() + "AddComponentInstancesArtifactsInCsar"+ File.separator; + } + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator + "AddComponentInstancesArtifactsInCsar"+ File.separator; + } + } + + // US847439 - Story [BE] - Add Component Instance's artifacts in CSAR + // TC1521795 - VF CSAR - The Flow + @Test + public void vfAndServicerCsarTheFlow() throws Exception{ + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + String vnfFile = "FDNT.zip"; + String snmpFile = "Fault-alarms-ASDC-vprobes-vLB.zip"; + + OnboardingUtils.createVendorLicense(getUser()); + Pair> createVSP = OnboardingUtils.createVSP(vnfFile, filePath, getUser()); + String vspName = createVSP.left; + resourceMetaData.setName(vspName); + Map resourceMeta = createVSP.right; + String vspid = resourceMeta.get("vspId"); + OnboardingUtils.addVFCArtifacts(filePath, snmpFile, null, vspid, getUser()); + OnboardingUtils.prepareVspForUse(getUser(), vspid); + + HomePage.showVspRepository(); + OnboardingUtils.importVSP(createVSP); + resourceMetaData.setVersion("0.1"); + Resource vfResource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceMetaData.getName(), resourceMetaData.getVersion()); + + + Map artifacts = getArtifactsOfComponentAndComponentsInstance(vfResource); + + List> artifactsUploadedToComponentInstance = new LinkedList<>(); + Random random = new Random(); + for(int i=0; i uploadArtifactOnRandomVfc = uploadArtifactOnRandomRI(vfResource); + + if(uploadArtifactOnRandomVfc.getRight().getArtifactName() != null) { + artifactsUploadedToComponentInstance.add(uploadArtifactOnRandomVfc); + } + } + + if(artifactsUploadedToComponentInstance.size() > 0) { + Map artifactsOfResourceInstance = getArtifactsOfResourceInstance(artifactsUploadedToComponentInstance); + artifacts.put("Resources", artifactsOfResourceInstance); + } + + + ResourceGeneralPage.getLeftMenu().moveToToscaArtifactsScreen(); + ToscaArtifactsPage.downloadCsar(); + File latestFilefromDir = FileHandling.getLastModifiedFileFromDir(); + Map combineHeatArtifacstWithFolderArtifacsToMap = ArtifactFromCsar.getVFCArtifacts(latestFilefromDir.getAbsolutePath()); + + compareArtifactFromFileStructureToArtifactsFromJavaObject(artifacts, combineHeatArtifacstWithFolderArtifacsToMap); + + +// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// // Submit for testing + certify +// DeploymentArtifactPage.clickSubmitForTestingButton(vspName); +// +// reloginWithNewRole(UserRoleEnum.TESTER); +// GeneralUIUtils.findComponentAndClick(vspName); +// TesterOperationPage.certifyComponent(vspName); +// +// reloginWithNewRole(UserRoleEnum.DESIGNER); +// // create service +// ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); +// ServiceUIUtils.createService(serviceMetadata, getUser()); +// serviceMetadata.setVersion("0.1"); +// +// +// // Upload informationl artifact to service +// ServiceGeneralPage.getLeftMenu().moveToCompositionScreen(); +// +// String HEAT_FILE_YAML_NAME = "Heat-File.yaml"; +// String DESCRIPTION = "kuku"; +// String ARTIFACT_LABEL = "artifact3"; +// +// ArtifactInfo artifact = new ArtifactInfo(filePath, HEAT_FILE_YAML_NAME, DESCRIPTION, ARTIFACT_LABEL,"OTHER"); +// CompositionPage.showDeploymentArtifactTab(); +// CompositionPage.clickAddArtifactButton(); +// ArtifactUIUtils.fillAndAddNewArtifactParameters(artifact, CompositionPage.artifactPopup()); +// +// ArtifactInfo informationArtifact = new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "GUIDE"); +// CompositionPage.showInformationArtifactTab(); +// CompositionPage.clickAddArtifactButton(); +// ArtifactUIUtils.fillAndAddNewArtifactParameters(informationArtifact, CompositionPage.artifactPopup()); +// +// +// +// // Add component instance to canvas of the service +// CompositionPage.searchForElement(vspName); +// CanvasManager serviceCanvasManager = CanvasManager.getCanvasManager(); +// CanvasElement vfElement = serviceCanvasManager.createElementOnCanvas(vspName); +// +// Service service = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, serviceMetadata.getName(), serviceMetadata.getVersion()); +// +//// ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", "OTHER", true, false); +//// RestResponse restResponse = ArtifactRestUtils.externalAPIUploadArtifactOfTheAsset(service, getUser(), artifactReqDetails); +//// Integer responseCode = restResponse.getErrorCode(); +//// Assert.assertEquals(responseCode, (Integer)200, "Response code is not correct."); +//// +//// service = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, serviceMetadata.getName(), serviceMetadata.getVersion()); +// +// Map artifactsService = getArtifactsOfComponentAndComponentsInstance(service); +// +// System.out.println("12354"); +// +// artifactsService.put(vfResource.getToscaResourceName(), artifacts); +// +// System.out.println("1234"); + + } + + public void compareArtifactFromFileStructureToArtifactsFromJavaObject(Map artifactFromJavaObject, Map artifactsFromFileStructure) { + for(String key: artifactFromJavaObject.keySet()) { + if((!key.equals("Deployment")) && (!key.equals("Informational"))) { + Map newArtifactFromJavaObject = (Map) artifactFromJavaObject.get(key); + Map newArtifactsFromFileStructure = (Map) artifactsFromFileStructure.get(key); + compareArtifactFromFileStructureToArtifactsFromJavaObject(newArtifactFromJavaObject, newArtifactsFromFileStructure); + } else { + compareArtifacts(artifactFromJavaObject.get(key), artifactsFromFileStructure.get(key)); + } + + + + + } + } + + + private void compareArtifacts(Object artifactFromJavaObject, Object artifactsFromFileStructure) { + Map> artifactsMap = (Map>) artifactFromJavaObject; + List artifactsList = (List) artifactsFromFileStructure; + + for(HeatMetaFirstLevelDefinition heatMetaFirstLevelDefinition: artifactsList) { + Assert.assertTrue(artifactsMap.get(heatMetaFirstLevelDefinition.getType()).contains(heatMetaFirstLevelDefinition.getFileName()), + "Expected that artifacts will be the same. Not exists: " + heatMetaFirstLevelDefinition.getFileName() + " of type: " + heatMetaFirstLevelDefinition.getType()); + } + + for(String key: artifactsMap.keySet()) { + List artifacts = artifactsMap.get(key); + + for(HeatMetaFirstLevelDefinition heatMetaFirstLevelDefinition: artifactsList) { + if(heatMetaFirstLevelDefinition.getType().equals(key)) { + if(artifacts.contains(heatMetaFirstLevelDefinition.getFileName())) { + artifacts.remove(heatMetaFirstLevelDefinition.getFileName()); + } + } + } + + Assert.assertEquals(artifacts.size(), 0, "Expected that all artifacts equal. There is artifacts which not equal: " + artifacts.toString()); + } + } + + + public Map getArtifactsOfResourceInstance(List> riList) { + Map artifacts = new HashMap<>(); + + for(ImmutablePair ri: riList) { + ArtifactDefinition artifactDefinition = ri.getRight(); + ComponentInstance componentInstance = ri.getLeft(); + if(artifacts.containsKey(componentInstance.getNormalizedName())) { + if( ((Map>)((Map)artifacts.get(componentInstance.getNormalizedName())).get("Deployment")).containsKey(artifactDefinition.getArtifactType()) ) { + + ((Map>)((Map) artifacts.get(componentInstance.getNormalizedName())).get("Deployment")).get(artifactDefinition.getArtifactType()).add(artifactDefinition.getArtifactName()); + + } else { + ArrayList list = new ArrayList(); + list.add(artifactDefinition.getArtifactName()); + ((Map>)((Map) artifacts.get(componentInstance.getNormalizedName())).get("Deployment")).put(artifactDefinition.getArtifactType(), list); + } + + } else { + try { + + + ArrayList list = new ArrayList(); + list.add(artifactDefinition.getArtifactName()); + + Map> map = new HashMap<>(); + map.put(artifactDefinition.getArtifactType(), list); + + Map>> addMap = new HashMap<>(); + addMap.put("Deployment", map); + + artifacts.put(componentInstance.getNormalizedName(), addMap); + +// if(artifacts.size() == 0) { +// artifacts.put("Deployment", addMap); +// } else { +// ((Map>>) artifacts.get("Deployment")).putAll(addMap); +// } + } catch (Exception e) { + Assert.fail("Artifact name is null for componentInstance: " + componentInstance.getNormalizedName()); + } + } + } + return artifacts; + } + + public Map getArtifactsOfComponentAndComponentsInstance(Component component) { + Map artifacts = getArtifacstOfComponent(component); + + for(ComponentInstance componentInstance: component.getComponentInstances()) { + Map artifacstOfComponentInstance = getArtifacstOfComponentInstance(componentInstance); + if(artifacstOfComponentInstance.size() > 0) { + artifacts.put(componentInstance.getToscaComponentName() + "." + componentInstance.getComponentVersion(), artifacstOfComponentInstance); + } + } + + return artifacts; + } + + public Map getArtifacstOfComponentInstance(ComponentInstance componentInstance) { + Map map = new HashMap<>(); + + if(componentInstance.getArtifacts() != null) { + Map informationalArtifacts = getArtifacts(componentInstance.getArtifacts()); + if(informationalArtifacts.size() > 0) { + map.put("Informational", informationalArtifacts); + } + } + + if(componentInstance.getDeploymentArtifacts() != null) { + Map deploymentArtifacts = getArtifacts(componentInstance.getDeploymentArtifacts()); + if(deploymentArtifacts.size() > 0) { + map.put("Deployment", deploymentArtifacts); + } + } + + return map; + } + + public Map getArtifacstOfComponent(Component component) { + Map map = new HashMap<>(); + + if(component.getArtifacts() != null) { + Map informationalArtifacts = getArtifacts(component.getArtifacts()); + if(informationalArtifacts.size() > 0) { + map.put("Informational", informationalArtifacts); + } + } + + if(component.getDeploymentArtifacts() != null) { + Map deploymentArtifacts = getArtifacts(component.getDeploymentArtifacts()); + if(deploymentArtifacts.size() > 0) { + map.put("Deployment", deploymentArtifacts); + } + } + + return map; + } + + public Map getArtifacts(Map artifacts) { + Map map = new HashMap<>(); + + for(String artifact: artifacts.keySet()) { + ArtifactDefinition artifactDefinition = artifacts.get(artifact); + if((artifactDefinition.getEsId() != null) && (!artifactDefinition.getEsId().equals("")) && (!artifactDefinition.getArtifactType().equals("HEAT_ENV"))) { + if(map.containsKey(artifactDefinition.getArtifactType())) { + ((List) map.get(artifactDefinition.getArtifactType())).add(artifactDefinition.getArtifactName()); + } else { + ArrayList list = new ArrayList(); + list.add(artifactDefinition.getArtifactName()); + map.put(artifactDefinition.getArtifactType(), list); + } + } + } + + return map; + } + + public ImmutablePair uploadArtifactOnRandomRI(Component component) throws IOException, Exception { + ArtifactReqDetails artifactReqDetails = getRandomArtifact(); + Random random = new Random(); + int randInt = random.nextInt(component.getComponentInstances().size()); + User defaultUser = ElementFactory.getDefaultUser(getRole()); + ComponentInstance componentInstance = component.getComponentInstances().get(randInt); + + RestResponse uploadArtifactRestResponse = ArtifactRestUtils.externalAPIUploadArtifactOfComponentInstanceOnAsset(component, defaultUser, artifactReqDetails, componentInstance); + + // Check response of external API + Integer responseCode = uploadArtifactRestResponse.getErrorCode(); + Assert.assertEquals(responseCode, (Integer)200, "Response code is not correct."); + + ImmutablePair pair = ImmutablePair.of(componentInstance, ArtifactRestUtils.getArtifactDataFromJson(uploadArtifactRestResponse.getResponse())); + + return pair; + } + + public ImmutablePair uploadArtifactOnRandomRI(Resource resource) throws IOException, Exception { + ArtifactReqDetails artifactReqDetails = getRandomVfcArtifact(); + Random random = new Random(); + int randInt = random.nextInt(resource.getComponentInstances().size()); + User defaultUser = ElementFactory.getDefaultUser(getRole()); + ComponentInstance componentInstance = resource.getComponentInstances().get(randInt); + + RestResponse uploadArtifactRestResponse = ArtifactRestUtils.externalAPIUploadArtifactOfComponentInstanceOnAsset(resource, defaultUser, artifactReqDetails, componentInstance); + + + + // Check response of external API + Integer responseCode = uploadArtifactRestResponse.getErrorCode(); + + if(responseCode.equals(404)) { + getExtendTest().log(Status.SKIP, String.format("DE271521")); + throw new SkipException("DE271521"); + } + + Assert.assertEquals(responseCode, (Integer)200, "Response code is not correct."); + + ImmutablePair pair = ImmutablePair.of(componentInstance, ArtifactRestUtils.getArtifactDataFromJson(uploadArtifactRestResponse.getResponse())); + + return pair; + } + + public ArtifactReqDetails getRandomArtifact() throws IOException, Exception { + List artifactsTypeList = Arrays.asList("Other"); + return getRandomArtifact(artifactsTypeList); + } + + public ArtifactReqDetails getRandomVfcArtifact() throws IOException, Exception { + List vfcArtifactsTypeList = Arrays.asList("DCAE_INVENTORY_TOSCA", "DCAE_INVENTORY_JSON", "DCAE_INVENTORY_POLICY", "DCAE_INVENTORY_DOC", + "DCAE_INVENTORY_BLUEPRINT", "DCAE_INVENTORY_EVENT", "SNMP_POLL", "SNMP_TRAP"); + return getRandomArtifact(vfcArtifactsTypeList); + } + + public ArtifactReqDetails getRandomArtifact(List artifactType) throws IOException, Exception { + Random random = new Random(); + + ArtifactReqDetails artifactReqDetails = ElementFactory.getArtifactByType("ci", artifactType.get(random.nextInt(artifactType.size())), true, false); + return artifactReqDetails; + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/ImportUpdateInformationalDeploymentArtifacts.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/ImportUpdateInformationalDeploymentArtifacts.java new file mode 100644 index 0000000000..913064b7fd --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/ImportUpdateInformationalDeploymentArtifacts.java @@ -0,0 +1,343 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import static org.testng.AssertJUnit.assertTrue; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.testng.SkipException; +import org.testng.annotations.Test; + +public class ImportUpdateInformationalDeploymentArtifacts extends SetupCDTest { + + private String folder ="US747946"; + + // US747946 - Import artifacts to component instances + // TC1407822 - Import VFC Artifacts - Deployment Artifacts - Multiple Artifacts, Multiple Types + @Test + public void importVfvArtifactsDeploymentArtifactsMultipleArtifactsMultipleTypes() throws Exception { + + if(true){ + throw new SkipException("Open bug 197126"); + } + + String filePath = FileHandling.getFilePath(folder); + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + String fileName = "TC1407822.csar"; + + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName, getUser()); + + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceMetaData.getName(), "0.1"); + + List snmpPollArtifactList = Stream + .of("base_cgi_frwl.mib", "base_vIECCF_volume.yml", "node_userdata_script.sh", "vendor-license-model.xml") + .collect(Collectors.toList()); + List snmpTrapArtifactList = Stream + .of("module_1_ixlt.mib", "module_1_ixlt.yaml") + .collect(Collectors.toList()); + + + List filteredArtifactNames = + //Stream of component Instances + resource.getComponentInstances().stream() + //Stream of all the artifacts on all the component instances + .flatMap( e -> e.getDeploymentArtifacts().values().stream()) + //filter relevant artifact types + .filter( e -> e.getArtifactType().equals(ArtifactTypeEnum.SNMP_TRAP.getType()) || e.getArtifactType().equals(ArtifactTypeEnum.SNMP_POLL.getType())) + //collect to list + .collect(Collectors.toList()); + + + assertTrue("Not contain all SNMP TRAP artifacts.", filteredArtifactNames.stream() + .filter(e -> e.getArtifactType().equals(ArtifactTypeEnum.SNMP_TRAP.getType())) + .map(e -> e.getArtifactName()) + .collect(Collectors.toList()) + .containsAll(snmpTrapArtifactList)); + + assertTrue("Not contain all SNMP POLL artifacts.", filteredArtifactNames.stream() + .filter(e -> e.getArtifactType().equals(ArtifactTypeEnum.SNMP_POLL.getType())) + .map(e -> e.getArtifactName()) + .collect(Collectors.toList()) + .containsAll(snmpPollArtifactList)); + + filteredArtifactNames.stream() + .map(e->e.getArtifactDisplayName()) + .collect(Collectors.toList()) + .forEach(e -> { + assertTrue("Wrong artifact appear on deployment artifact UI page.", + !GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.ArtifactPageEnum.UUID.getValue() + e)); + }); + + } + + + + // US747946 - Import artifacts to component instances + // TC1408044 - Import VFC Artifacts - Informational Artifacts on Single VFC + @Test + public void importVfcArtifactsInformationalArtifactsOnSingleVfc() throws Exception { + + if(true){ + throw new SkipException("Open bug 197126"); + } + + String filePath = FileHandling.getFilePath(folder); + String fileName = "TC1408044.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName, getUser()); + + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceMetaData.getName(), "0.1"); + + resource.getComponentInstances().forEach(e -> { + + if(e.getToscaComponentName().endsWith("heat.ltm")) { + Map> artifactsMap = new HashMap>() { + { + put(ArtifactTypeEnum.GUIDE.getType(), Arrays.asList("module_1_ldsa.yaml", "vendor-license-model.xml")); + put(ArtifactTypeEnum.OTHER.getType(), Arrays.asList("module_2_ldsa.yaml", "vf-license-model.xml")); + } + }; + + validateInformationalArtifactOnComponetInstance(e, artifactsMap, "heat.ltm"); + } + }); + } + + // TODO: Note there is performance issue with this CSAR + // US747946 - Import artifacts to component instances + // TC1407998 - Import VFC Artifacts - Deployment & Informational Artifacts - Multiple VFCs + @Test + public void importVfcArtifactsDeploymentAndInformationalArtifactsMultipleVfcs() throws Exception { + + if(true){ + throw new SkipException("Open bug 197126"); + } + + String filePath = FileHandling.getFilePath(folder); + String fileName = "TC1407998.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName, getUser()); + +// resourceMetaData.setName("TC1407998"); + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceMetaData.getName(), "0.1"); + + resource.getComponentInstances().forEach(e -> { + + if(e.getToscaComponentName().endsWith("heat.ps")) { + Map> deployArtifactsMap = new HashMap>() { + { + put(ArtifactTypeEnum.SNMP_POLL.getType(), Arrays.asList("PS_DEPL_Poll1.mib", "PS_DEPL_Poll2.xml", "PS_DEPL_Poll3.yaml")); + put(ArtifactTypeEnum.SNMP_TRAP.getType(), Arrays.asList("PS_DEPL_Trap1.mib", "PS_DEPL_Trap2.xml", "PS_DEPL_Trap3.sh", "PS_DEPL_Trap4.yml")); + } + }; + validateDeploymentArtifactOnComponetInstance(e, deployArtifactsMap, "heat.ps"); + + Map> infoArtifactsMap = new HashMap>() { + { + put(ArtifactTypeEnum.GUIDE.getType(), Arrays.asList("PS_INFO_GUIDE1.yaml", "PS_INFO_GUIDE2.xml")); + put(ArtifactTypeEnum.OTHER.getType(), Arrays.asList("PS_INFO_OTHER1.yaml", "PS_INFO_OTHER2.xml")); + } + }; + validateInformationalArtifactOnComponetInstance(e, infoArtifactsMap, "heat.ps"); + + + } else if (e.getToscaComponentName().endsWith("heat.sm")) { + Map> deployArtifactsMap = new HashMap>() { + { + put(ArtifactTypeEnum.SNMP_POLL.getType(), Arrays.asList("SM_DEPL_Poll1.mib", "SM_DEPL_Poll2.mib", "SM_DEPL_Poll3.xml")); + put(ArtifactTypeEnum.SNMP_TRAP.getType(), Arrays.asList("SM_DEPL_Trap1.mib", "SM_DEPL_Trap2.xml")); + } + }; + validateDeploymentArtifactOnComponetInstance(e, deployArtifactsMap, "heat.sm"); + + Map> infoArtifactsMap = new HashMap>() { + { + put(ArtifactTypeEnum.GUIDE.getType(), Arrays.asList("SM_INFO_GUIDE1.yaml", "SM_INFO_GUIDE2.xml")); + put(ArtifactTypeEnum.OTHER.getType(), Arrays.asList("SM_INFO_OTHER1.yaml", "SM_INFO_OTHER2.xml")); + } + }; + validateInformationalArtifactOnComponetInstance(e, infoArtifactsMap, "heat.sm"); + } + }); + + } + + // US747946 - Import artifacts to component instances + // TC1410352 - Import VFC Artifacts - Deployment Artifacts - Extra folder Under VFC-Identification + @Test + public void importVfcArtifactsDeploymentArtifactsExtraFolderUnderVfcIdentification() throws Exception { + + if(true){ + throw new SkipException("Open bug 197126"); + } + + String filePath = FileHandling.getFilePath(folder); + String fileName = "TC1410352.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName, getUser()); + +// resourceMetaData.setName("TC1410352"); + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceMetaData.getName(), "0.1"); + + resource.getComponentInstances().forEach(e -> { + + if(e.getToscaComponentName().endsWith("heat.ltm")) { + Map> deployArtifactsMap = new HashMap>() { + { + put(ArtifactTypeEnum.SNMP_POLL.getType(), Arrays.asList("Poll1.mib", "Poll2.xml", "Poll3.sh", "Poll4.yml")); + put(ArtifactTypeEnum.SNMP_TRAP.getType(), Arrays.asList("Trap1.mib", "Trap2.yaml")); + } + }; + validateDeploymentArtifactOnComponetInstance(e, deployArtifactsMap, "heat.ltm"); + + Map> infoArtifactsMap = new HashMap>() { + { + put(ArtifactTypeEnum.GUIDE.getType(), Arrays.asList("GUIDE1.yaml", "GUIDE2.xml")); + put(ArtifactTypeEnum.OTHER.getType(), Arrays.asList("OTHER1.yaml", "OTHER2.xml")); + } + }; + validateInformationalArtifactOnComponetInstance(e, infoArtifactsMap, "heat.ltm"); + } + }); + } + + + // US747946 - Import artifacts to component instances + // TC1410352 - Import VFC Artifacts - Deployment Artifacts - Invalid Artifact Type + @Test + public void importVfcArtifactsDeploymentArtifactsInvalidArtifactType() throws Exception { + + if(true){ + throw new SkipException("Open bug 197126"); + } + + String filePath = FileHandling.getFilePath(folder); + String fileName = "TC1425032.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName, getUser()); + +// resourceMetaData.setName("TC1425032"); + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceMetaData.getName(), "0.1"); + + resource.getComponentInstances().forEach(e -> { + + if(e.getToscaComponentName().endsWith("heat.ltm")) { + Map> deployArtifactsMap = new HashMap>() { + { + put(ArtifactTypeEnum.SNMP_POLL.getType(), Arrays.asList("DeploySNMPPoll1.mib", "DeploySNMPPoll2.yml", "DeploySNMPPoll3.sh", "DeploySNMPPoll4.xml")); + put(ArtifactTypeEnum.OTHER.getType(), Arrays.asList("DeploySNMPTrapB1.mib", "DeploySNMPTrapB2.yaml")); + } + }; + validateDeploymentArtifactOnComponetInstance(e, deployArtifactsMap, "heat.ltm"); + + Map> infoArtifactsMap = new HashMap>() { + { + put(ArtifactTypeEnum.GUIDE.getType(), Arrays.asList("InfoGuide1.yaml", "InfoGuide2.xml")); + put(ArtifactTypeEnum.OTHER.getType(), Arrays.asList("InfoOther1.yaml", "InfoOther2.xml", "InfoInvalid1.yaml")); + } + }; + validateInformationalArtifactOnComponetInstance(e, infoArtifactsMap, "heat.ltm"); + } + }); + } + + + private void validateInformationalArtifactOnComponetInstance(ComponentInstance instacne, Map> artifactsMap, String endswith){ + if(instacne.getToscaComponentName().endsWith(endswith) ){ + Set types = artifactsMap.keySet(); + + Map> collect = instacne.getArtifacts().values().stream() + .filter( a -> types.contains(a.getArtifactType())) + .collect(Collectors.groupingBy( e -> e.getArtifactType())); + + types.forEach(m -> { + if(collect.containsKey(m)){ + List found = collect.get(m).stream().map(e -> e.getArtifactName()).collect(Collectors.toList()); + boolean isValid = found.containsAll(artifactsMap.get(m)) && artifactsMap.get(m).containsAll(found); + assertTrue("Not contain all artifact of type: " + m, isValid); + } else{ + assertTrue("Contains informational artifact which not in provided list", false); + } + }); + } + } + + private void validateDeploymentArtifactOnComponetInstance(ComponentInstance instacne, Map> artifactsMap, String endswith){ + if(instacne.getToscaComponentName().endsWith(endswith) ){ + Set types = artifactsMap.keySet(); + + Map> collect = instacne.getDeploymentArtifacts().values().stream() + .filter( a -> types.contains(a.getArtifactType())) + .collect(Collectors.groupingBy( e -> e.getArtifactType())); + + types.forEach(m -> { + if(collect.containsKey(m)){ + List found = collect.get(m).stream().map(e -> e.getArtifactName()).collect(Collectors.toList()); + boolean isValid = found.containsAll(artifactsMap.get(m)) && artifactsMap.get(m).containsAll(found); + assertTrue("Not contain all artifact of type: " + m, isValid); + } else{ + assertTrue("Contains deployment artifact which not in provided list", false); + } + }); + } + } + + + + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Inputs.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Inputs.java new file mode 100644 index 0000000000..dff10dba49 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Inputs.java @@ -0,0 +1,226 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.InputsPage; +import org.openecomp.sdc.ci.tests.pages.PropertyPopup; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.Assert; +import org.testng.TestException; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class Inputs extends SetupCDTest { + + private static final String DESCRIPTION = "kuku"; + private static final String ARTIFACT_LABEL = "artifact3"; + private static final String ARTIFACT_LABEL_UPDATE = "artifactUpdate"; + private static final String GET_ARTIFACT_LIST_BY_CLASS_NAME = "i-sdc-designer-sidebar-section-content-item-artifact"; + private static final String HEAT_FILE_YAML_NAME = "Heat-File.yaml"; + private static final String HEAT_FILE_YAML_UPDATE_NAME = "Heat-File-Update.yaml"; + private String filePath; + + @BeforeMethod + public void beforeTest(){ + filePath = FileHandling.getFilePath(""); + } + + // TODO: There is defect that imported VFC checkin not appear in service until refresh + // TODO: add support for CP (there is no normative CP's with complex properties which can be selected - import one) - importVFCWithComplexProperty.yml + // TC1508249 + // Delete Input declared from VLi/CPi in service level - Deleting an Input that was declared from Complex property. + @Test + public void deletingAnInputThatWasDeclaredFromComplexProperty() throws Exception{ + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + Map> resourceInstanceToProperty = new HashMap<>(); + CompositionPage.searchForElement("ExtVL"); + CanvasElement computeElement = canvasManager.createElementOnCanvas("ExtVL"); + canvasManager.clickOnCanvaElement(computeElement); + resourceInstanceToProperty.put(CompositionPage.getSelectedInstanceName(), Arrays.asList("network_homing", "instance_node_target")); + +// CompositionPage.searchForElement("ExtCP"); +// computeElement = canvasManager.createElementOnCanvas("ExtCP"); +// canvasManager.clickOnCanvaElement(computeElement); +// resourceInstanceToProperty.put(CompositionPage.getSelectedInstanceName(), "order"); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + DeploymentArtifactPage.getLeftMenu().moveToInputsScreen(); + + + for(String element: resourceInstanceToProperty.keySet()) { + String propertyName = resourceInstanceToProperty.get(element).get(0); + String innerPropertyName = resourceInstanceToProperty.get(element).get(1); + String dataTestIdPropertyCheckbox = DataTestIdEnum.InputsScreenService.RESOURCE_INSTANCE_PROPERTY_CHECKBOX.getValue() + propertyName; + + GeneralUIUtils.clickOnElementByText(element); + GeneralUIUtils.ultimateWait(); + + InputsPage.clickOnProperty(propertyName); + + PropertyPopup propertyPopup = new PropertyPopup(); + propertyPopup.selectPropertyRadioButton(innerPropertyName); + propertyPopup.clickSave(); + + InputsPage.clickOnAddInputButton(); + + // Verify that input checkbox selected + verifyPropertyCheckBoxSelected(dataTestIdPropertyCheckbox); + + InputsPage.deleteServiceInput(element, propertyName + "_" + innerPropertyName); + + // Trying to find deleted service input + try{ + InputsPage.getServiceInput(element, propertyName + "_" + innerPropertyName); + assert(false); + } catch(TestException e){ + System.out.println("Verfied that service input deleted"); + } + + // Verify that input checkbox not selected + verifyPropertyCheckBoxNotSelected(dataTestIdPropertyCheckbox); + + GeneralUIUtils.clickOnElementByText(element); + GeneralUIUtils.ultimateWait(); + } + + } + + + // TC1508248 + // Delete inputs who come from CP/VL properties + @Test + public void deleteInputsWhoComeFromCpVlProperties() throws Exception{ + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + Map resourceInstanceToProperty = new HashMap<>(); + CompositionPage.searchForElement("ExtVL"); + CanvasElement computeElement = canvasManager.createElementOnCanvas("ExtVL"); + canvasManager.clickOnCanvaElement(computeElement); + resourceInstanceToProperty.put(CompositionPage.getSelectedInstanceName(), "network_role"); + + CompositionPage.searchForElement("ExtCP"); + computeElement = canvasManager.createElementOnCanvas("ExtCP"); + canvasManager.clickOnCanvaElement(computeElement); + resourceInstanceToProperty.put(CompositionPage.getSelectedInstanceName(), "order"); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + DeploymentArtifactPage.getLeftMenu().moveToInputsScreen(); + + + for(String element: resourceInstanceToProperty.keySet()) { + GeneralUIUtils.clickOnElementByText(element); + GeneralUIUtils.ultimateWait(); + + WebElement webElementByTestID = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.InputsScreenService.RESOURCE_INSTANCE_PROPERTY_CHECKBOX.getValue() + resourceInstanceToProperty.get(element)); + InputsPage.clickOnVFInputCheckbox(webElementByTestID); + + InputsPage.clickOnAddInputButton(); + + // Verify that input checkbox selected + verifyPropertyCheckBoxSelected(DataTestIdEnum.InputsScreenService.RESOURCE_INSTANCE_PROPERTY_CHECKBOX.getValue() + resourceInstanceToProperty.get(element)); + + InputsPage.deleteServiceInput(element, resourceInstanceToProperty.get(element)); + + // Trying to find deleted service input + try{ + InputsPage.getServiceInput(element, resourceInstanceToProperty.get(element)); + assert(false); + } catch(TestException e){ + System.out.println("Verfied that service input deleted"); + } + + // Verify that input checkbox not selected + verifyPropertyCheckBoxNotSelected(DataTestIdEnum.InputsScreenService.RESOURCE_INSTANCE_PROPERTY_CHECKBOX.getValue() + resourceInstanceToProperty.get(element)); + + GeneralUIUtils.clickOnElementByText(element); + GeneralUIUtils.ultimateWait(); + } + + } + + + + + + + + public String verifyPropertyCheckBox(String dataTestId) { + WebElement webElementByTestID = GeneralUIUtils.getWebElementByTestID(dataTestId); + webElementByTestID = webElementByTestID.findElement(By.className("tlv-checkbox-i")); + if(webElementByTestID.getAttribute("checked") == null) { + return "false"; + } + return "true"; + } + + public void verifyPropertyCheckBoxSelected(String dataTestId) { + if(!verifyPropertyCheckBox(dataTestId).equals("true")) { + Assert.assertEquals(true, false, "Expected that checkbox will be selected."); + } + } + + public void verifyPropertyCheckBoxNotSelected(String dataTestId) { + if(!verifyPropertyCheckBox(dataTestId).equals("false")) { + Assert.assertEquals(false, true, "Expected that checkbox will not be selected."); + } + } + + public String getNormalizedName(String notNormalizedName) { + String normalizedName = notNormalizedName.toLowerCase(); + normalizedName = normalizedName.replaceAll(" ", ""); + + return normalizedName; + } + + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/LocalGeneralUtilities.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/LocalGeneralUtilities.java new file mode 100644 index 0000000000..fb1798d0c9 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/LocalGeneralUtilities.java @@ -0,0 +1,99 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.json.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; + +import com.clearspring.analytics.util.Pair; + +public class LocalGeneralUtilities { + + public LocalGeneralUtilities() { + // TODO Auto-generated constructor stub + } + public static final String FILE_PATH = FileHandling.getBasePath() + "\\src\\main\\resources\\Files\\VNFs\\"; + public static final String Env_FILE_PATH = FileHandling.getBasePath() + "\\src\\main\\resources\\Files\\Env_files\\"; + public static String downloadPath = "C:\\Users\\th0695\\Downloads"; + +public static String getValueFromJsonResponse(String response, String fieldName) { + try { + JSONObject jsonResp = (JSONObject) JSONValue.parse(response); + Object fieldValue = jsonResp.get(fieldName); + return fieldValue.toString(); + + } catch (Exception e) { + return null; + } + +} + +public static List getValuesFromJsonArray(RestResponse message) throws Exception { + List artifactTypesArrayFromApi = new ArrayList(); + + org.json.JSONObject responseObject = new org.json.JSONObject(message.getResponse()); + JSONArray jArr = responseObject.getJSONArray("componentInstances"); + + for (int i = 0; i < jArr.length(); i++) { + org.json.JSONObject jObj = jArr.getJSONObject(i); + String value = jObj.get("uniqueId").toString(); + + artifactTypesArrayFromApi.add(value); + } + return artifactTypesArrayFromApi; +} + +public static String simpleOnBoarding(String fileName, String filePath,User user) throws Exception { + OnboardingUtils.createVendorLicense(user); + Pair> createVendorSoftwareProduct = OnboardingUtils + .createVendorSoftwareProduct(fileName, filePath, user); + String vspName = createVendorSoftwareProduct.left; + HomePage.showVspRepository(); + OnboardingUtils.importVSP(createVendorSoftwareProduct); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralElementsEnum.CHECKIN_BUTTON.getValue()).click(); + GeneralUIUtils.waitForLoader(); + return vspName; +} + +//check if file downloaded successfully. +public static boolean isFileDownloaded(String downloadPath, String fileName) { + boolean flag = false; + File dir = new File(downloadPath); + File[] dir_contents = dir.listFiles(); + for (int i = 0; i < dir_contents.length; i++) { + if (dir_contents[i].getName().equals(fileName)) + return flag = true; + } + return flag; +} +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/MIBsArtifactsOnResourceInstance.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/MIBsArtifactsOnResourceInstance.java new file mode 100644 index 0000000000..949a20b4a9 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/MIBsArtifactsOnResourceInstance.java @@ -0,0 +1,269 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.io.FileUtils; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.TopMenuButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.UploadArtifactPopup; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ArtifactRestUtils; +import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + + +public class MIBsArtifactsOnResourceInstance extends SetupCDTest { + + private String folder =""; + + @DataProvider(name="mibsArtifactCRUDUi") + public static Object[][] dataProviderMibsArtifactCRUDUi() { + return new Object[][] { + {"mibsvFW_VFC.yml", ResourceTypeEnum.VFC}, + {"mibsVL.yml", ResourceTypeEnum.VL}, + {"mibsCP.yml", ResourceTypeEnum.CP} + }; + } + + // US820414 + // Artifact UI CRUD on VFC/VL/CP + // TODO: Change download validation from download artifact via external API to UI + @Test(dataProvider="mibsArtifactCRUDUi") + public void mibsArtifactCRUDUi(String fileName, ResourceTypeEnum resourceTypeEnum) throws Exception { + setLog("mibsArtifactCRUDUi"); + String filePath = FileHandling.getFilePath(folder); + + if(true){ + throw new SkipException("Open bug 197101"); + } + + // import Resource + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(resourceTypeEnum, getUser()); + ResourceUIUtils.importVfc(resourceMetaData, filePath, fileName, getUser()); + + // get resourceUUID from BE + String resourceUUID = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceMetaData.getName(), "0.1").getUUID(); + + // 2. Upload MIBs artifacts - SNMP_TRAP & SNMP_POLL. + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + List deploymentArtifactList = new ArrayList(); + deploymentArtifactList.add(new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "SNMP_TRAP")); + deploymentArtifactList.add(new ArtifactInfo(filePath, "sample-xml-alldata-1-1.xml", "cuku", "artifact2", "SNMP_POLL")); + for (ArtifactInfo deploymentArtifact : deploymentArtifactList) { + DeploymentArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(deploymentArtifact, new UploadArtifactPopup(true)); + + assertTrue("Only created artifact need to be exist", DeploymentArtifactPage.checkElementsCountInTable(1)); + + String artifactUUID = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.UUID.getValue() + deploymentArtifact.getArtifactLabel()).getText(); + ArtifactUIUtils.validateExistArtifactOnDeploymentInformationPage(deploymentArtifact.getArtifactLabel(), null, "1", deploymentArtifact.getArtifactType(), true, true, true, false); + + // Verify that uploaded correct file by download artifact via external api + RestResponse restResponse = ArtifactRestUtils.getResourceDeploymentArtifactExternalAPI(resourceUUID, artifactUUID, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ComponentTypeEnum.RESOURCE.toString()); + File file = new File(deploymentArtifact.getFilepath() + deploymentArtifact.getFilename()); + String readFileToString = FileUtils.readFileToString(file); + Assert.assertEquals(restResponse.getResponse(), readFileToString); + + DeploymentArtifactPage.clickEditArtifact(deploymentArtifact.getArtifactLabel()); + UploadArtifactPopup artifactPopup = new UploadArtifactPopup(true); + artifactPopup.loadFile(filePath, "CP.yml"); + artifactPopup.clickDoneButton(); + + assertTrue("Only updated artifact need to be exist", DeploymentArtifactPage.checkElementsCountInTable(1)); + Assert.assertNotEquals(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.UUID.getValue() + deploymentArtifact.getArtifactLabel()).getText(), artifactUUID); + ArtifactUIUtils.validateExistArtifactOnDeploymentInformationPage(deploymentArtifact.getArtifactLabel(), null, "2", deploymentArtifact.getArtifactType(), true, true, true, false); + + // Verify that updated correct file by download artifact via external api + artifactUUID = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.UUID.getValue() + deploymentArtifact.getArtifactLabel()).getText(); + restResponse = ArtifactRestUtils.getResourceDeploymentArtifactExternalAPI(resourceUUID, artifactUUID, ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER), ComponentTypeEnum.RESOURCE.toString()); + file = new File(deploymentArtifact.getFilepath() + "CP.yml"); + readFileToString = FileUtils.readFileToString(file); + Assert.assertEquals(restResponse.getResponse(), readFileToString); + + DeploymentArtifactPage.clickDeleteArtifact(deploymentArtifact.getArtifactLabel()); + DeploymentArtifactPage.clickOK(); + + assertTrue("No artifact need to be exist", DeploymentArtifactPage.checkElementsCountInTable(0)); + } + + } + + @DataProvider(name="mibsArtifacsOnResourceInstanceShouldOnlyHaveDownloadOption") + public static Object[][] dataProviderMibsArtifacsOnResourceInstanceShouldOnlyHaveDownloadOption() { + return new Object[][] { + {"mibs1vFW_VFC.yml", ResourceTypeEnum.VFC}, + // TODO: delete comment below when we will have support for VL on canvas +// {"mibs1VL.yml", ResourceTypeEnum.VL}, + {"mibs1CP.yml", ResourceTypeEnum.CP} + }; + } + + // US820414 + // Import VFC/VL/CP, upload MIBs artifacts then drag it on VF & verify that deployment artifact have only download option + @Test(dataProvider="mibsArtifacsOnResourceInstanceShouldOnlyHaveDownloadOption") + public void mibsArtifacsOnResourceInstanceShouldOnlyHaveDownloadOption(String fileName, ResourceTypeEnum resourceTypeEnum) throws Exception { + + setLog("mibsArtifacsOnResourceInstanceShouldOnlyHaveDownloadOption"); + + String filePath = FileHandling.getFilePath(folder); + + // import Resource + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(resourceTypeEnum, getUser()); + ResourceUIUtils.importVfc(resourceMetaData, filePath, fileName, getUser()); + + // 2. Upload MIBs artifacts - SNMP_TRAP & SNMP_POLL. + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + List deploymentArtifactList = new ArrayList(); + deploymentArtifactList.add(new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "SNMP_TRAP")); + deploymentArtifactList.add(new ArtifactInfo(filePath, "sample-xml-alldata-1-1.xml", "cuku", "artifact2", "SNMP_POLL")); + for (ArtifactInfo deploymentArtifact : deploymentArtifactList) { + DeploymentArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(deploymentArtifact, new UploadArtifactPopup(true)); + } + assertTrue("artifact table does not contain artifacts uploaded", DeploymentArtifactPage.checkElementsCountInTable(deploymentArtifactList.size())); + + // 3. Check-in DataProvider resource. + ResourceGeneralPage.clickCheckinButton(resourceMetaData.getName()); + + // 4. Create VF. + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + // 5. Click on composition. + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + // 6. Drag created DataProvider resource to canvas. + CanvasManager vfCanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(resourceMetaData.getName()); + CanvasElement resourceInstance = vfCanvasManager.createElementOnCanvas(resourceMetaData.getName()); + + // 7. Click on DataProvider resource. + vfCanvasManager.clickOnCanvaElement(resourceInstance); + + // 8. Click on deployment artifacts in right menu. + CompositionPage.showDeploymentArtifactTab(); + + // 9. Verify that each uploaded MIBs artifacts shows in deployment artifacts. + // 10. Verify that only have download option. + for (ArtifactInfo deploymentArtifact : deploymentArtifactList) { + // Hover over webelement -> check that only dowload button displayed + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_DISPLAY_NAME.getValue() + deploymentArtifact.getArtifactLabel()); + Assert.assertEquals(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DOWNLOAD.getValue() + deploymentArtifact.getArtifactLabel()).isDisplayed(), true); + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DELETE.getValue() + deploymentArtifact.getArtifactLabel()), false); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_DISPLAY_NAME.getValue() + deploymentArtifact.getArtifactLabel()); + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.ArtifactPopup.MODAL_WINDOW.getValue()), false); + } + + + } + + // US820414 + // Create VF, upload MIBs artifacts then drag it on service & verify that deployment artifact have only download option + @Test + public void mibsArtifacsOnVFInstanceShouldOnlyHaveDownloadOption() throws Exception { + String filePath = FileHandling.getFilePath(folder); + + // 1. Create VF. + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(resourceMetaData, getUser()); + + // 2. Upload MIBs artifacts - SNMP_TRAP & SNMP_POLL. + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + List deploymentArtifactList = new ArrayList(); + deploymentArtifactList.add(new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "SNMP_TRAP")); + deploymentArtifactList.add(new ArtifactInfo(filePath, "sample-xml-alldata-1-1.xml", "cuku", "artifact2", "SNMP_POLL")); + for (ArtifactInfo deploymentArtifact : deploymentArtifactList) { + DeploymentArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(deploymentArtifact, new UploadArtifactPopup(true)); + } + assertTrue("artifact table does not contain artifacts uploaded", DeploymentArtifactPage.checkElementsCountInTable(deploymentArtifactList.size())); + + // 3. Check-in VF. + ResourceGeneralPage.clickCheckinButton(resourceMetaData.getName()); + + // 4. Create service. + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + // 5. Click on composition. + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + // 6. Drag created DataProvider s to canvas. + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(resourceMetaData.getName()); + CanvasElement resourceInstance = canvasManager.createElementOnCanvas(resourceMetaData.getName()); + + // 7. Click on DataProvider resource. + canvasManager.clickOnCanvaElement(resourceInstance); + + // 8. Click on deployment artifacts in right menu. + CompositionPage.showDeploymentArtifactTab(); + + // 9. Verify that each uploaded MIBs artifacts shows in deployment artifacts. + // 10. Verify that only have download option. + for (ArtifactInfo deploymentArtifact : deploymentArtifactList) { + // Hover over webelement -> check that only dowload button displayed + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_DISPLAY_NAME.getValue() + deploymentArtifact.getArtifactLabel()); + Assert.assertEquals(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DOWNLOAD.getValue() + deploymentArtifact.getArtifactLabel()).isDisplayed(), true); + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DELETE.getValue() + deploymentArtifact.getArtifactLabel()), false); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_DISPLAY_NAME.getValue() + deploymentArtifact.getArtifactLabel()); + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.ArtifactPopup.MODAL_WINDOW.getValue()), false); + } + } + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/MobProxy.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/MobProxy.java new file mode 100644 index 0000000000..179c300a18 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/MobProxy.java @@ -0,0 +1,144 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import java.io.File; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.util.List; + +import java.net.Proxy; + +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.remote.CapabilityType; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.github.markusbernhardt.proxy.ProxySearch; +import com.github.markusbernhardt.proxy.ProxySearch.Strategy; + +import net.lightbody.bmp.BrowserMobProxyServer; +import net.lightbody.bmp.client.ClientUtil; +import net.lightbody.bmp.core.har.Har; +import net.lightbody.bmp.proxy.CaptureType; + +public class MobProxy { + public static WebDriver driver; + public static BrowserMobProxyServer server; + + @BeforeClass + public void setup() throws Exception { + + ProxySearch proxySearch = new ProxySearch(); + proxySearch.addStrategy(Strategy.OS_DEFAULT); + proxySearch.addStrategy(Strategy.JAVA); + proxySearch.addStrategy(Strategy.BROWSER); + ProxySelector proxySelector = proxySearch.getProxySelector(); + + ProxySelector.setDefault(proxySelector); + URI home = URI.create("http://www.google.com"); + System.out.println("ProxySelector: " + proxySelector); + System.out.println("URI: " + home); + List proxyList = proxySelector.select(home); + String host = null; + String port = null; + if (proxyList != null && !proxyList.isEmpty()) { + for (Proxy proxy : proxyList) { + System.out.println(proxy); + SocketAddress address = proxy.address(); + if (address instanceof InetSocketAddress) { + host = ((InetSocketAddress) address).getHostName(); + port = Integer.toString(((InetSocketAddress) address).getPort()); + System.setProperty("http.proxyHost", host); + System.setProperty("http.proxyPort", port); + } + } + } + + server = new BrowserMobProxyServer(); + InetSocketAddress address = new InetSocketAddress(host, Integer.parseInt(port)); + server.setChainedProxy(address); + server.start(); + int port1 = server.getPort(); + DesiredCapabilities seleniumCapabilities = new DesiredCapabilities(); + seleniumCapabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true); + seleniumCapabilities.setCapability(CapabilityType.PROXY, ClientUtil.createSeleniumProxy(server)); + driver = new FirefoxDriver(seleniumCapabilities); + server.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT); + System.out.println("Port started:" + port1); + } + + @Test + public void first_test1() throws InterruptedException { + + server.newHar("asdc.har"); + + driver.get("https://www.e-access.att.com/QA-SCRUM1/sdc1/portal#/dashboard"); + driver.manage().window().maximize(); + + WebElement userNameTextbox = driver.findElement(By.name("userid")); + userNameTextbox.sendKeys("m99121"); + WebElement passwordTextbox = driver.findElement(By.name("password")); + passwordTextbox.sendKeys("66-Percent"); + + WebElement submitButton = driver.findElement(By.name("btnSubmit")); + submitButton.click(); + Thread.sleep(300); + WebElement buttonOK = driver.findElement(By.name("successOK")); + AssertJUnit.assertTrue(buttonOK.isDisplayed()); + buttonOK.click(); + Thread.sleep(2000); + driver.findElement(By.xpath(getXpath("main-menu-button-catalog"))).click(); + Thread.sleep(2000); + driver.findElement(By.xpath(getXpath("checkbox-service"))).click(); + Thread.sleep(2000); + } + + public static String getXpath(String dataTestId){ + return String.format("//*[@data-tests-id='%s']", dataTestId); + } + + @AfterClass + public void shutdown() { + try { + + // Get the HAR data + Har har = server.getHar(); + File harFile = new File("C:\\temp\\asdc.har"); + har.writeTo(harFile); + + } catch (IOException ioe) { + ioe.printStackTrace(); + } + driver.quit(); + server.stop(); + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/NewArtifactTypeGuide.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/NewArtifactTypeGuide.java new file mode 100644 index 0000000000..9d460b0b0c --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/NewArtifactTypeGuide.java @@ -0,0 +1,123 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import static org.testng.AssertJUnit.assertTrue; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.TopMenuButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.InformationalArtifactPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.UploadArtifactPopup; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.testng.Assert; +import org.testng.annotations.Test; + + +public class NewArtifactTypeGuide extends SetupCDTest { + + private String folder =""; + + // US820276 + // Upload information artifact of type GUIDE to VF + @Test + public void crudGuideInformationArtifactForVf() throws Exception { + String filePath = FileHandling.getFilePath(folder); + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(resourceMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + ArtifactInfo informationArtifact = new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "GUIDE"); + + InformationalArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(informationArtifact); + + assertTrue("Only created artifact need to be exist", DeploymentArtifactPage.checkElementsCountInTable(1)); + + String artifactUUID = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.UUID.getValue() + informationArtifact.getArtifactLabel()).getText(); + ArtifactUIUtils.validateExistArtifactOnDeploymentInformationPage(informationArtifact.getArtifactLabel(), null, "1", informationArtifact.getArtifactType(), true, true, true, false); + + InformationalArtifactPage.clickEditArtifact(informationArtifact.getArtifactLabel()); + UploadArtifactPopup artifactPopup = new UploadArtifactPopup(); + artifactPopup.loadFile(filePath, "CP.yml"); + artifactPopup.clickDoneButton(); + + assertTrue("Only updated artifact need to be exist", DeploymentArtifactPage.checkElementsCountInTable(1)); + Assert.assertNotEquals(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.UUID.getValue() + informationArtifact.getArtifactLabel()).getText(), artifactUUID); + ArtifactUIUtils.validateExistArtifactOnDeploymentInformationPage(informationArtifact.getArtifactLabel(), null, "2", informationArtifact.getArtifactType(), true, true, true, false); + + InformationalArtifactPage.clickDeleteArtifact(informationArtifact.getArtifactLabel()); + InformationalArtifactPage.clickOK(); + } + + // US820276 + // Upload information artifact of type GUIDE to VFC + @Test + public void crudGuideInformationArtifactForVfc() throws Exception { + String filePath = FileHandling.getFilePath(folder); + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VFC, getUser()); + ResourceUIUtils.importVfc(resourceMetaData, filePath, "guidevFW_VFC.yml", getUser()); + + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + ArtifactInfo informationArtifact = new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "GUIDE"); + + InformationalArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(informationArtifact); + + assertTrue("Only created artifact need to be exist", DeploymentArtifactPage.checkElementsCountInTable(1)); + String artifactUUID = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.UUID.getValue() + informationArtifact.getArtifactLabel()).getText(); + ArtifactUIUtils.validateExistArtifactOnDeploymentInformationPage(informationArtifact.getArtifactLabel(), null, "1", informationArtifact.getArtifactType(), true, true, true, false); + + InformationalArtifactPage.clickEditArtifact(informationArtifact.getArtifactLabel()); + UploadArtifactPopup artifactPopup = new UploadArtifactPopup(); + artifactPopup.loadFile(filePath, "CP.yml"); + artifactPopup.clickDoneButton(); + + assertTrue("Only updated artifact need to be exist", DeploymentArtifactPage.checkElementsCountInTable(1)); + Assert.assertNotEquals(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.UUID.getValue() + informationArtifact.getArtifactLabel()).getText(), artifactUUID); + ArtifactUIUtils.validateExistArtifactOnDeploymentInformationPage(informationArtifact.getArtifactLabel(), null, "2", informationArtifact.getArtifactType(), true, true, true, false); + + InformationalArtifactPage.clickDeleteArtifact(informationArtifact.getArtifactLabel()); + InformationalArtifactPage.clickOK(); + } + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/RemoveRestrictionOfDeploymentArtifacts.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/RemoveRestrictionOfDeploymentArtifacts.java new file mode 100644 index 0000000000..1f85ec21fb --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/RemoveRestrictionOfDeploymentArtifacts.java @@ -0,0 +1,117 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.TopMenuButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.InformationalArtifactPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.TesterOperationPage; +import org.openecomp.sdc.ci.tests.pages.UploadArtifactPopup; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.testng.annotations.Test; + + +public class RemoveRestrictionOfDeploymentArtifacts extends SetupCDTest { + + private String folder =""; + + // US833330 - Story [BE] - remove restriction of deployment artifacts + // Create service without resource instance and without deployment artifacts and verify it can submit for testing + @Test + public void createServiceWithoutRIAndArtifacts() throws Exception { + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(serviceMetadata.getName()); + } + + + // US833330 - Story [BE] - remove restriction of deployment artifacts + // Create service with VL resource instance and without deployment artifacts and verify it can submit for testing + @Test + public void createServiceWithVlAndWithoutArtfiacts() throws Exception { + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + canvasManager.createElementOnCanvas(LeftPanelCanvasItems.NETWORK); + canvasManager.createElementOnCanvas(LeftPanelCanvasItems.NETWORK); + canvasManager.createElementOnCanvas(LeftPanelCanvasItems.NETWORK); + + ResourceGeneralPage.clickSubmitForTestingButton(serviceMetadata.getName()); + } + + // US833330 - Story [BE] - remove restriction of deployment artifacts + // Create service with VF with informational artifacts and verify it can submit for testing + @Test + public void createServiceWithInformationalArtifacts() throws Exception { + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(resourceMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + String filePath = FileHandling.getFilePath(folder); + List informationalArtifactList = new ArrayList(); + informationalArtifactList.add(new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER")); + informationalArtifactList.add(new ArtifactInfo(filePath, "sample-xml-alldata-1-1.xml", "cuku", "artifact2", "GUIDE")); + for (ArtifactInfo informationalArtifact : informationalArtifactList) { + InformationalArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(informationalArtifact, new UploadArtifactPopup(true)); + } + ResourceGeneralPage.clickSubmitForTestingButton(resourceMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(resourceMetaData.getName()); + TesterOperationPage.certifyComponent(resourceMetaData.getName()); + reloginWithNewRole(UserRoleEnum.DESIGNER); + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement resourceInstance = canvasManager.createElementOnCanvas(resourceMetaData.getName()); + + ResourceGeneralPage.clickSubmitForTestingButton(serviceMetadata.getName()); + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Service_Tests_UI.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Service_Tests_UI.java new file mode 100644 index 0000000000..80801afafb --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Service_Tests_UI.java @@ -0,0 +1,107 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.StepsEnum; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.sanity.Onboard; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.testng.annotations.Test; + +import com.clearspring.analytics.util.Pair; + +public class Service_Tests_UI extends SetupCDTest{ + + public Service_Tests_UI() { + // TODO Auto-generated constructor stub + } + + // US839610 - E2E Declare VL / CP properties as inputs in service level + @Test + public void declareVL_CP_InputsInServiceLevel() throws Exception { + String vnfFile = "FDNT.zip"; + Pair> VspName =OnboardingUtils.onboardAndValidate(Onboard.getFilePath(), vnfFile, getUser()); + ServiceReqDetails servicemetadata = ElementFactory.getDefaultService(getUser()); + ServiceUIUtils.createService(servicemetadata, getUser()); + GeneralUIUtils.moveToStep(StepsEnum.COMPOSITION); + CanvasManager service_CanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(VspName.left); + GeneralUIUtils.waitForLoader(); + CanvasElement vfi_Element = service_CanvasManager.createElementOnCanvas(VspName.left); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtonsFromInsideFrame.HOME_BUTTON.getValue()) + .click(); + GeneralUIUtils.findComponentAndClick(servicemetadata.getName()); + GeneralUIUtils.moveToStep(StepsEnum.INPUTS); + GeneralUIUtils.getWebElementByTestID("inputs-vf-instance-1").click(); +// GeneralUIUtils.onNameClicked(input); + } + @Test + public void CreateServiceWithCpInstance() throws Exception { + String vnfFile = "FDNT.zip"; + Pair> VspName =OnboardingUtils.onboardAndValidate(Onboard.getFilePath(), vnfFile, getUser()); + ServiceReqDetails servicemetadata = ElementFactory.getDefaultService(getUser()); + ServiceUIUtils.createService(servicemetadata, getUser()); + GeneralUIUtils.moveToStep(StepsEnum.COMPOSITION); + CanvasManager service_CanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(VspName.left); + GeneralUIUtils.waitForLoader(); + CanvasElement vfi_Element = service_CanvasManager.createElementOnCanvas(VspName.left); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtonsFromInsideFrame.HOME_BUTTON.getValue()) + .click(); + GeneralUIUtils.findComponentAndClick(servicemetadata.getName()); + GeneralUIUtils.moveToStep(StepsEnum.DEPLOYMENT_VIEW); + String version = GeneralUIUtils.getWebElementByTestID("versionHeader").getText(); + RestResponse service = ServiceRestUtils.getServiceByNameAndVersion(getUser(), servicemetadata.getName(), + version.substring(1)); + List serviceResponseArray = new ArrayList(); + serviceResponseArray =LocalGeneralUtilities.getValuesFromJsonArray(service); + servicemetadata.setUniqueId(serviceResponseArray.get(0)); + RestResponse serviceResponse = ServiceRestUtils.getService(servicemetadata, getUser()); + if (serviceResponseArray.get(0).contains("VL")) { + System.out.println("OK"); + } + + } + + @Override + protected UserRoleEnum getRole() { + // TODO Auto-generated method stub + return UserRoleEnum.DESIGNER; + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Testing.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Testing.java new file mode 100644 index 0000000000..089ad9580f --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Testing.java @@ -0,0 +1,125 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaDefinition; +import org.openecomp.sdc.ci.tests.utils.ToscaParserUtils; +import org.testng.Assert; + + + + + + +public class Testing { + + public static void main(String[] args) throws Exception { + // TODO Auto-generated method stub + + File path = new File("C:\\Users\\rp955r\\Desktop\\US\\US831517\\TCExport\\TC1459238.yml"); + ToscaDefinition toscaDefinition = ToscaParserUtils.parseToscaYamlToJavaObject(path); + + Map vl_us831517_1 = new HashMap(); + vl_us831517_1.put("property_1", true); + vl_us831517_1.put("property_2", "init_value_2"); + vl_us831517_1.put("property_3", "init_value_3"); + + + Map vl_us831517_2 = new HashMap(); + vl_us831517_2.put("property_1", false); + vl_us831517_2.put("property_2", "init_value_2"); + vl_us831517_2.put("property_3", "new_value_3"); + + Map vl_us831517_3 = new HashMap(); + vl_us831517_3.put("property_1", true); + vl_us831517_3.put("property_2", "init_value_2"); + vl_us831517_3.put("property_3", "init_value_3"); + vl_us831517_3.put("property_4", false); + vl_us831517_3.put("property_5", "init_value_5"); + + Map> predefinedProperties = new HashMap>(); + predefinedProperties.put("VL_US831517_1", vl_us831517_1); + predefinedProperties.put("VL_US831517_2", vl_us831517_2); + predefinedProperties.put("VL_US831517_3", vl_us831517_3); + + validateNodeTemplatesProperties(predefinedProperties, toscaDefinition); + + + + } + + + + private static void validateNodeTemplatesProperties(Map> predefinedMap, ToscaDefinition toscaDefinition) { + + for(String key: predefinedMap.keySet()) { + Map nodeTemplateProperties = getNodeTemplatePropertiesByNodeTemplateType(key, toscaDefinition); + + predefinedMap.get(key).forEach((i,j) -> { + Assert.assertEquals(nodeTemplateProperties.get(i), j, "Expected that the properties will be equal"); + }); + } + + } + + // Get properties by type + private static Map getNodeTemplatePropertiesByNodeTemplateType(String nodeTemplateType, ToscaDefinition toscaDefinition) { + Map propertiesMap = null; + + Set nodeTemplates = getNodeTemplates(toscaDefinition); + + for(String nodeTemplate: nodeTemplates) { + String currentNodeTemplateType = getNodeTemplateType(toscaDefinition, nodeTemplate); + currentNodeTemplateType = currentNodeTemplateType.substring(currentNodeTemplateType.lastIndexOf(".") + 1); + if(currentNodeTemplateType.equals(nodeTemplateType)) { + propertiesMap = getNodeTemplateProperties(toscaDefinition, nodeTemplate); + break; + } + } + + return propertiesMap; + } + + // Get node templates + private static Set getNodeTemplates(ToscaDefinition toscaDefinition) { + Set resourceInstanceArray = toscaDefinition.getTopology_template().getNode_templates().keySet(); + return resourceInstanceArray; + } + + // Get type of node template + private static String getNodeTemplateType(ToscaDefinition toscaDefinition, String nodeTemplate) { + return toscaDefinition.getTopology_template().getNode_templates().get(nodeTemplate).getType(); + } + + // Get properties of node template + private static Map getNodeTemplateProperties(ToscaDefinition toscaDefinition, String nodeTemplate) { + Map propertiesMap = toscaDefinition.getTopology_template().getNode_templates().get(nodeTemplate).getProperties(); + return propertiesMap; + } + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/VfModule.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/VfModule.java new file mode 100644 index 0000000000..a038c284e1 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/VfModule.java @@ -0,0 +1,156 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import static org.testng.AssertJUnit.assertNotNull; + +import java.awt.AWTException; +import java.io.File; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.TypeHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.ToscaArtifactsScreenEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.devCI.ArtifactFromCsar; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.ServiceGeneralPage; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaDefinition; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.DownloadManager; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.CsarParserUtils; +import org.openecomp.sdc.ci.tests.utils.ToscaParserUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.verificator.ServiceVerificator; +import org.openecomp.sdc.ci.tests.verificator.VfModuleVerificator; +import org.testng.annotations.Test; + +import com.clearspring.analytics.util.Pair; +import com.aventstack.extentreports.Status; + +/** + * @author al714h + * + */ + +public class VfModule extends SetupCDTest { + + + @Test + public void checkVfModulesCountAndStructure() throws Exception, AWTException { + +// String filepath = "src\\main\\resources\\Files\\VNFs"; + String filepath = FileHandling.getVnfRepositoryPath(); +// String vnfFile = "LDSA.zip"; + String vnfFile = "FDNT.zip"; + getExtendTest().log(Status.INFO, String.format("Going to onboard the VNF %s......", vnfFile)); + System.out.println(String.format("Going to onboard the VNF %s......", vnfFile)); + + OnboardingUtils.createVendorLicense(getUser()); + Pair> createVendorSoftwareProduct = OnboardingUtils.createVendorSoftwareProduct(vnfFile, filepath, getUser()); + String vspName = createVendorSoftwareProduct.left; + // + DownloadManager.downloadCsarByNameFromVSPRepository(vspName, createVendorSoftwareProduct.right.get("vspId")); + File latestFilefromDir = FileHandling.getLastModifiedFileFromDir(); + List listTypeHeatMetaDefinition = CsarParserUtils.getListTypeHeatMetaDefinition(latestFilefromDir); + // + getExtendTest().log(Status.INFO, String.format("Searching for onboarded %s", vnfFile)); + HomePage.showVspRepository(); + getExtendTest().log(Status.INFO, String.format("Going to import %s......", vnfFile.substring(0, vnfFile.indexOf(".")))); + + OnboardingUtils.importVSP(createVendorSoftwareProduct); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + // Verify deployment artifacts + Map combinedMap = ArtifactFromCsar.combineHeatArtifacstWithFolderArtifacsToMap(latestFilefromDir.getAbsolutePath()); + LinkedList deploymentArtifacts = ((LinkedList) combinedMap.get("Deployment")); + for(HeatMetaFirstLevelDefinition deploymentArtifact: deploymentArtifacts) { + if(deploymentArtifact.getType().equals("HEAT_ENV")) { + continue; + } + System.out.println("--------------"); + System.out.println(deploymentArtifact.getFileName()); + System.out.println(deploymentArtifact.getType()); +// System.out.println(deploymentArtifact.getFileName().trim().substring(0, deploymentArtifact.getFileName().lastIndexOf("."))); + if(deploymentArtifact.getFileName().contains(".")) { + ArtifactUIUtils.validateArtifactNameVersionType(deploymentArtifact.getFileName().trim().substring(0, deploymentArtifact.getFileName().lastIndexOf(".")), "1", deploymentArtifact.getType()); + } else { + ArtifactUIUtils.validateArtifactNameVersionType(deploymentArtifact.getFileName().trim(), "1", deploymentArtifact.getType()); + } + + } + + DeploymentArtifactPage.verifyArtifactsExistInTable(filepath, vnfFile); + + DeploymentArtifactPage.clickSubmitForTestingButton(vspName); + + // create service + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ServiceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CompositionPage.searchForElement(vspName); + CanvasManager serviceCanvasManager = CanvasManager.getCanvasManager(); + CanvasElement vfElement = serviceCanvasManager.createElementOnCanvas(vspName); + assertNotNull(vfElement); + ServiceVerificator.verifyNumOfComponentInstances(serviceMetadata, "0.1", 1, getUser()); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + ResourceGeneralPage.getLeftMenu().moveToToscaArtifactsScreen(); + GeneralUIUtils.clickOnElementByTestId(ToscaArtifactsScreenEnum.TOSCA_TEMPLATE.getValue()); + latestFilefromDir = FileHandling.getLastModifiedFileFromDir(); + +// verification + Service service = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, serviceMetadata.getName(), serviceMetadata.getVersion()); + ToscaDefinition toscaDefinition = ToscaParserUtils.parseToscaYamlToJavaObject(latestFilefromDir); + +// compare number of vf modules defined in HEAT.meta file vs Service TOSCA yaml + VfModuleVerificator.compareNumberOfVfModules(listTypeHeatMetaDefinition, toscaDefinition); + VfModuleVerificator.verifyGroupMetadata(toscaDefinition, service); + + getExtendTest().log(Status.INFO, String.format("Onboarding %s test is passed ! ", vnfFile)); + + } + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Vf_Tests_UI.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Vf_Tests_UI.java new file mode 100644 index 0000000000..71c2612a82 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/US/Vf_Tests_UI.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.US; + +import java.awt.AWTException; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.ArtifactPageEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.StepsEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.sanity.Onboard; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.verificator.VfVerificator; +import org.openqa.selenium.WebElement; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class Vf_Tests_UI extends SetupCDTest{ + + public Vf_Tests_UI() { + // TODO Auto-generated constructor stub + } + public void uploadHeatEnvVFLevel() throws Exception { + + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + } + +// @Test +// // Download ENV file from VF level. +// public void downloadEnvVFLevel() throws AWTException, Exception { +// String firstEnvArtifact = "base_stsi_dnt_frwl.env"; +// String secondEnvArtifact = "mod_vmsi_dnt_fw_parent.env"; +// String filePath=Config.instance().getWindowsDownloadDirectory(); +// String vnfFile = "FDNT.zip"; +// OnboardingUtils.onboardAndValidate(Onboard.getFilePath(), vnfFile, getUser()); +// Map mD5OfFilesToValidate = new HashMap(); +// mD5OfFilesToValidate.put(firstEnvArtifact,new File(FileHandling.getResourcesEnvFilesPath() + firstEnvArtifact)); +// mD5OfFilesToValidate.put(secondEnvArtifact,new File(FileHandling.getResourcesEnvFilesPath() + secondEnvArtifact)); +// ListfilesToBeDeleted=new ArrayList<>(mD5OfFilesToValidate.values()); +// FileHandling.deleteLastDowloadedFiles(filesToBeDeleted); +// ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); +// List allDisplayedArtifcats = DeploymentArtifactPage.getDeploymentArtifactsNamesWorkSpace(); +// for (int i=0;i assetsName = importThreeAsset(fileName_vl1, fileName_vl2, fileName_vl3, resourceTypeEnum); + + if(ComponentTypeEnum.SERVICE == componentTypeEnum) { + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + } else { + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(resourceMetaData, getUser()); + } + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement resourceInstance1 = canvasManager.createElementOnCanvas(assetsName.get(0)); + CanvasElement resourceInstance2 = canvasManager.createElementOnCanvas(assetsName.get(1)); + CanvasElement resourceInstance3 = canvasManager.createElementOnCanvas(assetsName.get(2)); + + canvasManager.clickOnCanvaElement(resourceInstance1); + CompositionPage.showPropertiesAndAttributesTab(); + PropertiesUIUtils.changePropertyDefaultValueInComposition("property_1", "false"); + + canvasManager.clickOnCanvaElement(resourceInstance2); + CompositionPage.showPropertiesAndAttributesTab(); + PropertiesUIUtils.changePropertyDefaultValueInComposition("property_3", "customize"); + + canvasManager.clickOnCanvaElement(resourceInstance3); + CompositionPage.showPropertiesAndAttributesTab(); + PropertiesUIUtils.changePropertyDefaultValueInComposition("property_2", "customize derived"); + PropertiesUIUtils.changePropertyDefaultValueInComposition("property_5", "customize new"); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + ResourceGeneralPage.getLeftMenu().moveToToscaArtifactsScreen(); + GeneralUIUtils.clickOnElementByTestId(ToscaArtifactsScreenEnum.TOSCA_TEMPLATE.getValue()); + + // TODO: Replace it by automatic download to path + // TODO: After it remove + File path = new File("C:\\Users\\rp955r\\Desktop\\US\\US831517\\TCExport\\TC1459238.yml"); + ToscaDefinition toscaDefinition = ToscaParserUtils.parseToscaYamlToJavaObject(path); + + Map vl_us831517_1 = new HashMap(); + vl_us831517_1.put("property_1", false); + vl_us831517_1.put("property_2", "init_value_2"); + vl_us831517_1.put("property_3", "init_value_3"); + + + Map vl_us831517_2 = new HashMap(); + vl_us831517_2.put("property_1", false); + vl_us831517_2.put("property_2", "init_value_2"); + vl_us831517_2.put("property_3", "customize"); + + Map vl_us831517_3 = new HashMap(); + vl_us831517_3.put("property_1", true); + vl_us831517_3.put("property_2", "customize derived"); + vl_us831517_3.put("property_3", "init_value_3"); + vl_us831517_3.put("property_4", false); + vl_us831517_3.put("property_5", "customize new"); + + Map> predefinedProperties = new HashMap>(); + predefinedProperties.put("VL_US831517_1", vl_us831517_1); + predefinedProperties.put("VL_US831517_2", vl_us831517_2); + predefinedProperties.put("VL_US831517_3", vl_us831517_3); + + validateNodeTemplatesProperties(predefinedProperties, toscaDefinition); + + RestCDUtils.deleteOnDemand(); + } + + @DataProvider(name="serviceVfUsedVlsCps") + public static Object[][] dataProviderServiceVfUsedVlsCps() { + return new Object[][] { + {"VL_US831517_1.yml", "VL_US831517_2.yml", "VL_US831517_3.yml", ResourceTypeEnum.VL, ComponentTypeEnum.SERVICE}, + {"CP_US831517_1.yml", "CP_US831517_2.yml", "CP_US831517_3.yml", ResourceTypeEnum.CP, ComponentTypeEnum.SERVICE}, + {"VL_US831517_1.yml", "VL_US831517_2.yml", "VL_US831517_3.yml", ResourceTypeEnum.VL, ComponentTypeEnum.RESOURCE}, + {"CP_US831517_1.yml", "CP_US831517_2.yml", "CP_US831517_3.yml", ResourceTypeEnum.CP, ComponentTypeEnum.RESOURCE}, + }; + } + + + // US831517 - Story [BE] - Extend node_template properties with default values + @Test(dataProvider="serviceVfUsedVlsCps") + public void serviceVfUsedVlsCps(String fileName_vl1, String fileName_vl2, String fileName_vl3, ResourceTypeEnum resourceTypeEnum, ComponentTypeEnum componentTypeEnum) throws Exception { + setLog("Extend node_template properties with default values"); + + // import Resource + LinkedList assetsName = importThreeAsset(fileName_vl1, fileName_vl2, fileName_vl3, resourceTypeEnum); + + if(ComponentTypeEnum.SERVICE == componentTypeEnum) { + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + } else { + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(resourceMetaData, getUser()); + } + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + canvasManager.createElementOnCanvas(assetsName.get(0)); + canvasManager.createElementOnCanvas(assetsName.get(1)); + canvasManager.createElementOnCanvas(assetsName.get(2)); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + ResourceGeneralPage.getLeftMenu().moveToToscaArtifactsScreen(); + GeneralUIUtils.clickOnElementByTestId(ToscaArtifactsScreenEnum.TOSCA_TEMPLATE.getValue()); + + // TODO: Replace it by automatic download to path + // TODO: After it remove + File path = new File("C:\\Users\\rp955r\\Desktop\\US\\US831517\\TCExport\\TC1459238.yml"); + ToscaDefinition toscaDefinition = ToscaParserUtils.parseToscaYamlToJavaObject(path); + + Map vl_us831517_1 = new HashMap(); + vl_us831517_1.put("property_1", true); + vl_us831517_1.put("property_2", "init_value_2"); + vl_us831517_1.put("property_3", "init_value_3"); + + + Map vl_us831517_2 = new HashMap(); + vl_us831517_2.put("property_1", false); + vl_us831517_2.put("property_2", "init_value_2"); + vl_us831517_2.put("property_3", "new_value_3"); + + Map vl_us831517_3 = new HashMap(); + vl_us831517_3.put("property_1", true); + vl_us831517_3.put("property_2", "init_value_2"); + vl_us831517_3.put("property_3", "init_value_3"); + vl_us831517_3.put("property_4", false); + vl_us831517_3.put("property_5", "init_value_5"); + + Map> predefinedProperties = new HashMap>(); + predefinedProperties.put("VL_US831517_1", vl_us831517_1); + predefinedProperties.put("VL_US831517_2", vl_us831517_2); + predefinedProperties.put("VL_US831517_3", vl_us831517_3); + + validateNodeTemplatesProperties(predefinedProperties, toscaDefinition); + + RestCDUtils.deleteOnDemand(); + } + + private LinkedList importThreeAsset(String fileName_vl1, String fileName_vl2, String fileName_vl3, ResourceTypeEnum resourceTypeEnum) throws Exception { + LinkedList assetsNames = new LinkedList(); + + String filePath = System.getProperty("filepath"); + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath() + File.separator + "US831517" + File.separator; + } + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator + "US831517" + File.separator; + } + + // import Resource + ResourceReqDetails resourceMetaDataVl1 = ElementFactory.getDefaultResourceByType(resourceTypeEnum, getUser()); + assetsNames.add(resourceMetaDataVl1.getName()); + ResourceUIUtils.importVfc(resourceMetaDataVl1, filePath, fileName_vl1, getUser()); + GeneralPageElements.clickSubmitForTestingButton(resourceMetaDataVl1.getName()); + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(resourceMetaDataVl1.getName()); + TesterOperationPage.certifyComponent(resourceMetaDataVl1.getName()); + reloginWithNewRole(UserRoleEnum.DESIGNER); + + ResourceReqDetails resourceMetaDataVl2 = ElementFactory.getDefaultResourceByType(resourceTypeEnum, getUser()); + assetsNames.add(resourceMetaDataVl2.getName()); + ResourceUIUtils.importVfc(resourceMetaDataVl2, filePath, fileName_vl2, getUser()); + GeneralPageElements.clickCheckinButton(resourceMetaDataVl2.getName()); + + ResourceReqDetails resourceMetaDataVl3 = ElementFactory.getDefaultResourceByType(resourceTypeEnum, getUser()); + assetsNames.add(resourceMetaDataVl3.getName()); + ResourceUIUtils.importVfc(resourceMetaDataVl3, filePath, fileName_vl3, getUser()); + GeneralPageElements.clickCheckinButton(resourceMetaDataVl2.getName()); + + return assetsNames; + } + + + private static void validateNodeTemplatesProperties(Map> predefinedMap, ToscaDefinition toscaDefinition) { + + for(String key: predefinedMap.keySet()) { + Map nodeTemplateProperties = getNodeTemplatePropertiesByNodeTemplateType(key, toscaDefinition); + + predefinedMap.get(key).forEach((i,j) -> { + Assert.assertEquals(nodeTemplateProperties.get(i), j, "Expected that the properties will be equal"); + }); + } + + } + + // Get properties by type + private static Map getNodeTemplatePropertiesByNodeTemplateType(String nodeTemplateType, ToscaDefinition toscaDefinition) { + Map propertiesMap = null; + + Set nodeTemplates = getNodeTemplates(toscaDefinition); + + for(String nodeTemplate: nodeTemplates) { + String currentNodeTemplateType = getNodeTemplateType(toscaDefinition, nodeTemplate); + currentNodeTemplateType = currentNodeTemplateType.substring(currentNodeTemplateType.lastIndexOf(".") + 1); + if(currentNodeTemplateType.equals(nodeTemplateType)) { + propertiesMap = getNodeTemplateProperties(toscaDefinition, nodeTemplate); + break; + } + } + + return propertiesMap; + } + + // Get node templates + private static Set getNodeTemplates(ToscaDefinition toscaDefinition) { + Set resourceInstanceArray = toscaDefinition.getTopology_template().getNode_templates().keySet(); + return resourceInstanceArray; + } + + // Get type of node template + private static String getNodeTemplateType(ToscaDefinition toscaDefinition, String nodeTemplate) { + return toscaDefinition.getTopology_template().getNode_templates().get(nodeTemplate).getType(); + } + + // Get properties of node template + private static Map getNodeTemplateProperties(ToscaDefinition toscaDefinition, String nodeTemplate) { + Map propertiesMap = toscaDefinition.getTopology_template().getNode_templates().get(nodeTemplate).getProperties(); + return propertiesMap; + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/businesslogic/ArtifactBusinessLogic.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/businesslogic/ArtifactBusinessLogic.java new file mode 100644 index 0000000000..6dce83fd40 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/businesslogic/ArtifactBusinessLogic.java @@ -0,0 +1,208 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.businesslogic; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.openecomp.sdc.be.datatypes.elements.HeatParameterDataDefinition; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.ci.tests.datatypes.HeatAndHeatEnvNamesPair; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.HeatWithParametersDefinition; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.execute.devCI.ArtifactFromCsar; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; + +import com.clearspring.analytics.util.Pair; + +public class ArtifactBusinessLogic { + + private final static String[] okFileExtensions = new String[] {"yaml", "yml", "env"}; + private static final String PARAMETERS = "parameters"; + private static final String DEPLOYMENT = "Deployment"; + + public static synchronized Map createEnvFilesListFromCsar(String vspName, String filePath) throws Exception{ + Map generatedEnvFiles = new HashMap<>(); + File csarFile= HomePage.downloadVspCsarToDefaultDirectory(vspName); + FileHandling.unzip(csarFile.toString(), filePath); + List yamlList = getHeatFilesCreatedFromCsar(csarFile, filePath); + Map filesPairMap = getFilesPairMap(yamlList); + generatedEnvFiles = generateDefaultEnvFiles(filesPairMap, filePath); + return generatedEnvFiles; + } + + public static synchronized List getHeatFilesCreatedFromCsar(File pathToDirectory, String filePath) throws Exception { + List fileList = new ArrayList<>(); + String artifactsFilePath = filePath + "Artifacts" + File.separator; + List fileListFromArtifactsDirectory = FileHandling.getHeatAndHeatEnvArtifactsFromZip(new File(artifactsFilePath), okFileExtensions); + Map combinedMap = ArtifactFromCsar.combineHeatArtifacstWithFolderArtifacsToMap(pathToDirectory.toString()); + LinkedList deploymentArtifacts = ((LinkedList) combinedMap.get(DEPLOYMENT)); + for(HeatMetaFirstLevelDefinition deploymentArtifact : deploymentArtifacts){ + String type = deploymentArtifact.getType(); + if(type.equals(ArtifactTypeEnum.HEAT.getType()) || + type.equals(ArtifactTypeEnum.HEAT_ENV.getType()) || + type.equals(ArtifactTypeEnum.HEAT_VOL.getType()) || + type.equals(ArtifactTypeEnum.HEAT_NET.getType())){ + File file = (new File(artifactsFilePath + deploymentArtifact.getFileName())); + if(fileListFromArtifactsDirectory.contains(file)){ + fileList.add(file); + }else{ + assertTrue("File " + file + " does not exist", false); + } + } + } + return fileList; + } + public static synchronized Map getFilesPairMap(List generatedEnvFiles) { + + Map heatAndHeatEnvPairs= new HashMap<>(); + for(File file : generatedEnvFiles){ + String[] fileName = file.getName().split("\\."); + String currentKey = fileName[0]; + String currentExtension = fileName[1]; + HeatAndHeatEnvNamesPair pair; + if(!heatAndHeatEnvPairs.containsKey(currentKey)){ + pair = new HeatAndHeatEnvNamesPair(); + heatAndHeatEnvPairs.put(currentKey, pair); + }else{ + pair = heatAndHeatEnvPairs.get(currentKey); + } + setFileToPair(file, currentExtension, pair); + } + return heatAndHeatEnvPairs; + } + + /** + * The method fill list of HeatWithParametersDefinition parameters + * @param deploymentArtifacts + * @return + */ + public static synchronized List extractHeatWithParametersDefinition(Map deploymentArtifacts) { + + List heatAndEnvLabelList = new ArrayList<>(); + + for (Entry artifactDefinitionChild : deploymentArtifacts.entrySet()){ + if(artifactDefinitionChild.getValue().getArtifactType().equals(ArtifactTypeEnum.HEAT_ENV.getType())){ + for(Entry artifactDefinitionParent : deploymentArtifacts.entrySet()){ + if(artifactDefinitionChild.getValue().getGeneratedFromId().equals(artifactDefinitionParent.getValue().getUniqueId())){ + String heatLabel = artifactDefinitionParent.getValue().getArtifactLabel(); + String heatArtifactType = artifactDefinitionParent.getValue().getArtifactType(); + String heatArtifactDisplayName = artifactDefinitionParent.getValue().getArtifactDisplayName(); + List heatParameterDefinition = artifactDefinitionParent.getValue().getHeatParameters(); + String heatEnvLabel = artifactDefinitionChild.getValue().getArtifactLabel(); + String heatEnvArtifactType = artifactDefinitionChild.getValue().getArtifactType(); + heatAndEnvLabelList.add(new HeatWithParametersDefinition(heatLabel, heatEnvLabel, heatArtifactType, heatEnvArtifactType, heatArtifactDisplayName, heatParameterDefinition)); + break; + } + } + } + } + return heatAndEnvLabelList; + } + + + public static synchronized void setFileToPair(File file, String currentExtension, HeatAndHeatEnvNamesPair pair) { + if(!currentExtension.equals("env")){ + pair.setHeatFileName(file); + }else{ + pair.setHeatEnvFileName(file); + } + } + + public static synchronized Map generateDefaultEnvFiles(Map filesPairMap, String filePath) throws Exception { + + Map generatedEnvFilesMap = new HashMap<>(); + for(Entry pair : filesPairMap.entrySet()){ + Map> envParametersMap = getEnvParametersMap(pair); + File generatedEnvFile = createEnvFile(envParametersMap, new File(filePath + pair.getKey() + ".env")); + generatedEnvFilesMap.put(pair.getKey(), generatedEnvFile); + } + return generatedEnvFilesMap; + } + + public static synchronized File createEnvFile(Map> envParametersMap, File fileToWrite) throws IOException { + + FileHandling.writeToFile(fileToWrite, PARAMETERS+":", 0); + FileHandling.writeToFile(fileToWrite, envParametersMap, 2); + return fileToWrite; + } + + public static synchronized Map> getEnvParametersMap(Entry pair) throws Exception { + File heatFileName = pair.getValue().getHeatFileName(); + File heatEnvFileName = pair.getValue().getHeatEnvFileName(); + Map> envParametersMap = new HashMap<>(); + fillParametersMapFromHeatFile(heatFileName, envParametersMap); + fillParametersMapFromHeatEnvFile(heatEnvFileName, envParametersMap); + return envParametersMap; + } + + public static synchronized void fillParametersMapFromHeatEnvFile(File heatEnvFileName, Map> envParametersMap) throws Exception { + if(heatEnvFileName != null){ + Map mapHeatEnvFileParameters = FileHandling.parseYamlFileToMapByPattern(heatEnvFileName, PARAMETERS); + for (Map.Entry parameter : mapHeatEnvFileParameters.entrySet()){ + String key = parameter.getKey(); + Pair pair; + if(envParametersMap.containsKey(key)){ + if(envParametersMap.get(key).left.equals("string") && parameter.getValue() != null){ + pair = Pair.create(envParametersMap.get(key).left, "\"" + parameter.getValue() + "\""); + }else if(envParametersMap.get(key).left.equals("string") && parameter.getValue() == null){ + pair = Pair.create(envParametersMap.get(key).left, ""); + }else if(parameter.getValue() == null){ + pair = Pair.create(envParametersMap.get(key).left, ""); + }else{ + pair = Pair.create(envParametersMap.get(key).left, parameter.getValue()); + } + envParametersMap.put(key, pair); + } + } + } + } + + @SuppressWarnings("unchecked") + public static synchronized void fillParametersMapFromHeatFile(File heatFileName, Map> envParametersMap) throws Exception { + Map mapHeatFileParameters = FileHandling.parseYamlFileToMapByPattern(heatFileName, PARAMETERS); + for (Map.Entry parameter : mapHeatFileParameters.entrySet()){ + Map value = (Map) parameter.getValue(); + Pair pair; + if(value.get("type").toString().equals("string") && value.get("default") != null ){ + pair = Pair.create(value.get("type").toString(), "\"" + value.get("default") + "\""); + }else if(value.get("type").toString().equals("string") && value.get("default") == null){ + pair = Pair.create(value.get("type").toString(), ""); + }else if(value.get("default") == null){ + pair = Pair.create(value.get("type").toString(), ""); + }else{ + pair = Pair.create(value.get("type").toString(), value.get("default")); + } + envParametersMap.put(parameter.getKey(), pair); + } + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactInfo.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactInfo.java new file mode 100644 index 0000000000..1302cb52af --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ArtifactInfo.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class ArtifactInfo { + + private String filepath; + private String filename; + private String description; + private String artifactType; + private String artifactLabel; + private String artifactVersion; + + public ArtifactInfo(String filepath, String filename, String description, String artifactLabel, + String artifactType) { + super(); + this.filepath = filepath; + this.filename = filename; + this.description = description; + this.artifactType = artifactType; + this.artifactLabel = artifactLabel; + } + + public ArtifactInfo(String filepath, String filename, String description, String artifactLabel, + String artifactType, String artifactVersion) { + super(); + this.filepath = filepath; + this.filename = filename; + this.description = description; + this.artifactType = artifactType; + this.artifactLabel = artifactLabel; + this.artifactVersion = artifactVersion; + } + + public ArtifactInfo() { + super(); + } + + public String getArtifactVersion() { + return artifactVersion; + } + + public void setArtifactVersion(String artifactVersion) { + this.artifactVersion = artifactVersion; + } + + public String getFilepath() { + return filepath; + } + + public void setFilepath(String filepath) { + this.filepath = filepath; + } + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getArtifactType() { + return artifactType; + } + + public void setArtifactType(String artifactType) { + this.artifactType = artifactType; + } + + public String getArtifactLabel() { + return artifactLabel; + } + + public void setArtifactLabel(String artifactLabel) { + this.artifactLabel = artifactLabel; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CanvasElement.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CanvasElement.java new file mode 100644 index 0000000000..818b488d64 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CanvasElement.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; + +public final class CanvasElement { + private final String uniqueId; + private ImmutablePair location; + private LeftPanelCanvasItems normativeElementType; + private String elementType; + + CanvasElement(String name, ImmutablePair location, LeftPanelCanvasItems canvasItem) { + super(); + this.uniqueId = name; + this.location = location; + normativeElementType = canvasItem; + } + + CanvasElement(String name, ImmutablePair location, String canvasItem) { + super(); + this.uniqueId = name; + this.location = location; + elementType = canvasItem; + } + + public String getUniqueId() { + return uniqueId; + } + + public ImmutablePair getLocation() { + return location; + } + + public void setLocation(ImmutablePair location) { + this.location = location; + } + + public LeftPanelCanvasItems getNormativeElementType() { + return normativeElementType; + } + + public String getElementType() { + return elementType; + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CanvasManager.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CanvasManager.java new file mode 100644 index 0000000000..25ed4c2d91 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CanvasManager.java @@ -0,0 +1,268 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; +import org.testng.Assert; + +import com.aventstack.extentreports.Status; + +public final class CanvasManager { + private Map canvasElements; + private Actions actions; + private WebElement canvas; + private int reduceCanvasWidthFactor; + private CanvasElement canvasElement; + // Offsets Are used to find upper right corner of canvas element in order to + // connect links + private static final int CANVAS_ELEMENT_Y_OFFSET = 30; + private static final int CANVAS_ELEMENT_X_OFFSET = 18; // 14 - 27 + + private CanvasManager() { + canvasElements = new HashMap<>(); + actions = new Actions(GeneralUIUtils.getDriver()); + canvas = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralCanvasItems.CANVAS.getValue()); + try { + WebElement webElement = GeneralUIUtils + .getWebElementByTestID(DataTestIdEnum.GeneralCanvasItems.CANVAS_RIGHT_PANEL.getValue()); + reduceCanvasWidthFactor = webElement.getSize().width; + } catch (Exception e) { + reduceCanvasWidthFactor = 0; + } + } + + public static CanvasManager getCanvasManager() { + return new CanvasManager(); + } + + public List getCanvasElements() { + return canvasElements.values().stream().collect(Collectors.toList()); + } + + private void addCanvasElement(CanvasElement element) { + canvasElements.put(element.getUniqueId(), element); + } + + private void moveElementOnCanvas(CanvasElement canvasElement, ImmutablePair newLocation) + throws Exception { + GeneralUIUtils.waitForLoader(); + actions.moveToElement(canvas, canvasElement.getLocation().left, canvasElement.getLocation().right); + actions.clickAndHold(); + actions.moveToElement(canvas, newLocation.left, newLocation.right); + actions.release(); + actions.perform(); + canvasElement.setLocation(newLocation); + GeneralUIUtils.waitForLoader(); + + } + + public void moveToFreeLocation(String containerName) { + int maxWait = 5000; + int sumOfWaiting = 0; + int napPeriod = 200; + boolean isKeepWaiting = false; + while (!isKeepWaiting) { + ImmutablePair freePosition = getFreePosition(); + actions.moveToElement(canvas, freePosition.left, freePosition.right); + actions.clickAndHold(); + actions.release(); + actions.perform(); + isKeepWaiting = GeneralUIUtils.getWebElementByTestID("selectedCompTitle").getText() + .equals(containerName); + sumOfWaiting += napPeriod; + if (sumOfWaiting > maxWait) { + Assert.fail("Can't click on VF"); + } + } + } + + public void clickOnCanvaElement(CanvasElement canvasElement) { + actions.moveToElement(canvas, canvasElement.getLocation().left, canvasElement.getLocation().right); + actions.clickAndHold(); + actions.release(); + actions.perform(); + actions.click().perform(); + GeneralUIUtils.ultimateWait(); + ExtentTestActions.log(Status.INFO, String.format("Canvas element %s selected", canvasElement.getElementType())); + } + + public void moveElementOnCanvas(CanvasElement canvasElement) throws Exception { + moveElementOnCanvas(canvasElement, getFreePosition()); + } + + public void deleteElementFromCanvas(CanvasElement canvasElement) throws Exception { + GeneralUIUtils.waitForLoader(); + actions.moveToElement(canvas, canvasElement.getLocation().left, canvasElement.getLocation().right); + actions.click(); + actions.perform(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralCanvasItems.DELETE_INSTANCE_BUTTON.getValue()) + .click(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.OK.getValue()).click(); + canvasElements.remove(canvasElement.getUniqueId()); + GeneralUIUtils.ultimateWait(); + if (canvasElement.getElementType().contains("-")){ + ExtentTestActions.log(Status.INFO, String.format("Canvas element %s removed", canvasElement.getElementType().split("-")[4])); + } + else{ + ExtentTestActions.log(Status.INFO, String.format("Canvas element %s removed", canvasElement.getElementType())); + } + } + + private WebElement findClickElement(String dataTestId) { + int attempts = 0; + while (attempts < 2) { + try { + return GeneralUIUtils.getWebElementByTestID(dataTestId); + } catch (StaleElementReferenceException e) { + } + attempts++; + } + return null; + } + + public CanvasElement createElementOnCanvas(String elementName) throws Exception { + String actionDuration = GeneralUIUtils.getActionDuration(() -> { + try { + canvasElement = createElementOnCanvasWithoutDuration(elementName); + } catch (Exception e) { + e.printStackTrace(); + } + }); + + if (canvasElement != null){ + ExtentTestActions.log(Status.INFO, String.format("The element %s should now be on the canvas", elementName), actionDuration); + } + return canvasElement; + } + + private CanvasElement createElementOnCanvasWithoutDuration(String elementDataTestId) throws Exception { + try { + WebElement element = findClickElement(elementDataTestId); + ImmutablePair freePosition = getFreePosition(); + actions.moveToElement(element, 20, 20); + actions.clickAndHold(); + actions.moveToElement(canvas, freePosition.left, freePosition.right); + actions.release(); + actions.perform(); + GeneralUIUtils.ultimateWait(); + String uniqueId = elementDataTestId + "_" + UUID.randomUUID().toString(); + CanvasElement canvasElement = new CanvasElement(uniqueId, freePosition, elementDataTestId); + addCanvasElement(canvasElement); + GeneralUIUtils.ultimateWait(); + return canvasElement; + } + catch (Exception e) { + System.out.println("Can't create element on canvas"); + e.printStackTrace(); + } + return null; + } + + public CanvasElement createElementOnCanvas(LeftPanelCanvasItems canvasItem) throws Exception { + return createElementOnCanvas(canvasItem.getValue()); + } + + private ImmutablePair getFreePosition() { + ImmutablePair randomPosition = null; + boolean freePosition = false; + int minSpace = 150; + while (!freePosition) { + ImmutablePair tempRandomPosition = getRandomPosition(); + freePosition = !canvasElements.values().stream().map(e -> e.getLocation()) + .filter(e -> Math.abs(e.left - tempRandomPosition.left) < minSpace + && Math.abs(e.right - tempRandomPosition.right) < minSpace) + .findAny().isPresent(); + randomPosition = tempRandomPosition; + } + return randomPosition; + } + + private ImmutablePair getRandomPosition() { + int edgeBuffer = 50; + Random random = new Random(); + int xElement = random.nextInt(canvas.getSize().width - 2 * edgeBuffer - reduceCanvasWidthFactor) + edgeBuffer; + int yElement = random.nextInt(canvas.getSize().height - 2 * edgeBuffer) + edgeBuffer; + return new ImmutablePair(xElement, yElement); + } + + public void linkElements(CanvasElement firstElement, CanvasElement secondElement) throws Exception { + ExtentTestActions.log(Status.INFO, String.format("Linking between the %s instance and the %s instance.", firstElement.getElementType(), secondElement.getElementType())); + drawSimpleLink(firstElement, secondElement); + selectReqAndCapAndConnect(); + ExtentTestActions.log(Status.INFO, String.format("The instances %s and %s should now be connected.", firstElement.getElementType(), secondElement.getElementType())); + } + + private void selectReqAndCapAndConnect() throws Exception { + // Select First Cap + GeneralUIUtils.getWebElementsListByTestID(DataTestIdEnum.LinkMenuItems.LINK_ITEM_CAP.getValue()).get(0).click(); + // Select First Req + GeneralUIUtils.getWebElementsListByTestID(DataTestIdEnum.LinkMenuItems.LINK_ITEM_REQ.getValue()).get(0).click(); + // Connect + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.LinkMenuItems.CONNECT_BUTTON.getValue()).click(); + + GeneralUIUtils.waitForLoader(); + } + + private void drawSimpleLink(CanvasElement firstElement, CanvasElement secondElement) throws Exception { + int yOffset = CANVAS_ELEMENT_Y_OFFSET; + int xOffset = CANVAS_ELEMENT_X_OFFSET; + + actions.moveToElement(canvas, firstElement.getLocation().left + xOffset, + firstElement.getLocation().right - yOffset); + + actions.clickAndHold(); + actions.moveToElement(canvas, secondElement.getLocation().left + xOffset, secondElement.getLocation().right - yOffset); + actions.release(); + actions.perform(); + GeneralUIUtils.ultimateWait(); + } + + public String updateElementNameInCanvas(CanvasElement canvasElement, String newInstanceName) throws Exception { + GeneralUIUtils.ultimateWait();; + clickOnCanvaElement(canvasElement); + WebElement updateInstanceName = GeneralUIUtils.getWebElementBy(By.id("editPencil")); + updateInstanceName.click(); + WebElement instanceNameField = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralCanvasItems.INSTANCE_NAME_FIELD.getValue()); + String oldInstanceName = instanceNameField.getAttribute("value"); + instanceNameField.clear(); + instanceNameField.sendKeys(newInstanceName); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.OK.getValue()).click(); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.waitForElementInVisibilityByTestId(By.className("w-sdc-modal-resource-instance-name")); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Name of element instance changed from %s to %s", oldInstanceName, newInstanceName)); + return oldInstanceName; + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CatalogFilterTitlesEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CatalogFilterTitlesEnum.java new file mode 100644 index 0000000000..1335b51788 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CatalogFilterTitlesEnum.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum CatalogFilterTitlesEnum { + + TYPE("typeFilterTitle"), CATEGORIES("categoriesFilterTitle"), STATUS("statusFilterTitle"); + + private String value; + + public String getValue() { + return value; + } + + private CatalogFilterTitlesEnum(String value) { + this.value = value; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CheckBoxStatusEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CheckBoxStatusEnum.java new file mode 100644 index 0000000000..ffa17ee607 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CheckBoxStatusEnum.java @@ -0,0 +1,50 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum CheckBoxStatusEnum { + CHECKOUT("", "checkbox-checkout"), + CHECKIN("", "checkbox-checkin"), + READY_FOR_TESTING("checkbox-readyfortesting","checkbox-1"), + IN_TESTING("checkbox-intesting", "checkbox-2"), + WAITING_FOR_DISTRIBUTION("", "checkbox-waitingforapproval"), + DISTRIBUTION_REJECTED("", "checkbox-distributionrejected"), + DISTRIBUTION_APPROVED("", "checkbox-distributionapproved"), + CERTIFIED("checkbox-certified", "checkbox-3"), + DISTRIBUTED("", "checkbox-4"), + IN_DESIGN("", "checkbox-0"); + + private String value; + private String value2; + + public String getValue() { + return value; + } + + public String getCatalogValue() { + return value2; + } + + private CheckBoxStatusEnum(String value, String value2) { + this.value = value; + this.value2 = value2; + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CreateAndImportButtonsEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CreateAndImportButtonsEnum.java new file mode 100644 index 0000000000..a49c5024a6 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/CreateAndImportButtonsEnum.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum CreateAndImportButtonsEnum { + + IMPORT_VF, IMPORT_VFC, IMPORT_CP, IMPORT_VL, CREATE_VF, CREATE_SERVICE, CREATE_PRODUCT; + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/DataTestIdEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/DataTestIdEnum.java new file mode 100644 index 0000000000..ef510b8a12 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/DataTestIdEnum.java @@ -0,0 +1,835 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.Arrays; +import java.util.List; + +public final class DataTestIdEnum { + private DataTestIdEnum() { + } + + public enum Dashboard { + IMPORT_AREA("importButtonsArea"), + ADD_AREA("AddButtonsArea"), + BUTTON_ADD_VF("createResourceButton"), + BUTTON_ADD_SERVICE("createServiceButton"), + IMPORT_VFC("importVFCbutton"), + IMPORT_VF("importVFbutton"), + IMPORT_VFC_FILE("file-importVFCbutton"), + IMPORT_VF_FILE("file-importVFbutton"), + BUTTON_ADD_PRODUCT("createProductButton"); + + private String value; + + public String getValue() { + return value; + } + + private Dashboard(String value) { + this.value = value; + } + } + + public enum LifeCyleChangeButtons { + CREATE("create/save"), + CHECK_IN("check_in"), + SUBMIT_FOR_TESTING("submit_for_testing"), + START_TESTING("start_testing"), + ACCEPT("accept"), + CHECKOUT("check_out"); + + private String value; + + public String getValue() { + return value; + } + + private LifeCyleChangeButtons(String value) { + this.value = value; + } + } + + public enum DistributionChangeButtons { + APPROVE("approve"), + REJECT("reject"), + DISTRIBUTE("distribute"), + MONITOR("monitor"), + APPROVE_MESSAGE("checkindialog"), + RE_DISTRIBUTE("redistribute"); + + private String value; + + public String getValue() { + return value; + } + + private DistributionChangeButtons(String value) { + this.value = value; + } + } + + public enum InformationalArtifactsPlaceholders { + CLOUD_QUESTIONNAIRE("Cloud Questionnaire (completed)"), + FEATURES("Features"), + VENDOR_TEST_RESULT("Vendor Test Result"), + TEST_SCRIPTS("Test Scripts"), + RESOURCE_SECURITY_TEMPLATE("Resource Security Template"), + HEAT_TEMPLATE_FROM_VENDOR("HEAT Template from Vendor"), + CAPACITY("Capacity"); + + private String value; + + public String getValue() { + return value; + } + + private InformationalArtifactsPlaceholders(String value) { + this.value = value; + } + } + + public enum ModalItems { + BROWSE_BUTTON("browseButton"), + ADD("Add"), + DESCRIPTION("description"), + SUMBIT_FOR_TESTING_MESSAGE("changeLifeCycleMessage"), + OK("OK"), + CANCEL("Cancel"), + ACCEP_TESTING_MESSAGE("checkindialog"); + + private String value; + + public String getValue() { + return value; + } + + private ModalItems(String value) { + this.value = value; + } + } + + public enum LeftPanelCanvasItems { + BLOCK_STORAGE("BlockStorage"), + CINDER_VOLUME("CinderVolume"), + COMPUTE("Compute"), + LOAD_BALANCER("LoadBalancer"), + NOVA_SERVER("NovaServer"), + OBJECT_STORAGE("ObjectStorage"), + NEUTRON_PORT("NeutronPort"), + PORT("Port"), DATABASE("Database"), + NETWORK("Network"); + + private String value; + + public String getValue() { + return value; + } + + private LeftPanelCanvasItems(String value) { + this.value = value; + } + } + + public enum LinkMenuItems { + CANCEL_BUTTON("link-menu-button-cancel"), + CONNECT_BUTTON("link-menu-button-connect"), + LINK_ITEM_CAP("link-item-capabilities"), + LINK_ITEM_REQ("link-item-requirements"), + LINK_MENU("link-menu-open"); + + private String value; + + public String getValue() { + return value; + } + + private LinkMenuItems(String value) { + this.value = value; + } + } + + public enum GeneralCanvasItems { + CANVAS("canvas"), + CANVAS_RIGHT_PANEL("w-sdc-designer-sidebar-head"), + DELETE_INSTANCE_BUTTON("e-sdc-small-icon-delete"), + UPDATE_INSTANCE_NAME("e-sdc-small-icon-update"), + INSTANCE_NAME_FIELD("instanceName"); + + private String value; + + public String getValue() { + return value; + } + + private GeneralCanvasItems(String value) { + this.value = value; + } + } + + public enum ResourceMetadataEnum { + RESOURCE_NAME("name"), + DESCRIPTION("description"), + CATEGORY("selectGeneralCategory"), + VENDOR_NAME("vendorName"), + VENDOR_RELEASE("vendorRelease"), + TAGS("i-sdc-tag-input"), + CONTACT_ID("contactId"), + ICON(" iconBox"), + TAGS_TABLE("i-sdc-tag-text"); + private String value; + + public String getValue() { + return value; + } + + private ResourceMetadataEnum(String value) { + this.value = value; + } + } + + public enum GeneralElementsEnum { + CREATE_BUTTON("create/save"), + CHECKIN_BUTTON("check_in"), + CHECKOUT_BUTTON("check_out"), + SUBMIT_FOR_TESTING_BUTTON("submit_for_testing"), + DELETE_VERSION_BUTTON("delete_version"), + REVERT_BUTTON("revert"), + LIFECYCLE_STATE("formlifecyclestate"), + VERSION_HEADER("versionHeader"), + OK("OK"), + UPLOAD_FILE_INPUT("browseButton"); + + private String value; + + public String getValue() { + return value; + } + + private GeneralElementsEnum(String value) { + this.value = value; + } + } + + public enum ArtifactPageEnum { + ADD_DEPLOYMENT_ARTIFACT("add-deployment-artifact-button"), + ADD_INFORMATIONAL_ARTIFACT("add-information-artifact-button"), + DOWNLOAD_ARTIFACT_ENV("download_env_"), + ADD_ANOTHER_ARTIFACT("add-another-artifact-button"), + EDIT_ARTIFACT("edit_"), //upload env file by its label(via deployment artifact view)/displayName(via Canvas) + DELETE_ARTIFACT("delete_"), + DOWNLOAD_ARTIFACT("download_"), + GET_DEPLOYMENT_ARTIFACT_DESCRIPTION("description"), + GET_INFORMATIONAL_ARTIFACT_DESCRIPTION("Description"), + OK("OK"), + TYPE("artifactType_"), + DEPLOYMENT_TIMEOUT("timeout_"), + VERSION("artifactVersion_"), + UUID("artifactUUID_"), + EDIT_PARAMETERS_OF_ARTIFACT("edit-parameters-of-"), + ARTIFACT_NAME("artifactDisplayName_"), + UPLOAD_HEAT_ENV_PARAMETERS("uplaodEnv_"), + VERSION_ENV("artifactEnvVersion_"); + private String value; + + public String getValue() { + return value; + } + + private ArtifactPageEnum(String value) { + this.value = value; + } + } + + public enum PropertiesPageEnum { + + ADD_NEW_PROPERTY("addGrey"), + EDIT_PROPERTY("edit_"), + DELETE_PROPERTY("delete_"), + PROPERTY_NAME("propertyName_"), + PROPERTY_DESCRIPTION("propertyDescription_"), + PROPERTY_TYPE("propertyType_"), + ENTRY_SCHEMA("propertySchema_"), + ADD("Add"), CANCEL("Cancel"), + DONE("Done"), + PROPERTY_ROW("propertyRow"), + SAVE("Save"), + POPUP_FORM("sdc-edit-property-container"); + private String value; + + public String getValue() { + return value; + } + + private PropertiesPageEnum(String value) { + this.value = value; + } + } + + public enum PropertiesPopupEnum { + + PROPERTY_NAME("propertyName"), + PROPERTY_VALUE("defaultvalue"), + PROPERTY_BOOLEAN_VALUE("booleantype"), + PROPERTY_DESCRIPTION("description"), + PROPERTY_TYPE("propertyType"), + ENTRY_SCHEMA("schema-type"), + CANCEL("Cancel"), + SAVE("Save"), + POPUP_FORM("sdc-edit-property-container"), + ADD("Add"), + DONE("Done"), + PROPERTY_RADIO_BUTTON_CONTAINER("propertyRadioButton_"), + RADIO_BUTTON_CLASS("tlv-radio-label"); + private String value; + + public String getValue() { + return value; + } + + private PropertiesPopupEnum(String value) { + this.value = value; + } + } + + public enum AdminPageTabs { + USER_MANAGEMENT("usermanagmenttab"), + CATEGORY_MANAGEMENT("categorymanagmenttab"); + + private String value; + + public String getValue() { + return value; + } + + private AdminPageTabs(String value) { + this.value = value; + } + } + + public enum UserManagementEnum { + + SEARCH_BOX("searchbox"), + NEW_USER_FIELD("newuserId"), + ROLE_SELECT("selectrole"), + CREATE_BUTTON("creategreen"), + CLASS__USER_MANAGEMENT_TABLE("sdc-user-management-table"), + ROW_TABLE("row_"), + FIRST_NAME("firstName_"), + LAST_NAME("lastName__"), + USER_ID("userId_"), + EMAIL("email_"), + ROLE("role_"), + LAST_ACTIVE("lastActive_"), + UPDATE_ROLE("selectRole_"), + UPDATE_USER_BUTTON("updateUser_"), + SAVE_USER("save_"), + DELETE_USER("delete_"), + ; + + + private String value; + + public String getValue() { + return value; + } + + private UserManagementEnum(String value) { + this.value = value; + } + } + + public enum CategoryManagement { + + SERVICE_CATEGORY_HEADER("servicecategoryheader"), + RESOURCE_CATEGORY_HEADER("resourcecategoryheader"), + SERVICE_CATEGORY_LIST("servicecategory"), + RESOURCE_CATEGORY_LIST("resourcecategory"), + NEW_CATEGORY_BUTTON("newcategory"), + NEW_SUB_CATEGORY_BUTTON("newsubcategory"), + NEW_CATEGORY_NAME("i-sdc-form-input"); + + private String value; + + public String getValue() { + return value; + } + + private CategoryManagement(String value) { + this.value = value; + } + } + + + + public enum MainMenuButtons { + HOME_BUTTON("main-menu-button-home"), + CATALOG_BUTTON("main-menu-button-catalog"), + ONBOARD_BUTTON("main-menu-button-onboard"), + SEARCH_BOX("main-menu-input-search"), + REPOSITORY_ICON("repository-icon"); + private String value; + + public String getValue() { + return value; + } + + private MainMenuButtons(String value) { + this.value = value; + } + } + + public enum MainMenuButtonsFromInsideFrame { + HOME_BUTTON("breadcrumbs-button-0"); + private String value; + + public String getValue() { + return value; + } + + private MainMenuButtonsFromInsideFrame(String value) { + this.value = value; + } + } + + public enum MenuOptionsEnum { + EDIT("Edit"), + CHECK_IN("Check in"), + CHECK_OUT("Check out"), + VIEW("View"), + SUBMIT_FOR_TEST("Submit For Test"), + ACCEPT("Accept"), + REJECT("Reject"), + START_TEST("Start test"), + DISTREBUTE("Distribute"); + + private String value; + + public String getValue() { + return value; + } + + private MenuOptionsEnum(String value) { + this.value = value; + } + } + + public enum StepsEnum { + GENERAL("Generalstep"), + ICON("Iconstep"), + DEPLOYMENT_ARTIFACT("Deployment Artifactstep"), + INFORMATION_ARTIFACT("Information Artifactstep"), + PROPERTIES("Propertiesstep"), + COMPOSITION("Compositionstep"), + ACTIVITY_LOG("Activity Logstep"), + DEPLOYMENT_VIEW("Deploymentstep"), + TOSCA_ARTIFACTS("TOSCA Artifactsstep"), + MONITOR("Monitor step"), + MANAGEMENT_WORKFLOW("Management Workflowstep"), + INPUTS("Inputsstep"), + HIERARCHY("Hierarchystep"); + + private String value; + + public String getValue() { + return value; + } + + private StepsEnum(String value) { + this.value = value; + } + } + + public enum ArtifactPopup { + + BROWSE("browseButton"), + ARTIFACT_DESCRIPTION("description"), + ARTIFACT_LABEL("artifactLabel"), + ARTIFACT_TYPE("artifacttype"), + OK("OK"), + SAVE("Save"), + DONE_BUTTON("Done"), + CANCEL_BUTTON("Cancel"), + URL("input[class^='i-sdc-form-input']"), + MODAL_WINDOW("sdc-add-artifact"); + + private String value; + + public String getValue() { + return value; + } + + private ArtifactPopup(String value) { + this.value = value; + } + } + + public enum ServiceMetadataEnum { + SERVICE_NAME("name"), DESCRIPTION("description"), CATEGORY("selectGeneralCategory"), PROJECT_CODE("projectCode"), TAGS("i-sdc-tag-input"), CONTACT_ID("contactId"), ICON(" iconBox"); + + private String value; + + public String getValue() { + return value; + } + + private ServiceMetadataEnum(String value) { + this.value = value; + } + } + + public enum ProductMetadataEnum { + PRODUCT_NAME("name"), + FULL_NAME("fullName"), + DESCRIPTION("description"), + PROJECT_CODE("projectCode"), + TAGS("i-sdc-tag-input"), + ATT_CONTACT("attContact"), + ICON(" iconBox"); + + private String value; + + public String getValue() { + return value; + } + + private ProductMetadataEnum(String value) { + this.value = value; + } + } + + public enum DashboardCardEnum { + ASSET_TYPE("asset-type"), LIFECYCLE_STATE("span[class^='w-sdc-dashboard-card-info-lifecycleState']"), + INFO_NAME("div.sdc-tile-content-info-item-name"), + VERSION("div[class^='w-sdc-dashboard-card-info-user']"), + DASHBOARD_CARD("div[class^='w-sdc-dashboard-card ']"), + ASSET_TYPE_CSS("span[data-tests-id='asset-type']"); + + private String value; + + public String getValue() { + return value; + } + + private DashboardCardEnum(String value) { + this.value = value; + } + } + + public enum CatalogPageLeftPanelCategoryCheckbox { + GENERIC_CHECKBOX("span[data-tests-id='checkbox-resourcenewcategory.generic']"), + NETWORK_L2_3("span[data-tests-id='checkbox-resourcenewcategory.networkl2-3']"), + NETWORK_L4_PLUS("span[data-tests-id='checkbox-resourcenewcategory.networkl4+']"), + NETWORK_CONNECTIVITY("span[data-tests-id='checkbox-resourcenewcategory.networkconnectivity']"), + APPLICATION_L4_PLUS("span[data-tests-id='checkbox-resourcenewcategory.applicationl4+']"), + DCAE("span[data-tests-id='checkbox-resourcenewcategory.dcaecomponent']"); + + private String value; + + public String getValue() { + return value; + } + + private CatalogPageLeftPanelCategoryCheckbox(String value) { + this.value = value; + } + } + + public enum CatalogPageLeftPanelFilterTitle { + TYPE("span[data-tests-id='typeFilterTitle']"), + CATEGORIES("span[data-tests-id='categoriesFilterTitle']"), + STATUS("span[data-tests-id='statusFilterTitle']"); + + private String value; + + public String getValue() { + return value; + } + + private CatalogPageLeftPanelFilterTitle(String value) { + this.value = value; + } + } + + public enum CatalogPageLeftPanelSubCategoryCheckbox { + COMMON_NETWORK_RESOURCES("span[data-tests-id='checkbox-resourcenewcategory.networkl4+.commonnetworkresources']"), + ROUTER("span[data-tests-id='checkbox-resourcenewcategory.networkl2-3.router']"), + WAN_CONNECTORS("span[data-tests-id='checkbox-resourcenewcategory.networkl2-3.wanconnectors']"), + LAN_CONNECTORS("span[data-tests-id='checkbox-resourcenewcategory.networkl2-3.lanconnectors']"), + INFRASTRUCTERE_NETWORKl2_3("span[data-tests-id='checkbox-resourcenewcategory.networkl2-3.infrastructure']"), + GATEWAY("span[data-tests-id='checkbox-resourcenewcategory.networkl2-3.gateway']"), + NETWORK_ELEMENTS("span[data-tests-id='checkbox-resourcenewcategory.generic.networkelements']"), + ABSTRACT("span[data-tests-id='checkbox-resourcenewcategory.generic.abstract']"), + RULES("span[data-tests-id='checkbox-resourcenewcategory.generic.rules']"), + DATABASE("span[data-tests-id='checkbox-resourcenewcategory.generic.database']"), + INFRASTRUCTERE_GENERIC("span[data-tests-id='checkbox-resourcenewcategory.generic.infrastructure']"), + VIRTUAL_LINKS("span[data-tests-id='checkbox-resourcenewcategory.networkconnectivity.virtuallinks']"), + CONNECTION_POINTS("span[data-tests-id='checkbox-resourcenewcategory.networkconnectivity.connectionpoints']"), + APPLICATION_SERVER("span[data-tests-id='checkbox-resourcenewcategory.applicationl4+.applicationserver']"), + CALL_CONTROL("span[data-tests-id='checkbox-resourcenewcategory.applicationl4+.callcontrol']"), + MEDIASERVERS("span[data-tests-id='checkbox-resourcenewcategory.applicationl4+.mediaservers']"), + WEBSERVER("span[data-tests-id='checkbox-resourcenewcategory.applicationl4+.webserver']"), + LOAD_BALANCER("span[data-tests-id='checkbox-resourcenewcategory.applicationl4+.loadbalancer']"), + BORDER_ELEMENT("span[data-tests-id='checkbox-resourcenewcategory.applicationl4+.borderelement']"), + DATABASE_APPLIVATION_L4_PLUS("span[data-tests-id='checkbox-resourcenewcategory.applicationl4+.database']"), + FIREWALL("span[data-tests-id='checkbox-resourcenewcategory.applicationl4+.firewall']"), + DATABASE_DCAE("span[data-tests-id='checkbox-resourcenewcategory.dcaecomponent.database']"), + POLICY("span[data-tests-id='checkbox-resourcenewcategory.dcaecomponent.policy']"), + MICROSERVICE("span[data-tests-id='checkbox-resourcenewcategory.dcaecomponent.microservice']"), + SOURCE("span[data-tests-id='checkbox-resourcenewcategory.dcaecomponent.source']"), + COLLECTOR("span[data-tests-id='checkbox-resourcenewcategory.dcaecomponent.collector']"), + UTILITY("span[data-tests-id='checkbox-resourcenewcategory.dcaecomponent.utility']"), + ANALYTICS("span[data-tests-id='checkbox-resourcenewcategory.dcaecomponent.analytics']"); + + private String value; + + public String getValue() { + return value; + } + + private CatalogPageLeftPanelSubCategoryCheckbox(String value) { + this.value = value; + } + } + + public enum CompositionScreenEnum { + + CHANGE_VERSION("changeVersion", Arrays.asList()), + DEPLOYMENT_ARTIFACT_TAB("deployment-artifact-tab", Arrays.asList("Deployment Artifacts")), + ADD_ARTIFACT("add_Artifact_Button", Arrays.asList()), + SEARCH_ASSET("searchAsset", Arrays.asList()), + PROPERTIES_AND_ATTRIBUTES_TAB("properties-and-attributes-tab",Arrays.asList()), + MENU_INPUTS("sub-menu-button-inputs",Arrays.asList()), + MENU_TRIANGLE_DROPDOWN("triangle-dropdown", Arrays.asList()), + ARTIFACTS_LIST("artifactName", Arrays.asList()), + INFORMATION_ARTIFACTS("button[tooltip-content='Information Artifacts']", Arrays.asList("Informational Artifacts")), + API("button[tooltip-content='API']", Arrays.asList("API Artifacts")), + INFORMATION("button[tooltip-content='Information']", Arrays.asList("General Info", "Additional Information", "Tags")), + COMPOSITION("button[tooltip-content='Composition']", Arrays.asList("Composition")), + INPUTS("button[tooltip-content='Inputs']", Arrays.asList("")), + REQUIREMENTS_AND_CAPABILITIES("button[tooltip-content='Requirements and Capabilities']", Arrays.asList()), + INFORMATION_TAB("information-tab", Arrays.asList()), + CUSTOMIZATION_UUID("rightTab_customizationModuleUUID", Arrays.asList()); + + private String value; + private List title; + + public String getValue() { + return value; + } + + public List getTitle() { + return title; + } + + private CompositionScreenEnum(String value, List title) { + this.value = value; + this.title = title; + } + } + + public enum ToscaArtifactsScreenEnum { + + TOSCA_MODEL("download-Tosca Model"), + TOSCA_TEMPLATE("download-Tosca Template"), + ARTIFACT_VERSION("version-"), + ARTIFACT_NAME("name-"), + ARTIFACT_TYPE("type-"), + ARTIFACT_DETAILS("details-"), + DOWNLOAD_ARTIFACT("download-"), + DOWNLOAD_CSAR("download-Tosca Model"); + + private String value; + + public String getValue() { + return value; + } + + private ToscaArtifactsScreenEnum(String value) { + this.value = value; + } + } + + public enum InformationalArtifactsService { + AFFINITY_RULES("artifact_Display_Name-Affinity Rules"), + CONTROL_LOOP_FUNCTIONS("artifact_Display_Name-Control Loop Functions"), + DEPLOYMENT_VOTING_RECORD("artifact_Display_Name-Deployment Voting Record"), + DIMENSIONING_INFO("artifact_Display_Name-Dimensioning Info"), + DISTRIBUTION_INSTRUCTION("artifact_Display_Name-Distribution Instructions"), + ENGINEERING_RULES("artifact_Display_Name-Engineering Rules (ERD)"), + OPERATIONAL_POLICES("artifact_Display_Name-Operational Policies"), + SERVICE_ARTIFACT_PLAN("artifact_Display_Name-Service Artifact Plan"), + SERVICE_QUESTIONNAIRE("artifact_Display_Name-Service Questionnaire"), + SERVICE_SECURITY_TEMPLATE("artifact_Display_Name-Service Security Template"), + SERVICE_SPECIFIC_POLICIES("artifact_Display_Name-Service-specific Policies"), + SUMMARY_OF_IMPACTS_TO_ECOMP("artifact_Display_Name-Summary of impacts to ECOMP elements,OSSs, BSSs"), + TD_CERTIFICATION_TEST_RESULTS("artifact_Display_Name-TD Certification Test Results"); + + private String value; + + public String getValue() { + return value; + } + + private InformationalArtifactsService(String value) { + this.value = value; + } + } + + public enum APIArtifactsService { + + CONFIGURATION("artifact_Display_Name-Configuration"), + INSTANTIATION("artifact_Display_Name-Instantiation"), + LOGGING("artifact_Display_Name-Logging"), + MONITORING("artifact_Display_Name-Monitoring"), + REPORTING("artifact_Display_Name-Reporting"), + TESTING("artifact_Display_Name-Testing"); + + private String value; + + public String getValue() { + return value; + } + + private APIArtifactsService(String value) { + this.value = value; + } + } + + public enum DeploymentArtifactCompositionRightMenu { + ARTIFACT_NAME("artifactName-"), + ARTIFACT_DISPLAY_NAME("artifact_Display_Name-"), + DOWNLOAD("download_"), + DELETE("delete_"), + ADD_ARTIFACT_BUTTON("add_Artifact_Button"), + EDIT_PARAMETERS_OF_ARTIFACT("edit-parameters-of-"), + ARTIFACT_ITEM("artifact-item-"), + ARTIFACT_ENV("heat_env_"); + + private String value; + + public String getValue() { + return value; + } + + private DeploymentArtifactCompositionRightMenu(String value) { + this.value = value; + } + + } + + public enum InputsScreenService { + ADD_SELECTED_INPUTS_BTN("add-inputs-to-service-button"), + VF_INSTANCE_ROWS("expand-collapse[expanded-selector^='.vf-instance-list.']"), + VF_INSTANCE_ROW_NAME("span[class^='title-text']"), + VF_INSTANCE_INPUTS("div[class^='vf-instance-list ']"), + VF_INSTANCE_INPUT("div[class^='input-row ng-scope']"), + VF_INSTNCE_PROPERTY_NAME("div[class^='title-text']"), + INPUT_CHECKBOX("span[class^='tlv-checkbox-label']"), + SERVICE_INPUT_ROW("div[class^='service-input-row input-row']"), + DELETE_INPUT_BTN("span[class$='remove-input-icon']"), + RESOURCE_INSTANCE_PROPERTY_NAME("propertyName_"), + RESOURCE_INSTANCE_PROPERTY_TYPE("propertyType_"), + RESOURCE_INSTANCE_PROPERTY_CHECKBOX("propertyCheckbox_"), + SERVICE_INPUTS_DELETE_BUTTON("deleteInput_") + ; + + private String value; + + public String getValue() { + return value; + } + + private InputsScreenService(String value) { + this.value = value; + } + + } + + public enum DeploymentScreen { + MODULES("span[class^='expand-collapse-title-text']"), + MEMBERS("div[class^='expand-collapse-sub-title']"), + PROPERTIES("list-of-Properties"), + ARTIFACTS("list-of-Artifacts"), + BUTTON_PROPERTIES("div[data-tests-id='list-of-Properties'] span[class^='hand']"), + BUTTON_ARTIFACTS("div[data-tests-id='list-of-Artifacts'] span[class^='hand']"), + PROPERTY_NAMES("div[data-tests-id='selected-module-property-name'] span"), + PROPERTY_TYPES("selected-module-property-type"), + PROPERTY_SCHEMA_TYPE("selected-module-property-schema-type"), + ARTIFACT_NAME("selected-module-artifact-name"), + ARTIFACT_UUID("selected-module-artifact-uuid"), + ARTIFACT_VERSION("selected-module-artifact-version"), + PENCIL_ICON("edit-name-popover-icon"), + MODULE_NAME("selected-module-name"), + MODULE_ID("selected-module-group-uuid"), + RESOURCE_NAME_ON_POPOVER("popover-vfinstance-name"), + MODULE_NAME_ON_POPOVER("popover-module-name"), + NAME_INPUT("popover-heat-name"), + SAVE("popover-save-button"), + CANCEL("popover-close-button"), + X_BUTTON("popover-x-button"); + + private String value; + + public String getValue() { + return value; + } + + private DeploymentScreen(String value) { + this.value = value; + } + } + + public enum ImportVfRepository { + SEARCH("onboarding-search"), + IMPORT_VSP("import-csar"), + DOWNLOAD_CSAR("download-csar"), + UPDATE_VSP("update-csar"); + + private String value; + + public String getValue() { + return value; + } + + private ImportVfRepository(String value) { + this.value = value; + } + } + + public enum EnvParameterView { + SEARCH_ENV_PARAM_NAME("search-env-param-name"), + ENV_CURRENT_VALUE("value-field-of-"),//value-field-of-oam_volume_name_0 - parameter name + ENV_DEFAULT_VALUE("default-value-of-");// default-value-of-vnf_name + + private String value; + + public String getValue() { + return value; + } + + private EnvParameterView(String value) { + this.value = value; + } + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ErrorMessageProperties.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ErrorMessageProperties.java new file mode 100644 index 0000000000..a7d2551683 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ErrorMessageProperties.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class ErrorMessageProperties { + + private String messageId ; + private String code; + + public ErrorMessageProperties() { + + } + + public ErrorMessageProperties(String messageId, String code) { + this.messageId = messageId; + this.code = code; + } + + public String getMessageId() { + return messageId; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/GeneralCanvasItemsEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/GeneralCanvasItemsEnum.java new file mode 100644 index 0000000000..e708fb8ee4 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/GeneralCanvasItemsEnum.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum GeneralCanvasItemsEnum { + CANVAS("canvas"), + CANVAS_RIGHT_PANEL("w-sdc-designer-sidebar-head"), + DELETE_INSTANCE_BUTTON("e-sdc-small-icon-delete"); + + private String value; + + public String getValue() { + return value; + } + + private GeneralCanvasItemsEnum(String value) { + this.value = value; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatAndHeatEnvNamesPair.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatAndHeatEnvNamesPair.java new file mode 100644 index 0000000000..1df61b734c --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatAndHeatEnvNamesPair.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.io.File; + +public class HeatAndHeatEnvNamesPair { + + private File heatFileName; + private File heatEnvFileName; + + public HeatAndHeatEnvNamesPair() { + super(); + } + + public HeatAndHeatEnvNamesPair(File heatFileName, File heatEnvFileName) { + super(); + this.heatFileName = heatFileName; + this.heatEnvFileName = heatEnvFileName; + } + + public File getHeatFileName() { + return heatFileName; + } + + public void setHeatFileName(File heatFileName) { + this.heatFileName = heatFileName; + } + + public File getHeatEnvFileName() { + return heatEnvFileName; + } + + public void setHeatEnvFileName(File heatEnvFileName) { + this.heatEnvFileName = heatEnvFileName; + } + + @Override + public String toString() { + return "HeatHeatEnvNamesPair [heatFileName=" + heatFileName + ", heatEnvFileName=" + heatEnvFileName + "]"; + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatWithParametersDefinition.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatWithParametersDefinition.java new file mode 100644 index 0000000000..5ff173ee87 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/HeatWithParametersDefinition.java @@ -0,0 +1,102 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +import org.openecomp.sdc.be.datatypes.elements.HeatParameterDataDefinition; + +public class HeatWithParametersDefinition { + + private String heatLabel; + private String heatEnvLabel; + private String heatArtifactType; + private String heatEnvArtifactType; + private String heatArtifactDisplayName; + private List heatParameterDefinition; + + public HeatWithParametersDefinition(String heatLabel, String heatEnvLabel, String heatArtifactType, String heatEnvArtifactType, String heatArtifactDisplayName, List heatParameterDefinition) { + super(); + this.heatLabel = heatLabel; + this.heatEnvLabel = heatEnvLabel; + this.heatArtifactType = heatArtifactType; + this.heatEnvArtifactType = heatEnvArtifactType; + this.heatArtifactDisplayName = heatArtifactDisplayName; + this.heatParameterDefinition = heatParameterDefinition; + } + + public String getHeatArtifactDisplayName() { + return heatArtifactDisplayName; + } + + public void setHeatArtifactDisplayName(String heatArtifactDisplayName) { + this.heatArtifactDisplayName = heatArtifactDisplayName; + } + + public String getHeatLabel() { + return heatLabel; + } + + public void setHeatLabel(String heatLabel) { + this.heatLabel = heatLabel; + } + + public String getHeatEnvLabel() { + return heatEnvLabel; + } + + public void setHeatEnvLabel(String heatEnvLabel) { + this.heatEnvLabel = heatEnvLabel; + } + + public String getHeatArtifactType() { + return heatArtifactType; + } + + public void setHeatArtifactType(String heatArtifactType) { + this.heatArtifactType = heatArtifactType; + } + + public String getHeatEnvArtifactType() { + return heatEnvArtifactType; + } + + public void setHeatEnvArtifactType(String heatEnvArtifactType) { + this.heatEnvArtifactType = heatEnvArtifactType; + } + + public List getHeatParameterDefinition() { + return heatParameterDefinition; + } + + public void setHeatParameterDefinition(List heatParameterDefinition) { + this.heatParameterDefinition = heatParameterDefinition; + } + + @Override + public String toString() { + return "HeatWithParametersDefinition [heatLabel=" + heatLabel + ", heatEnvLabel=" + heatEnvLabel + ", heatArtifactType=" + heatArtifactType + ", heatEnvArtifactType=" + heatEnvArtifactType + ", heatArtifactDisplayName=" + + heatArtifactDisplayName + ", heatParameterDefinition=" + heatParameterDefinition + "]"; + } + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/LifeCycleStateEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/LifeCycleStateEnum.java new file mode 100644 index 0000000000..773cb57b2e --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/LifeCycleStateEnum.java @@ -0,0 +1,47 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum LifeCycleStateEnum { + + CHECKOUT("IN DESIGN CHECK OUT"), + CHECKIN("IN DESIGN CHECK IN"), + READY_FOR_TESTING("READY FOR TESTING"), + IN_TESTING("IN TESTING"), + WAITING_FOR_DISTRIBUTION("WAITING FOR DISTRIBUTION"), + DISTRIBUTION_REJECTED("DISTRIBUTION REJECTED"), + DISTRIBUTION_APPROVED("DISTRIBUTION APPROVED"), + CERTIFIED("CERTIFIED"), + DISTRIBUTED("DISTRIBUTED"), + IN_DESIGN("IN DESIGN"); + + private String value; + private String value2; + + public String getValue() { + return value; + } + + private LifeCycleStateEnum(String value) { + this.value = value; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/MenuOptionsEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/MenuOptionsEnum.java new file mode 100644 index 0000000000..63171a6c78 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/MenuOptionsEnum.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum MenuOptionsEnum { + + EDIT("Edit"), CHECK_IN("Check in"), CHECK_OUT("Check out"), VIEW("View"), SUBMIT_FOR_TEST("Submit For Test"), ACCEPT("Accept"), REJECT("Reject"), START_TEST("Start test"), DISTREBUTE("Distribute"); + + private String value; + + public String getValue() { + return value; + } + + private MenuOptionsEnum(String value) { + this.value = value; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyInfo.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyInfo.java new file mode 100644 index 0000000000..785a355e13 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/PropertyInfo.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; + +public class PropertyInfo { + + public PropertyInfo() { + super(); + } + + public PropertyInfo(PropertyTypeEnum prop) { + super(); + this.name = prop.getName(); + this.value = prop.getValue(); + this.type = prop.getType(); + this.description = prop.getDescription(); + } + + private String name; + private String value; + private String type; + private String description; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceCategoriesNameEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceCategoriesNameEnum.java new file mode 100644 index 0000000000..2c49c8718b --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ResourceCategoriesNameEnum.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum ResourceCategoriesNameEnum { + + GENERIC("checkbox-resourcenewcategory.generic"), NETWORK_CONNECTIVITY("checkbox-resourcenewcategory.networkconnectivity"), NETWORK_ELEMENTS("checkbox-resourcenewcategory.generic.networkelements"), + ABSTRACT("checkbox-resourcenewcategory.generic.abstract"), DATABASE_GENERIC("checkbox-resourcenewcategory.generic.database"), INFRASTRUCTURE("checkbox-resourcenewcategory.generic.infrastructure"), + VIRTUAL_LINKS("checkbox-resourcenewcategory.networkconnectivity.virtuallinks"), CONNECTION_POINTS("checkbox-resourcenewcategory.networkconnectivity.connectionpoints"), NETWORKL4("checkbox-resourcenewcategory.networkl4+"), + COMMON_NETWORK_RESOURCES("checkbox-resourcenewcategory.networkl4+.commonnetworkresources"), APPLICATIONL4("checkbox-resourcenewcategory.applicationl4+"), WEB_SERVER("checkbox-resourcenewcategory.applicationl4+.webserver"), + APPLICATION_SERVER("checkbox-resourcenewcategory.applicationl4+.applicationserver"), CALL_CONTROL("checkbox-resourcenewcategory.applicationl4+.callcontrol"), BORDER_ELEMENT("checkbox-resourcenewcategory.applicationl4+.borderelement"), + MEDIA_SERVERS("checkbox-resourcenewcategory.applicationl4+.mediaservers"), DATABASE("checkbox-resourcenewcategory.applicationl4+.database"), FIREWALL("checkbox-resourcenewcategory.applicationl4+.firewall"), + LOAD_BALANCER("checkbox-resourcenewcategory.applicationl4+.loadbalancer"), NETWORK_L23("checkbox-resourcenewcategory.networkl2-3"), Router("checkbox-resourcenewcategory.networkl2-3.router"), + WAN_Connectors("checkbox-resourcenewcategory.networkl2-3.wanconnectors"), LAN_CONNECTORS("checkbox-resourcenewcategory.networkl2-3.lanconnectors"), GATEWAY("checkbox-resourcenewcategory.networkl2-3.gateway"), + INFRASTRUCTUREL23("checkbox-resourcenewcategory.networkl2-3.infrastructure"); + + private String value; + + public String getValue() { + return value; + } + + private ResourceCategoriesNameEnum(String value) { + this.value = value; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceCategoriesNameEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceCategoriesNameEnum.java new file mode 100644 index 0000000000..b90e311f72 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/ServiceCategoriesNameEnum.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum ServiceCategoriesNameEnum { + + NETWORK_L13("checkbox-servicenewcategory.networkl1-3"), VOIPCALL_CONTROL("checkbox-servicenewcategory.voipcallcontrol"), NETWORKL4("checkbox-servicenewcategory.networkl4+"), MOBILITY("checkbox-servicenewcategory.mobility"); + + private String value; + + public String getValue() { + return value; + } + + private ServiceCategoriesNameEnum(String value) { + this.value = value; + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TopMenuButtonsEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TopMenuButtonsEnum.java new file mode 100644 index 0000000000..9e81505111 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TopMenuButtonsEnum.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum TopMenuButtonsEnum { + + HOME("main-menu-button-home"), CATALOG("main-menu-button-catalog"), ON_BOARDING("main-menu-button-onboard"); + + private String value; + private String value2; + + public String getButton() { + return value; + } + + private TopMenuButtonsEnum(String value) { + this.value = value; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TypesEnum.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TypesEnum.java new file mode 100644 index 0000000000..d27eb0c150 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/TypesEnum.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public enum TypesEnum { + + RESOURCE("checkbox-resource"), VF("checkbox-vf"), VFC("checkbox-vfc"), CP("checkbox-cp"), VL("checkbox-vl"), SERVICE("checkbox-service"), PRODUCT("checkbox-product"); + private String value; + + public String getValue() { + return value; + } + + private TypesEnum(String value) { + this.value = value; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/UserCredentials.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/UserCredentials.java new file mode 100644 index 0000000000..2de872504f --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/UserCredentials.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import org.openecomp.sdc.be.model.User; + +public class UserCredentials extends User { + + // private String userName; + private String password; + + public UserCredentials(String userId, String password, String firstname, String lastname, String role) { + super(); + setUserId(userId); + // this.userName = userName; + this.password = password; + setFirstName(firstname); + setLastName(lastname); + setRole(role); + } + + public UserCredentials() { + super(); + } + + // public String getUserName() { + // return userName; + // } + // public void setUserName(String userName) { + // this.userName = userName; + // } + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/UserManagementTab.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/UserManagementTab.java new file mode 100644 index 0000000000..0101b430d8 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/UserManagementTab.java @@ -0,0 +1,114 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.WebElement; + +import com.aventstack.extentreports.Status; + +public class UserManagementTab { + + public void searchUser(String searchCriterion){ + ExtentTestActions.log(Status.INFO, "Searching a user by the value : " + searchCriterion); + WebElement searchBoxWebElement = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.UserManagementEnum.SEARCH_BOX.getValue()); + searchBoxWebElement.clear(); + searchBoxWebElement.sendKeys(searchCriterion); + GeneralUIUtils.ultimateWait(); + } + + public void setNewUserBox(String user){ + ExtentTestActions.log(Status.INFO, "Inserting userid " + user); + WebElement createNewUserWebElement = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.UserManagementEnum.NEW_USER_FIELD.getValue()); + createNewUserWebElement.clear(); + createNewUserWebElement.sendKeys(user); + GeneralUIUtils.ultimateWait(); + } + + public void selectUserRole(UserRoleEnum userRole){ + String role = userRole.name().toLowerCase(); + ExtentTestActions.log(Status.INFO, "Selecting role " + userRole.name()); + GeneralUIUtils.getSelectList(role, DataTestIdEnum.UserManagementEnum.ROLE_SELECT.getValue()); + } + + public void updateUserRole(UserRoleEnum userRole, int rowIndx){ + String role = userRole.name().toLowerCase(); + ExtentTestActions.log(Status.INFO, "Updating the user role to " + userRole.name()); + GeneralUIUtils.getSelectList(role, DataTestIdEnum.UserManagementEnum.UPDATE_ROLE.getValue() + rowIndx); + } + + public void clickCreateButton(){ + ExtentTestActions.log(Status.INFO, "Clicking on 'Create' button."); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.UserManagementEnum.CREATE_BUTTON.getValue()); + } + + public WebElement getRow(int index){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.UserManagementEnum.ROW_TABLE.getValue() + index); + } + + public WebElement getFirstName(int index){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.UserManagementEnum.FIRST_NAME.getValue() + index); + } + + public WebElement getLastName(int index){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.UserManagementEnum.LAST_NAME.getValue() + index); + } + + public WebElement getUserId(int index){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.UserManagementEnum.USER_ID.getValue() + index); + } + + public WebElement getEmail(int index){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.UserManagementEnum.EMAIL.getValue() + index); + } + + public WebElement getRole(int index){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.UserManagementEnum.ROLE.getValue() + index); + } + + public WebElement getLastActive(int index){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.UserManagementEnum.LAST_ACTIVE.getValue() + index); + } + + public void updateUser(int index){ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.UserManagementEnum.UPDATE_USER_BUTTON.getValue() + index); + } + + public void deleteUser(int index){ + ExtentTestActions.log(Status.INFO, "Deleting the user in row " + (index + 1)); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.UserManagementEnum.DELETE_USER.getValue() + index); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + } + + public void saveAfterUpdateUser(int index){ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.UserManagementEnum.SAVE_USER.getValue() + index); + } + + public List getAllRowsDisplayed(){ + return GeneralUIUtils.getWebElementsListByContainTestID(DataTestIdEnum.UserManagementEnum.ROW_TABLE.getValue()); + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/VFCArtifact.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/VFCArtifact.java new file mode 100644 index 0000000000..540a36ad18 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/VFCArtifact.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.datatypes; + +public class VFCArtifact { + + String artifactUUID; + String artifactVersion; + String artifactname; + String artifacttype; + + + public VFCArtifact(String artifactName, String artifactType, String uuid, String version){ + artifactname = artifactName; + artifactUUID = uuid; + artifactVersion = version; + artifacttype = artifactType; + } + + public String getArtifactUUID() { + return artifactUUID; + } + + public void setArtifactUUID(String artifactUUID) { + this.artifactUUID = artifactUUID; + } + + public String getArtifactVersion() { + return artifactVersion; + } + + public void setArtifactVersion(String artifactVersion) { + this.artifactVersion = artifactVersion; + } + + public String getArtifactname() { + return artifactname; + } + + public void setArtifactname(String artifactname) { + this.artifactname = artifactname; + } + + public String getArtifacttype() { + return artifacttype; + } + + public void setArtifacttype(String artifacttype) { + this.artifacttype = artifacttype; + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/environmentLocal b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/environmentLocal new file mode 100644 index 0000000000..ea93ddfe85 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/datatypes/environmentLocal @@ -0,0 +1,10 @@ +//URL designer +urlDesigner=http://172.20.43.136:8080/sdc1/proxy-designer1#/dashboard +//URL tester +urlTester=http://172.20.43.136:8080/sdc1/proxy-tester1 +//URL Vagrant +urlDesignerVagrant=http://localhost:8181/sdc1/proxy-designer1#/dashboard +//UrlStaging +UrlStaging=https://www.e-access.att.com/sdcpstage/sdc1/portal#/dashboard +//UrlAdmin +UrlAdmin=http://172.20.43.136:8080/sdc1/proxy-admin1#/adminDashboard \ No newline at end of file diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/AdminUserManagment.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/AdminUserManagment.java new file mode 100644 index 0000000000..710188af43 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/AdminUserManagment.java @@ -0,0 +1,289 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import java.io.IOException; +import java.util.List; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.AdminGeneralPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.AdminWorkspaceUIUtilies; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.UserRestUtils; +import org.openecomp.sdc.ci.tests.verificator.ErrorMessageUIVerificator; +import org.openecomp.sdc.ci.tests.verificator.UserManagementVerificator; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; + +public class AdminUserManagment extends SetupCDTest { + + @DataProvider(name = "searchValues") + private final Object[][] searchString(){ + User newUser = createNewUserUsingAPI(); + return new Object[][]{{newUser.getUserId(), newUser}, {newUser.getFirstName(), newUser}, {newUser.getLastName(), newUser}, {newUser.getEmail(), newUser}}; + } + + //TC915100 + @Test + public void creatNewUserTest() throws Exception { + + String userId = generateValidUserId(); + UserRoleEnum userRole = UserRoleEnum.DESIGNER; + AdminWorkspaceUIUtilies.createNewUser(userId, userRole); + UserManagementVerificator.validateUserCreated(userId, userRole); + } + + //TC922253 + @Test + public void creatNewUser_MacIdTest() throws Exception { + + String macId = generateValidMacId(); + UserRoleEnum userRole = UserRoleEnum.DESIGNER; + AdminWorkspaceUIUtilies.createNewUser(macId, userRole); + UserManagementVerificator.validateUserCreated(macId, userRole); + } + + //TC922253 + @Test + public void createExistingUserTest(){ + String userId = generateValidUserId(); + UserRoleEnum userRole = UserRoleEnum.DESIGNER; + AdminWorkspaceUIUtilies.createNewUser(userId, userRole); + ExtentTestActions.log(Status.INFO, "Trying to create the same user once again."); + AdminWorkspaceUIUtilies.createNewUser(userId, userRole); + ErrorMessageUIVerificator.validateErrorMessage(ActionStatus.USER_ALREADY_EXIST); + } + + //TC922253 + @Test + public void createInvalidMacIdTest(){ + String macId = generateValidMacId(); + StringBuilder invalidMacId = new StringBuilder(macId); + invalidMacId.setCharAt(0, 'a'); + UserRoleEnum userRole = UserRoleEnum.DESIGNER; + ExtentTestActions.log(Status.INFO, "Trying to create an invalid macId."); + AdminWorkspaceUIUtilies.createNewUser(invalidMacId.toString(), userRole); + ErrorMessageUIVerificator.validateErrorMessage(ActionStatus.INVALID_USER_ID); + } + + //TC922253 + @Test + public void specialCharInUserIdTest(){ + String expectedErrorMsg = "User id not valid."; + String userId = generateValidUserId(); + StringBuilder invalidUserId = new StringBuilder(userId); + invalidUserId.setCharAt(1, '#'); + ExtentTestActions.log(Status.INFO, String.format("Trying to create an invalid user with special character (%s)", userId)); + AdminGeneralPage.getUserManagementTab().setNewUserBox(invalidUserId.toString()); + ExtentTestActions.log(Status.INFO, "Validating an error message is displayed as a result of invalid character."); + List inputErrors = null; + int inputErrorsSize = 0; + + try{ + WebElement inputField = GeneralUIUtils.getWebElementByClassName("input-error"); + ExtentTestActions.log(Status.INFO, String.format("Validating the message is : '%s'", expectedErrorMsg)); + inputErrors = inputField.findElements(By.className("ng-scope")); + inputErrorsSize = inputErrors.size(); + for (WebElement err : inputErrors){ + String actualErrorMessage = err.getText(); + if (actualErrorMessage.equals(expectedErrorMsg)){ + inputErrorsSize--; + } + } + } + catch(Exception e){ + ExtentTestActions.log(Status.INFO, "Did not find an error input."); + Assert.fail("Did not find an error message input."); + } + + Assert.assertEquals(inputErrors.size() - 1 , inputErrorsSize, "Did not find an error : " + expectedErrorMsg); + } + + //TC915101 + @Test(dataProvider = "searchValues") + public void searchUserByCriterionsTest(String searchCriterion, User user) throws IOException{ + setLog(searchCriterion); + AdminWorkspaceUIUtilies.searchForUser(searchCriterion); + UserManagementVerificator.validateFirstRowDisplayedCorrectly(user); + } + + //TC915101 + @Test + public void searchForUserByRoleTest(){ + String userId = generateValidUserId(); + UserRoleEnum userRole = UserRoleEnum.DESIGNER; + AdminWorkspaceUIUtilies.createNewUser(userId, userRole); + AdminWorkspaceUIUtilies.searchForUser(userRole.name()); + List allRows = GeneralUIUtils.getWebElementsListByContainTestID(DataTestIdEnum.UserManagementEnum.USER_ID.getValue()); + ExtentTestActions.log(Status.INFO, String.format("Found %s rows, looking for the user %s.", allRows.size(), userId)); + int rowsCount = allRows.size(); + for (int i = 0 ; i < allRows.size() ; i++){ + String userIdFromTable = GeneralUIUtils.getTextContentAttributeValue(allRows.get(i)); + if (userIdFromTable.equals(userId)){ + rowsCount--; + break; + } + } + Assert.assertEquals(allRows.size() - 1 , rowsCount , "Did not find a row with the userId " + userId); + } + + //TC915102 + @Test + public void modifyUserRoleTest(){ + User user = new User(); + user.setUserId(generateValidUserId()); + UserRoleEnum userRole = UserRoleEnum.DESIGNER; + AdminWorkspaceUIUtilies.createNewUser(user.getUserId(), userRole); + UserRoleEnum updatedUserRole = UserRoleEnum.TESTER; + AdminWorkspaceUIUtilies.updateUserRole(0, updatedUserRole); + UserManagementVerificator.validateUserRoleUpdated(0, updatedUserRole); + UserManagementVerificator.validateUserRoleUpdatedViaRest(user, getUser(), updatedUserRole); + } + + //TC915103 + @Test + public void deleteUserTest(){ + User user = new User(); + user.setUserId(generateValidUserId()); + UserRoleEnum userRole = UserRoleEnum.DESIGNER; + AdminWorkspaceUIUtilies.createNewUser(user.getUserId(), userRole); + AdminWorkspaceUIUtilies.deleteFirstRow(); + UserManagementVerificator.validateUserIdNotFound(user.getUserId()); + UserManagementVerificator.validateUserNotFoundViaRest(user, getUser()); + } + + //TC951428 + @Test + public void modifyUserRoleWithTaskInHand_Checkout() throws Exception{ + User newUser = new User(); + newUser.setUserId(generateValidUserId()); + UserRoleEnum userRole = UserRoleEnum.DESIGNER; + AdminWorkspaceUIUtilies.createNewUser(newUser.getUserId(), userRole); + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, newUser); + ExtentTestActions.log(Status.INFO, "Creating a new VF named " + resourceMetaData.getName() + " with the user " + newUser.getUserId()); + RestResponse createResourceResp = ResourceRestUtils.createResource(resourceMetaData, newUser); + Assert.assertEquals(createResourceResp.getErrorCode().intValue(), 201, "Did not succeed to create a VF"); + + UserRoleEnum updatedUserRole = UserRoleEnum.TESTER; + AdminWorkspaceUIUtilies.updateUserRole(0, updatedUserRole); + + ErrorMessageUIVerificator.validateErrorMessage(ActionStatus.CANNOT_UPDATE_USER_WITH_ACTIVE_ELEMENTS); + } + + @Test + public void modifyUserRoleWithTaskInHand_InTesting() throws Exception{ + User newTesterUser = new User(); + newTesterUser.setUserId(generateValidUserId()); + UserRoleEnum userTesterRole = UserRoleEnum.TESTER; + userTesterRole.setUserId(newTesterUser.getUserId()); + AdminWorkspaceUIUtilies.createNewUser(newTesterUser.getUserId(), userTesterRole); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ExtentTestActions.log(Status.INFO, "Creating a new VF named " + resourceMetaData.getName()); + ResourceUIUtils.createResource(resourceMetaData, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(resourceMetaData.getName()); + Resource resourceObjectByNameAndVersion = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, resourceMetaData.getName(), "0.1"); + ExtentTestActions.log(Status.INFO, "Getting the VF to 'In Testing' state."); + AtomicOperationUtils.changeComponentState(resourceObjectByNameAndVersion, userTesterRole, LifeCycleStatesEnum.STARTCERTIFICATION, true); + ExtentTestActions.log(Status.INFO, "Succeeded - The VF is in testing state."); + + reloginWithNewRole(UserRoleEnum.ADMIN); + UserRoleEnum updatedUserRole = UserRoleEnum.DESIGNER; + AdminWorkspaceUIUtilies.searchForUser(newTesterUser.getUserId()); + AdminWorkspaceUIUtilies.updateUserRole(0, updatedUserRole); + + ErrorMessageUIVerificator.validateErrorMessage(ActionStatus.CANNOT_UPDATE_USER_WITH_ACTIVE_ELEMENTS); + } + + + private static String generateValidUserId() { + String charsPattern = "abcdefghijklmnopqrstuvwxyz"; + String digitPatter = "0123456789"; + String chars = ResourceUIUtils.buildStringFromPattern(charsPattern, 2); + String digits = ResourceUIUtils.buildStringFromPattern(digitPatter, 4); + return chars + digits; + } + + private String generateValidMacId() { + String digitPatter = "0123456789"; + String digits = ResourceUIUtils.buildStringFromPattern(digitPatter, 5); + return "m" + digits; + } + + private User createNewUserUsingAPI() { + UserRoleEnum role = UserRoleEnum.DESIGNER; + String userId = generateValidUserId(); + User userByEnv = new User("Tzemer", "Gefen", userId, "userId@intl.sdc.com", role.name(), null); + User adminUser = getUserByEnv(UserRoleEnum.ADMIN); + try { + RestResponse createUserResp = UserRestUtils.createUser(userByEnv, adminUser); + Assert.assertEquals(createUserResp.getErrorCode().intValue(), 201, "Did not succeed to create a new user using API."); + } catch (IOException e) { + e.printStackTrace(); + } + return userByEnv; + } + + + private User getUserByEnv(UserRoleEnum userRole) { + try{ + if (!getConfig().getUrl().contains("localhost") && !getConfig().getUrl().contains("127.0.0.1")) { + return getUserFromFileByRole(userRole); + } + else{ + return getUser(userRole); + } + } + catch (Exception e){ + throw new RuntimeException(e); + } + } + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.ADMIN; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/CatalogLeftPanelTest.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/CatalogLeftPanelTest.java new file mode 100644 index 0000000000..10389d9331 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/CatalogLeftPanelTest.java @@ -0,0 +1,236 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.CheckBoxStatusEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.CatalogPageLeftPanelSubCategoryCheckbox; +import org.openecomp.sdc.ci.tests.datatypes.LifeCycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.TopMenuButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.TypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.CatalogUIUtilitis; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.verificator.CatalogVerificator; +import org.openqa.selenium.WebElement; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; + +@Test(singleThreaded = true) +public class CatalogLeftPanelTest extends SetupCDTest{ + + private String filePath; + @BeforeMethod + public void beforeTest(){ + filePath = System.getProperty("filepath"); + + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath(); + } + + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator; + } + } + + public static String[] resourceTypes = Arrays.stream(ResourceTypeEnum.class.getEnumConstants()). + map(ResourceTypeEnum::name).toArray(String[]::new); + + public static String[] catalogTypes = {"RESOURCE", "SERVICE", "PRODUCT"}; + + public static Object[][] provideData(String[] arObj) { + Object[][] arObject = new Object[arObj.length][]; + + int index = 0; + for (Object obj : arObj) { + arObject[index++] = new Object[]{obj}; + } + return arObject; + } + + @DataProvider(name = "Resource_Type_List") + private static final Object[][] resourceTypeList(){ + // Extract names of constants from enum as array of Strings + ResourceTypeEnum[] resourceEnums = {ResourceTypeEnum.CP, ResourceTypeEnum.VF, ResourceTypeEnum.VFC, ResourceTypeEnum.VL}; + String[] resourcesForTest = Arrays.stream(resourceEnums).map(ResourceTypeEnum::name).toArray(String[]::new); + return provideData(resourcesForTest); + } + + @DataProvider(name = "Type_List") + private static final Object[][] typeList(){ + // Extract names of constants from enum as array of Strings + Object[][] arObject = new Object[catalogTypes.length][]; + int index = 0; + for (String catalogType : catalogTypes) { + if (catalogType.equals("RESOURCE")){ + arObject[index++] = new Object[]{catalogType, resourceTypes}; + } else { + arObject[index++] = new Object[]{catalogType, new String[] {catalogType}}; + } + } + return arObject; + } + + @DataProvider(name = "Status_List") + private static final Object[][] statusList(){ + CheckBoxStatusEnum[] checkboxes = {CheckBoxStatusEnum.CERTIFIED, + CheckBoxStatusEnum.IN_DESIGN, + CheckBoxStatusEnum.DISTRIBUTED, + CheckBoxStatusEnum.IN_TESTING, + CheckBoxStatusEnum.READY_FOR_TESTING}; + Object[][] arObject = new Object[checkboxes.length][]; + int index = 0; + for (CheckBoxStatusEnum checkbox: checkboxes) { + if (checkbox.equals(CheckBoxStatusEnum.CERTIFIED)){ + arObject[index++] = new Object[]{checkbox, Arrays.asList(LifeCycleStateEnum.CERTIFIED, LifeCycleStateEnum.DISTRIBUTED, LifeCycleStateEnum.WAITING_FOR_DISTRIBUTION) }; + } else if (checkbox.equals(CheckBoxStatusEnum.IN_DESIGN)) { + arObject[index++] = new Object[]{checkbox, Arrays.asList(LifeCycleStateEnum.CHECKIN, LifeCycleStateEnum.CHECKOUT)}; + } else if (checkbox.equals(CheckBoxStatusEnum.DISTRIBUTED)) { + arObject[index++] = new Object[]{checkbox, Arrays.asList(LifeCycleStateEnum.DISTRIBUTED)}; + } else if (checkbox.equals(CheckBoxStatusEnum.IN_TESTING)) { + arObject[index++] = new Object[]{checkbox, Arrays.asList(LifeCycleStateEnum.IN_TESTING)}; + } else if (checkbox.equals(CheckBoxStatusEnum.READY_FOR_TESTING)) { + arObject[index++] = new Object[]{checkbox, Arrays.asList(LifeCycleStateEnum.READY_FOR_TESTING)}; + } + } + return arObject; + } + + // filter by Type Resource in catalog + @Test(dataProvider = "Type_List") + public void filterByType(String catalogType, String[] classValues ) throws Exception { + setLog(catalogType); +// getExtendTest().setDescription(catalogType); + + CatalogUIUtilitis.clickTopMenuButton(TopMenuButtonsEnum.CATALOG); + CatalogUIUtilitis.catalogFilterTypeChecBox(TypesEnum.valueOf(catalogType)); + + CatalogVerificator.validateType(TypesEnum.valueOf(catalogType)); + } + + @Test(dataProvider = "Resource_Type_List") + public void filterByResourceType(String resourceType) throws Exception { + setLog(resourceType); +// getExtendTest().setDescription(resourceType); + + CatalogUIUtilitis.clickTopMenuButton(TopMenuButtonsEnum.CATALOG); + CatalogUIUtilitis.catalogFilterTypeChecBox(TypesEnum.valueOf(resourceType)); + + CatalogVerificator.validateType(TypesEnum.valueOf(resourceType)); + } + + @Test(dataProvider = "Status_List") + public void filterByStatus(CheckBoxStatusEnum statusCheckbox, List lifecycleStates) throws Exception{ + setLog(statusCheckbox.name()); +// getExtendTest().setDescription(statusCheckbox.name()); + + CatalogUIUtilitis.clickTopMenuButton(TopMenuButtonsEnum.CATALOG); + CatalogUIUtilitis.clickOnLeftPanelElement(DataTestIdEnum.CatalogPageLeftPanelFilterTitle.CATEGORIES); + CatalogUIUtilitis.catalogFilterStatusChecBox(statusCheckbox); + + CatalogVerificator.validateStatus(lifecycleStates, statusCheckbox.name()); + } + + @Test + public void filterByUpperCategory() throws Exception{ + CatalogUIUtilitis.clickTopMenuButton(TopMenuButtonsEnum.CATALOG); + CatalogUIUtilitis.clickOnLeftPanelElement(DataTestIdEnum.CatalogPageLeftPanelFilterTitle.TYPE); + + WebElement categorieCheckbox = CatalogUIUtilitis.clickOnUpperCategoryCheckbox(); + + CatalogVerificator.validateCategory(categorieCheckbox.getAttribute("textContent").trim()); + } + + @Test + public void filterByGenericDtabaseSubCategory() throws Exception{ + CatalogUIUtilitis.clickTopMenuButton(TopMenuButtonsEnum.CATALOG); + CatalogUIUtilitis.clickOnLeftPanelElement(DataTestIdEnum.CatalogPageLeftPanelFilterTitle.TYPE); + + WebElement checkboxElement = GeneralUIUtils.getElementsByCSS(CatalogPageLeftPanelSubCategoryCheckbox.DATABASE.getValue()).get(0); + String checkboxElementName = checkboxElement.getAttribute("textContent").trim(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s subcategory ...", checkboxElementName)); + GeneralUIUtils.clickOnAreaJS(checkboxElement); + CatalogVerificator.validateSubCategory("Generic", checkboxElementName); + } + + @Test(priority = 1) + public void lastUpdatedService() throws Exception{ + // create service + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ResourceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + CatalogUIUtilitis.clickTopMenuButton(TopMenuButtonsEnum.CATALOG); + List cardElements = GeneralUIUtils.getElementsByCSS(DataTestIdEnum.DashboardCardEnum.INFO_NAME.getValue()); + String firstElementName = cardElements.get(0).getAttribute("textContent").trim(); + assertTrue(String.format("Wrong element name, Exepected : %s , Actual: %s", serviceMetadata.getName(), firstElementName), serviceMetadata.getName().equals(firstElementName)); + } + + @Test(priority = 17) + public void lastUpdatedResource() throws Exception{ + // create resource + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.clickCheckinButton(vfMetaData.getName()); + CatalogUIUtilitis.clickTopMenuButton(TopMenuButtonsEnum.CATALOG); + List cardElements = GeneralUIUtils.getElementsByCSS(DataTestIdEnum.DashboardCardEnum.INFO_NAME.getValue()); + String firstElementName = cardElements.get(0).getAttribute("textContent").trim(); + assertTrue(String.format("Wrong element name, Exepected : %s , Actual: %s", vfMetaData.getName(), firstElementName), vfMetaData.getName().equals(firstElementName)); + } + + @Test(priority = 5) + public void fromCatalogCheckout() throws Exception{ + // create resource + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.clickCheckinButton(vfMetaData.getName()); + CatalogUIUtilitis.clickTopMenuButton(TopMenuButtonsEnum.CATALOG); + GeneralUIUtils.findComponentAndClickInCatalog(vfMetaData.getName()); + ResourceGeneralPage.clickCheckoutButton(); + ResourceGeneralPage.clickCheckinButton(vfMetaData.getName()); + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Categories.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Categories.java new file mode 100644 index 0000000000..d2c787e4e5 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Categories.java @@ -0,0 +1,213 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import java.util.List; +import java.util.stream.Collectors; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.AdminGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openqa.selenium.WebElement; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class Categories extends SetupCDTest { + + + @Test + public void createResourceCategory() throws Exception { + + AdminGeneralPage.selectCategoryManagmetTab(); + String newResourceCategory = ElementFactory.getDefaultCategory().getName(); + AdminGeneralPage.createNewResourceCategory(newResourceCategory); + GeneralUIUtils.clickSomewhereOnPage(); + List resourceCategoriesList = AdminGeneralPage.getResourceCategoriesList(); + List collect = resourceCategoriesList.stream().map(f -> f.getText()).collect(Collectors.toList()); + collect.contains(newResourceCategory); + + + } + + @Test + public void createServiceCategory() throws Exception { + + AdminGeneralPage.selectCategoryManagmetTab(); + String newserviceCategory = ElementFactory.getDefaultCategory().getName(); + AdminGeneralPage.createNewServiceCategory(newserviceCategory); + GeneralUIUtils.clickSomewhereOnPage(); + List serviceCategoriesList = AdminGeneralPage.getServiceCategoriesList(); + List collect = serviceCategoriesList.stream().map(f -> f.getText()).collect(Collectors.toList()); + collect.contains(newserviceCategory); + + } + + + @Test + public void createResourceSubCategory() throws Exception { + + AdminGeneralPage.selectCategoryManagmetTab(); + String newResourceCategory = ElementFactory.getDefaultCategory().getName(); + String newserviceCategory = ElementFactory.getDefaultCategory().getName(); + String newSubCategory = ElementFactory.getDefaultSubCategory().getName(); + AdminGeneralPage.createNewResourceCategory(newResourceCategory); + AdminGeneralPage.createNewServiceCategory(newserviceCategory); + List serviceCategoriesList = AdminGeneralPage.getServiceCategoriesList(); + List resourceCategoriesList = AdminGeneralPage.getResourceCategoriesList(); + AdminGeneralPage.addSubCategoryToResource(resourceCategoriesList, newResourceCategory , newSubCategory); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.clickSomewhereOnPage(); + + + } + + + @Test + public void createExistingResourceCategory() throws Exception { + + AdminGeneralPage.selectCategoryManagmetTab(); + String newResourceCategory = ElementFactory.getDefaultCategory().getName(); + AdminGeneralPage.createNewResourceCategory(newResourceCategory); + AdminGeneralPage.createNewResourceCategory(newResourceCategory); + + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + + + } + + @Test + public void createExistingServiceCategory() throws Exception { + + AdminGeneralPage.selectCategoryManagmetTab(); + String newserviceCategory = ElementFactory.getDefaultCategory().getName(); + AdminGeneralPage.createNewServiceCategory(newserviceCategory); + AdminGeneralPage.createNewServiceCategory(newserviceCategory); + AdminGeneralPage.selectUserManagmetTab(); + + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.COMPONENT_CATEGORY_ALREADY_EXISTS.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + + } + + @Test + public void createExsitingResourceSubCategory() throws Exception { + + + AdminGeneralPage.selectCategoryManagmetTab(); + String newResourceCategory = ElementFactory.getDefaultCategory().getName(); + String newserviceCategory = ElementFactory.getDefaultCategory().getName(); + String newSubCategory = ElementFactory.getDefaultSubCategory().getName(); + AdminGeneralPage.createNewResourceCategory(newResourceCategory); + AdminGeneralPage.createNewServiceCategory(newserviceCategory); + List serviceCategoriesList = AdminGeneralPage.getServiceCategoriesList(); + List resourceCategoriesList = AdminGeneralPage.getResourceCategoriesList(); + AdminGeneralPage.addSubCategoryToResource(resourceCategoriesList, newResourceCategory , newSubCategory); + AdminGeneralPage.addSubCategoryToResource(resourceCategoriesList, newResourceCategory , newSubCategory); + GeneralUIUtils.waitForLoader(); + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.COMPONENT_SUB_CATEGORY_EXISTS_FOR_CATEGORY.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + + } + + + @Test + public void createServiceWithNewCategory() throws Exception { + + AdminGeneralPage.selectCategoryManagmetTab(); + String newResourceCategory = ElementFactory.getDefaultCategory().getName(); + String newserviceCategory = ElementFactory.getDefaultCategory().getName(); + String newSubCategory = ElementFactory.getDefaultSubCategory().getName(); + AdminGeneralPage.createNewResourceCategory(newResourceCategory); + AdminGeneralPage.createNewServiceCategory(newserviceCategory); + List serviceCategoriesList = AdminGeneralPage.getServiceCategoriesList(); + List resourceCategoriesList = AdminGeneralPage.getResourceCategoriesList(); + AdminGeneralPage.addSubCategoryToResource(resourceCategoriesList, newResourceCategory , newSubCategory); + GeneralUIUtils.waitForLoader(); + AdminGeneralPage.selectUserManagmetTab(); + reloginWithNewRole(UserRoleEnum.DESIGNER); + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + List categories = serviceMetadata.getCategories(); + categories.get(0).setName(newserviceCategory); + + ServiceUIUtils.createService(serviceMetadata, getUser()); + + } + + + @Test + public void createResourceWithNewCategory() throws Exception { + + AdminGeneralPage.selectCategoryManagmetTab(); + String newResourceCategory = ElementFactory.getDefaultCategory().getName(); + String newserviceCategory = ElementFactory.getDefaultCategory().getName(); + String newSubCategory = ElementFactory.getDefaultSubCategory().getName(); + AdminGeneralPage.createNewResourceCategory(newResourceCategory); + AdminGeneralPage.createNewServiceCategory(newserviceCategory); + List serviceCategoriesList = AdminGeneralPage.getServiceCategoriesList(); + List resourceCategoriesList = AdminGeneralPage.getResourceCategoriesList(); + AdminGeneralPage.addSubCategoryToResource(resourceCategoriesList, newResourceCategory , newSubCategory); + GeneralUIUtils.waitForLoader(); + AdminGeneralPage.selectUserManagmetTab(); + reloginWithNewRole(UserRoleEnum.DESIGNER); + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + List categories = resourceMetaData.getCategories(); + CategoryDefinition categoryDefinition = categories.get(0); + categoryDefinition.setName(newResourceCategory); + SubCategoryDefinition subCategoryDefinition = categoryDefinition.getSubcategories().get(0); + subCategoryDefinition.setName(newSubCategory); + + ResourceUIUtils.createResource(resourceMetaData, getUser()); + + + } + + + + + + + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.ADMIN; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/CustomizationUUID.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/CustomizationUUID.java new file mode 100644 index 0000000000..2c2b09af22 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/CustomizationUUID.java @@ -0,0 +1,383 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.ServiceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.TesterOperationPage; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.verificator.CustomizationUUIDVerificator; +import org.openecomp.sdc.ci.tests.verificator.ServiceVerificator; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; + +public class CustomizationUUID extends SetupCDTest { + + private static final String DESCRIPTION = "kuku"; + private static final String ARTIFACT_LABEL = "artifact3"; + private static final String ARTIFACT_LABEL_UPDATE = "artifactUpdate"; + private static final String GET_ARTIFACT_LIST_BY_CLASS_NAME = "i-sdc-designer-sidebar-section-content-item-artifact"; + private static final String HEAT_FILE_YAML_NAME = "Heat-File.yaml"; + private static final String HEAT_FILE_YAML_UPDATE_NAME = "Heat-File-Update.yaml"; + private String filePath; + + @BeforeMethod + public void beforeTest(){ + filePath = System.getProperty("filepath"); + + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath(); + } + + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator; + } + } + + @Test + public void uniqueCustomizationUUIDforeachVFi() throws Exception { + + + ResourceReqDetails vfMetaData = createNewResourceWithArtifactSubmitForTesting(); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + TesterOperationPage.certifyComponent(vfMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + + List customizationUUIDs = new ArrayList(); + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement VFiElement1 = addElemntToCanvas(vfMetaData, canvasManager); + CanvasElement VFiElement2 = addElemntToCanvas(vfMetaData, canvasManager); + CanvasElement VFiElement3 = addElemntToCanvas(vfMetaData, canvasManager); + + + ServiceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement1); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement2); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement3); + + ServiceGeneralPage.clickCheckoutButton(); + canvasManager = CanvasManager.getCanvasManager(); + CanvasElement VFiElement4 = addElemntToCanvas(vfMetaData, canvasManager); + CanvasElement VFiElement5 = addElemntToCanvas(vfMetaData, canvasManager); + CanvasElement VFiElement6 = addElemntToCanvas(vfMetaData, canvasManager); + + ServiceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement4); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement5); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement6); + + CustomizationUUIDVerificator.validateCustomizationUUIDuniqueness(customizationUUIDs); + + + } + + + @Test + public void uniqueCustomizationUUIDafterArtifactCRUDofVFi() throws Exception { + + + ResourceReqDetails vfMetaData = createNewResourceWithArtifactSubmitForTesting(); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + TesterOperationPage.certifyComponent(vfMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + + List customizationUUIDs = new ArrayList<>(); + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement VFiElement1 = addElemntToCanvas(vfMetaData, canvasManager); + + ServiceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement1); + + //add artifact to VFI + + ServiceGeneralPage.clickCheckoutButton(); + canvasManager = CanvasManager.getCanvasManager(); + + ArtifactInfo artifact = new ArtifactInfo(filePath, HEAT_FILE_YAML_NAME, DESCRIPTION, ARTIFACT_LABEL,ArtifactTypeEnum.SNMP_POLL.getType()); + + canvasManager.clickOnCanvaElement(VFiElement1); + CompositionPage.showDeploymentArtifactTab(); + CompositionPage.clickAddArtifactButton(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(artifact, CompositionPage.artifactPopup()); + + + ServiceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement1); + + + //delete VFI artifacts + + ServiceGeneralPage.clickCheckoutButton(); + canvasManager = CanvasManager.getCanvasManager(); + canvasManager.clickOnCanvaElement(VFiElement1); + CompositionPage.showDeploymentArtifactTab(); + List actualArtifactList = GeneralUIUtils.getWebElementsListBy(By.className(GET_ARTIFACT_LIST_BY_CLASS_NAME)); + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_ITEM.getValue() + ARTIFACT_LABEL); + SetupCDTest.getExtendTest().log(Status.INFO, "Going to delete " + HEAT_FILE_YAML_NAME + " artifact" + " and check if deleted"); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DELETE.getValue() + ARTIFACT_LABEL); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + + + ServiceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement1); + + + CustomizationUUIDVerificator.validateCustomizationUUIDuniqueness(customizationUUIDs); + + } + + + @Test + public void uniqueCustomizationUUIDchangeVFiVersion() throws Exception { + + + ResourceReqDetails vfMetaData = createNewResourceWithArtifactSubmitForTesting(); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + TesterOperationPage.certifyComponent(vfMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + + List customizationUUIDs = new ArrayList<>(); + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement VFiElement1 = addElemntToCanvas(vfMetaData, canvasManager); + + ServiceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement1); + + //change VF version + HomePage.navigateToHomePage(); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + ResourceGeneralPage.clickCheckoutButton(); + ResourceGeneralPage.clickSubmitForTestingButton(vfMetaData.getName()); + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + TesterOperationPage.certifyComponent(vfMetaData.getName()); + reloginWithNewRole(UserRoleEnum.DESIGNER); + + //update VFI version + + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + ServiceGeneralPage.clickCheckoutButton(); + canvasManager = CanvasManager.getCanvasManager(); + canvasManager.clickOnCanvaElement(VFiElement1); + CompositionPage.changeComponentVersion(canvasManager, VFiElement1, "2.0"); + + ServiceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement1); + + CustomizationUUIDVerificator.validateCustomizationUUIDuniqueness(customizationUUIDs); + + } + + + @Test + public void uniqueCustomizationUUIDaddRelation() throws Exception { + + + ResourceReqDetails vfMetaData = createNewResourceWithArtifactSubmitForTesting(); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + TesterOperationPage.certifyComponent(vfMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + + List customizationUUIDs = new ArrayList<>(); + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement VFiElement1 = addElemntToCanvas(vfMetaData, canvasManager); + + ServiceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement1); + + //change VF version + HomePage.navigateToHomePage(); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + ResourceGeneralPage.clickCheckoutButton(); + ResourceGeneralPage.clickSubmitForTestingButton(vfMetaData.getName()); + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + TesterOperationPage.certifyComponent(vfMetaData.getName()); + reloginWithNewRole(UserRoleEnum.DESIGNER); + + //update VFI version + + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + ServiceGeneralPage.clickCheckoutButton(); + canvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(NormativeTypesEnum.PORT.getFolderName()); + CanvasElement portElement = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.PORT); + canvasManager.linkElements(portElement, VFiElement1); + + canvasManager.clickOnCanvaElement(VFiElement1); + + + ServiceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + canvasManager = findServiceAndNavigateToCanvas(serviceMetadata); + addCanvasElementToList(customizationUUIDs, canvasManager, VFiElement1); + + CustomizationUUIDVerificator.validateCustomizationUUIDuniqueness(customizationUUIDs); + + } + + + + public CanvasManager findServiceAndNavigateToCanvas(ServiceReqDetails serviceMetadata) throws Exception { + CanvasManager canvasManager; + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + ServiceGeneralPage.getLeftMenu().moveToCompositionScreen(); + canvasManager = CanvasManager.getCanvasManager(); + return canvasManager; + } + + public ResourceReqDetails createNewResourceWithArtifactSubmitForTesting() throws Exception { + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + List deploymentArtifactList = new ArrayList(); + deploymentArtifactList.add(new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER")); + deploymentArtifactList.add(new ArtifactInfo(filePath, "sample-xml-alldata-1-1.xml", "cuku", "artifact2", "YANG_XML")); + for (ArtifactInfo deploymentArtifact : deploymentArtifactList) { + DeploymentArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(deploymentArtifact); + } + AssertJUnit.assertTrue("artifact table does not contain artifacts uploaded", DeploymentArtifactPage.checkElementsCountInTable(deploymentArtifactList.size())); + + String newDescription = "new description"; + DeploymentArtifactPage.clickEditArtifact(deploymentArtifactList.get(0).getArtifactLabel()); + DeploymentArtifactPage.artifactPopup().insertDescription(newDescription); + DeploymentArtifactPage.artifactPopup().clickDoneButton(); + String actualArtifactDescription = DeploymentArtifactPage.getArtifactDescription(deploymentArtifactList.get(0).getArtifactLabel()); + AssertJUnit.assertTrue("artifact description is not updated", newDescription.equals(actualArtifactDescription)); + + DeploymentArtifactPage.clickDeleteArtifact(deploymentArtifactList.get(0).getArtifactLabel()); + DeploymentArtifactPage.clickOK(); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + +// ResourceReqDetails vfcCompute = ElementFactory.getDefaultResource(NormativeTypesEnum.COMPUTE); + CompositionPage.searchForElement(NormativeTypesEnum.COMPUTE.name()); + CanvasManager canvasManagerVF = CanvasManager.getCanvasManager(); + CanvasElement VFiElement1 = canvasManagerVF.createElementOnCanvas(LeftPanelCanvasItems.COMPUTE); + + + ResourceGeneralPage.clickSubmitForTestingButton(vfMetaData.getName()); + return vfMetaData; + } + + public void addCanvasElementToList(List customizationUUIDs, CanvasManager canvasManager, CanvasElement VFiElement1) + throws Exception { + canvasManager.clickOnCanvaElement(VFiElement1); + WebElement VFi1customizationUUID = CompositionPage.getCustomizationUUID(); + customizationUUIDs.add(VFi1customizationUUID.getText()); + } + + public CanvasElement addElemntToCanvas(ResourceReqDetails vfMetaData, CanvasManager canvasManager) + throws Exception { + CompositionPage.searchForElement(vfMetaData.getName()); + CanvasElement VFiElement1 = canvasManager.createElementOnCanvas(vfMetaData.getName()); + return VFiElement1; + } + + public static void changeDeleteAndValidateVersionOnGeneralPage(String previousVersion, String currentVersion, String serviceName) throws Exception{ + GeneralPageElements.selectVersion("V" + previousVersion); + ServiceVerificator.verifyVersionUI(previousVersion); + GeneralUIUtils.clickJSOnElementByText("latest version"); + ServiceVerificator.verifyVersionUI(currentVersion); + GeneralPageElements.clickTrashButtonAndConfirm(); + GeneralUIUtils.findComponentAndClick(serviceName); + ServiceVerificator.verifyVersionUI(previousVersion); + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/DeploymentViewTests.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/DeploymentViewTests.java new file mode 100644 index 0000000000..87bf7b0506 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/DeploymentViewTests.java @@ -0,0 +1,286 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.DeploymentPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.verificator.DeploymentViewVerificator; +import org.openqa.selenium.WebElement; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; + +public class DeploymentViewTests extends SetupCDTest { + + private String filePath; + + @BeforeMethod + public void beforeTest(){ + filePath = System.getProperty("filepath"); + + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath(); + } + + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator; + } + } + + @DataProvider(name = "CSAR_VF_Files", parallel = false) + public Object[][] createDataX() { + return new Object[][] { { "vSeGWdoubleMembers.csar" }, { "vSeGW.csar" }, {"vSeGWsingleModule.csar"}}; + } + + + @Test(dataProvider = "CSAR_VF_Files") + public void deploymentScreenDCAEAssetImportCSARTest(String baseFileName) throws Exception{ + // + setLog(baseFileName); +// getExtendTest().setDescription(baseFileName); + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, baseFileName, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentViewScreen(); + List moduleRowsFromTable = GeneralUIUtils.getElementsByCSS(DataTestIdEnum.DeploymentScreen.MODULES.getValue()); + DeploymentViewVerificator verificator = new DeploymentViewVerificator(filePath + baseFileName); + verificator.verifyDeploymentPageModules(moduleRowsFromTable); + for(WebElement moduleRow :moduleRowsFromTable){ + String moduleRowText = moduleRow.getText(); + verificator.verifyDeploymentPageSubElements(moduleRowText.split("\\.\\.")[1]); + DeploymentPage.updateModuleName(moduleRowText, "updatedName"); + String updatedModuleName = DeploymentPage.reconstructModuleName(moduleRowText.split("\\.\\."), "updatedName"); + verificator.verifyComponentNameChanged( moduleRowText, updatedModuleName); + // Close module + GeneralUIUtils.clickOnElementByText(updatedModuleName); + } + } + + @Test + public void deploymentScreenDCAEAssetUpdateWithNewGroupCSAR_TC1368223_Test() throws Exception{ + String baseFileName = "baseUpdateMinusGroupFlowVF.csar"; + String updateFileName = "baseUpdateFlowVF.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating resource with %s groups ", 2)); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, baseFileName, getUser()); + + Map> metaDataFromUI = DeploymentPage.collectMetaDataFromUI(); + metaDataFromUI.put("base_ldsa", new HashMap (){ {put("version", "0"); + put("moduleID", "primary");}}); + + // add new group, base_ldsa + ResourceGeneralPage.getLeftMenu().moveToGeneralScreen(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating VF with new file, should be %s groups now", 3)); + ResourceUIUtils.updateVfWithCsar(filePath, updateFileName); + + DeploymentViewVerificator.regularDepoymentScreenVerificator(metaDataFromUI, new DeploymentViewVerificator(filePath + updateFileName)); + DeploymentViewVerificator.validateModuleNameUpadate(); + }; + + @Test + public void deploymentScreenDCAEAssetDeleteGroupFromCSAR_TC1368281_Test() throws Exception{ + String baseFileName = "baseUpdateFlowVF.csar"; + String updateFileName = "baseUpdateMinusGroupFlowVF.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating resource with %s groups ", 3)); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, baseFileName, getUser()); + + Map> metaDataFromUI = DeploymentPage.collectMetaDataFromUI(); + + // remove group base_ldsa + ResourceGeneralPage.getLeftMenu().moveToGeneralScreen(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating VF with new file, should be %s groups now, base_ldsa group should be removed", 2)); + ResourceUIUtils.updateVfWithCsar(filePath, updateFileName); + + // validate that group was removed + DeploymentViewVerificator.regularDepoymentScreenVerificator(metaDataFromUI, new DeploymentViewVerificator(filePath + updateFileName)); + + Map> metaDataFromUI2 = DeploymentPage.collectMetaDataFromUI(); + metaDataFromUI2.put("base_ldsa", new HashMap (){ {put("version", "0"); + put("moduleID", "primary");}}); + + ResourceGeneralPage.getLeftMenu().moveToGeneralScreen(); + // add group base_ldsa + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating VF with new file, should be %s groups now, base_ldsa group should be added", 3)); + ResourceUIUtils.updateVfWithCsar(filePath, baseFileName); + + // validate that group was added + DeploymentViewVerificator.regularDepoymentScreenVerificator(metaDataFromUI2, new DeploymentViewVerificator(filePath + baseFileName)); + DeploymentViewVerificator.validateModuleNameUpadate(); + } + + @Test + public void deploymentScreenDCAEAssetUpdateWithNewGroupWithoutMembersCSAR_TC1368280_Test() throws Exception{ + String baseFileName = "baseUpdateMinusGroupFlowVF.csar"; + String updateFileName = "baseUpdateAddGroupNoMembersUpdateFlow.csar"; + String updateFileName2 = "baseUpdateFlowVF.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating resource with %s groups ", 2)); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, baseFileName, getUser()); + + // add new group without members, base_ldsa + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating VF with new file, should be %s groups now, base_ldsa group without members", 3)); + ResourceUIUtils.updateVfWithCsar(filePath, updateFileName); + + Map> metaDataFromUI = DeploymentPage.collectMetaDataFromUI(); + + // validate that group was added and no members exist + DeploymentViewVerificator.regularDepoymentScreenVerificator(null, new DeploymentViewVerificator(filePath + updateFileName)); + + ResourceGeneralPage.getLeftMenu().moveToGeneralScreen(); + // add group base_ldsa with members + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating VF with new file, should be %s groups now, base_ldsa group with members", 3)); + ResourceUIUtils.updateVfWithCsar(filePath, updateFileName2); + + // validate that member was added to base_ldsa group + DeploymentViewVerificator.regularDepoymentScreenVerificator(metaDataFromUI, new DeploymentViewVerificator(filePath + updateFileName2)); + DeploymentViewVerificator.validateModuleNameUpadate(); + }; + + @Test + public void deploymentScreenDCAEAssetImportCSARWithArtifactSection_TC1368282_1_Test() throws Exception{ + String baseFileName = "baseUpdateFlowTwoArtifactsToGroup.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating resource with %s groups, should be 4 artifacts in every group ", 3)); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, baseFileName, getUser()); + + DeploymentViewVerificator.regularDepoymentScreenVerificator(null, new DeploymentViewVerificator(filePath + baseFileName)); + DeploymentViewVerificator.validateModuleNameUpadate(); + }; + + @Test + public void deploymentScreenDCAEAssetImportCSARRemoveArtifact_TC1368282_2_Test() throws Exception{ + String baseFileName = "baseUpdateFlowTwoArtifactsToGroup.csar"; + String updateFileName = "baseUpdateFlowOneArtifactToGroup.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating resource with %s groups, should be 4 artifacts in every group ", 3)); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, baseFileName, getUser()); + + Map> metaDataFromUI = DeploymentPage.collectMetaDataFromUI(); + + ResourceGeneralPage.getLeftMenu().moveToGeneralScreen(); + // remove artifact from every group + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating VF with new file, should be 3 artifacts in every group")); + ResourceUIUtils.updateVfWithCsar(filePath, updateFileName); + + DeploymentViewVerificator.regularDepoymentScreenVerificator(metaDataFromUI, new DeploymentViewVerificator(filePath + updateFileName)); + DeploymentViewVerificator.validateModuleNameUpadate(); + }; + + @Test + public void deploymentScreenDCAEAssetImportCSARAddArtifact_TC1368282_3_Test() throws Exception{ + String baseFileName = "baseUpdateFlowTwoArtifactsToGroup.csar"; + String updateFileName = "baseUpdateFlowOneArtifactToGroup.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating resource with %s groups, should be 3 artifacts in every group ", 3)); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, updateFileName, getUser()); + + Map> metaDataFromUI = DeploymentPage.collectMetaDataFromUI(); + + ResourceGeneralPage.getLeftMenu().moveToGeneralScreen(); + // add artifact to every group + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating VF with new file, should be 4 artifacts in every group")); + ResourceUIUtils.updateVfWithCsar(filePath, baseFileName); + + DeploymentViewVerificator.regularDepoymentScreenVerificator(metaDataFromUI, new DeploymentViewVerificator(filePath + baseFileName)); + DeploymentViewVerificator.validateModuleNameUpadate(); + }; + + @Test + public void deploymentScreenDCAEAssetImportCSARMixArtifacts_TC1368282_4_Test() throws Exception{ + String baseFileName = "baseUpdateFlowTwoArtifactsToGroup.csar"; + String updateFileName = "baseUpdateMixedArtifacts.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating resource with %s groups, should be 4 artifacts in every group ", 3)); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, baseFileName, getUser()); + + Map> metaDataFromUI = DeploymentPage.collectMetaDataFromUI(); + + ResourceGeneralPage.getLeftMenu().moveToGeneralScreen(); + //mix artifacts between groups + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating VF with new file, mixing between artifacts and groups", 3)); + ResourceUIUtils.updateVfWithCsar(filePath, updateFileName); + + DeploymentViewVerificator.regularDepoymentScreenVerificator(metaDataFromUI, new DeploymentViewVerificator()); + DeploymentViewVerificator.validateModuleNameUpadate(); + }; + + @Test + public void deploymentScreenDCAEAssetUpdateVFModule_TC1296437_Test() throws Exception{ + String baseFileName = "baseUpdateMinusGroupFlowVF.csar"; + String updateFileName = "baseUpdateFlowVF.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating resource with %s groups ", 2)); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, baseFileName, getUser()); +// SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating %s group version, should be %s ", moduleRowText, metaDataFromUI.get(moduleRowText.split("\\.\\.")[1]))); + + Map> metaDataFromUI = DeploymentPage.collectMetaDataFromUI(); + metaDataFromUI.put("base_ldsa", new HashMap (){ {put("version", "0"); + put("moduleID", "primary");}}); + + DeploymentViewVerificator.validateEditPopover(); + + ResourceGeneralPage.getLeftMenu().moveToGeneralScreen(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating VF with new file, should be %s groups now", 3)); + ResourceUIUtils.updateVfWithCsar(filePath, updateFileName); + + assertTrue(resourceMetaData.getName().equals(ResourceGeneralPage.getNameText())); + DeploymentViewVerificator.regularDepoymentScreenVerificator(metaDataFromUI, new DeploymentViewVerificator(filePath + updateFileName)); + DeploymentViewVerificator.validateModuleNameUpadate(); + } + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/ImportDCAE.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/ImportDCAE.java new file mode 100644 index 0000000000..6a80dfe854 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/ImportDCAE.java @@ -0,0 +1,678 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.LifeCycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.InformationalArtifactsPlaceholders; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.ResourceMetadataEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentPage; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openecomp.sdc.ci.tests.pages.InformationalArtifactPage; +import org.openecomp.sdc.ci.tests.pages.InputsPage; +import org.openecomp.sdc.ci.tests.pages.PropertiesPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.TesterOperationPage; +import org.openecomp.sdc.ci.tests.pages.ToscaArtifactsPage; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.PropertiesUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.verificator.ServiceVerificator; +import org.openecomp.sdc.ci.tests.verificator.VfVerificator; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; + +public class ImportDCAE extends SetupCDTest { + + private String filePath; + @BeforeMethod + public void beforeTest(){ + filePath = System.getProperty("filepath"); + + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath(); + } + + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator; + } + } + + @Test + public void updateDCAEAsset() throws Exception { + ResourceReqDetails resourceMetaData = createDCAEAsset(); + + // update Resource + ResourceReqDetails updatedResource = new ResourceReqDetails(); + updatedResource.setName("ciUpdatedNameImportDCAE"); + updatedResource.setDescription("kuku"); + updatedResource.setVendorName("updatedVendor"); + updatedResource.setVendorRelease("updatedRelease"); + updatedResource.setContactId("ab0001"); + updatedResource.setCategories(resourceMetaData.getCategories()); + updatedResource.setVersion("0.1"); + List newTags = resourceMetaData.getTags(); + newTags.remove(resourceMetaData.getName()); + newTags.add(updatedResource.getName()); + updatedResource.setTags(newTags); + ResourceUIUtils.updateResource(updatedResource, getUser()); + + VfVerificator.verifyVFMetadataInUI(updatedResource); + VfVerificator.verifyVFUpdated(updatedResource, getUser()); + } + + @Test + public void vfcLinkedToComputeInDCAEAssetFlowTest() throws Exception { + String fileName = "importVFC_VFC14.yml"; + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + + try{ + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(atomicResourceMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(atomicResourceMetaData.getName()); + TesterOperationPage.certifyComponent(atomicResourceMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + ResourceReqDetails resourceMetaData = createDCAEAsset(); + + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement computeElement = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.COMPUTE); + CompositionPage.searchForElement(atomicResourceMetaData.getName()); + CanvasElement cpElement = canvasManager.createElementOnCanvas(atomicResourceMetaData.getName()); + Assert.assertNotNull(cpElement); + ServiceVerificator.verifyNumOfComponentInstances(resourceMetaData, "0.1", 4, getUser()); + + canvasManager.linkElements(cpElement, computeElement); + + resourceMetaData.setVersion("0.1"); + VfVerificator.verifyLinkCreated(resourceMetaData, getUser(), 1); + } + finally{ + ResourceRestUtils.deleteResourceByNameAndVersion(atomicResourceMetaData.getName(), "1.0"); + } + + } + + @Test + public void addUpdateDeleteDeploymentArtifactToDCAEAssetTest() throws Exception { + createDCAEAsset(); + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + List deploymentArtifactList = new ArrayList(); + deploymentArtifactList.add(new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER")); + deploymentArtifactList.add(new ArtifactInfo(filePath, "sample-xml-alldata-1-1.xml", "cuku", "artifact2", "YANG_XML")); + for (ArtifactInfo deploymentArtifact : deploymentArtifactList) { + DeploymentArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(deploymentArtifact); + } + assertTrue("artifact table does not contain artifacts uploaded", DeploymentArtifactPage.checkElementsCountInTable(deploymentArtifactList.size())); + + String newDescription = "new description"; + DeploymentArtifactPage.clickEditArtifact(deploymentArtifactList.get(0).getArtifactLabel()); + DeploymentArtifactPage.artifactPopup().insertDescription(newDescription); + DeploymentArtifactPage.artifactPopup().clickDoneButton(); + String actualArtifactDescription = DeploymentArtifactPage.getArtifactDescription(deploymentArtifactList.get(0).getArtifactLabel()); + assertTrue("artifact description is not updated", newDescription.equals(actualArtifactDescription)); + + DeploymentArtifactPage.clickDeleteArtifact(deploymentArtifactList.get(0).getArtifactLabel()); + DeploymentArtifactPage.clickOK(); + assertTrue("artifact "+ deploymentArtifactList.get(0).getArtifactLabel() + "is not deleted", DeploymentArtifactPage.checkElementsCountInTable(deploymentArtifactList.size() - 1)); + + assertTrue("artifact "+ deploymentArtifactList.get(1).getArtifactLabel() + "is not displayed", DeploymentArtifactPage.clickOnArtifactDescription(deploymentArtifactList.get(1).getArtifactLabel()).isDisplayed()); + } + + @Test + public void addUpdateDeleteInformationalArtifactDCAEAssetTest() throws Exception { + createDCAEAsset(); + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + ArtifactInfo informationalArtifact = new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER"); + InformationalArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(informationalArtifact); + + assertTrue("artifact table does not contain artifacts uploaded", InformationalArtifactPage.checkElementsCountInTable(1)); + + String newDescription = "new description"; + InformationalArtifactPage.clickEditArtifact(informationalArtifact.getArtifactLabel()); + InformationalArtifactPage.artifactPopup().insertDescription(newDescription); + InformationalArtifactPage.artifactPopup().clickDoneButton(); + String actualArtifactDescription = InformationalArtifactPage.getArtifactDescription(informationalArtifact.getArtifactLabel()); + assertTrue("artifact description is not updated", newDescription.equals(actualArtifactDescription)); + + InformationalArtifactPage.clickDeleteArtifact(informationalArtifact.getArtifactLabel()); + InformationalArtifactPage.clickOK(); + assertTrue("artifact "+ informationalArtifact.getArtifactLabel() + "is not deleted", InformationalArtifactPage.checkElementsCountInTable(0)); + } + + @Test + public void addPropertiesToVfcInstanceInDCAEAssetTest() throws Exception { + String fileName = "importVFC_VFC15.yml"; + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + + try{ + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceGeneralPage.clickCheckinButton(atomicResourceMetaData.getName()); + + createDCAEAsset(); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager vfCanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(atomicResourceMetaData.getName()); + CanvasElement vfcElement = vfCanvasManager.createElementOnCanvas(atomicResourceMetaData.getName()); + + vfCanvasManager.clickOnCanvaElement(vfcElement); + CompositionPage.showPropertiesAndAttributesTab(); + List properties = CompositionPage.getProperties(); + String propertyValue = "abc123"; + for (int i = 0; i < 2; i++) { + WebElement findElement = properties.get(i).findElement(By.className("i-sdc-designer-sidebar-section-content-item-property-and-attribute-label")); + findElement.click(); + PropertiesPage.getPropertyPopup().insertPropertyDefaultValue(propertyValue); + PropertiesPage.getPropertyPopup().clickSave(); + + findElement = properties.get(i).findElement(By.className("i-sdc-designer-sidebar-section-content-item-property-value")); + assertTrue(findElement.getText().equals(propertyValue)); + } + } + finally{ + ResourceRestUtils.deleteResourceByNameAndVersion(atomicResourceMetaData.getName(), "0.1"); + } + } + + @Test + public void changeInstanceVersionDCAEAssetTest() throws Exception{ + ResourceReqDetails atomicResourceMetaData = null; + ResourceReqDetails vfMetaData = null; + CanvasManager vfCanvasManager; + CanvasElement vfcElement = null; + String fileName = "importVFC_VFC16.yml"; + try{ + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(atomicResourceMetaData.getName()); + + vfMetaData = createDCAEAsset(); + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + vfCanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(atomicResourceMetaData.getName()); + vfcElement = vfCanvasManager.createElementOnCanvas(atomicResourceMetaData.getName()); + + CompositionPage.clickSubmitForTestingButton(vfMetaData.getName()); + assert(false); + } + catch(Exception e){ + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.VALIDATED_RESOURCE_NOT_FOUND.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(atomicResourceMetaData.getName()); + TesterOperationPage.certifyComponent(atomicResourceMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + vfCanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.changeComponentVersion(vfCanvasManager, vfcElement, "1.0"); + + //verfication + VfVerificator.verifyInstanceVersion(vfMetaData, getUser(), atomicResourceMetaData.getName(), "1.0"); + } + + finally{ + ResourceRestUtils.deleteResourceByNameAndVersion(atomicResourceMetaData.getName(), "1.0"); + } + + } + + // future removed from ui + @Test(enabled = false) + public void addUpdateDeleteSimplePropertiesToDCAEAssetTest() throws Exception{ + createDCAEAsset(); + + ResourceGeneralPage.getLeftMenu().moveToPropertiesScreen(); + List propertyList = Arrays.asList(PropertyTypeEnum.STRING, PropertyTypeEnum.INTEGER); + int propertiesCount = PropertiesPage.getElemenetsFromTable().size(); + for (PropertyTypeEnum prop : propertyList){ + PropertiesUIUtils.addNewProperty(prop); + } + assertTrue(GeneralUIUtils.checkElementsCountInTable(propertiesCount + propertyList.size(), () -> PropertiesPage.getElemenetsFromTable())); + VfVerificator.verifyPropertiesInUI(propertyList); + PropertiesPage.verifyTotalProperitesField(propertiesCount + propertyList.size()); + + PropertyTypeEnum prop = propertyList.get(0); + prop.setDescription("updatedDescription"); + prop.setValue("value"); + PropertiesUIUtils.updateProperty(prop); + + PropertiesPage.clickDeletePropertyArtifact(prop.getName()); + assertTrue(GeneralUIUtils.checkElementsCountInTable(propertiesCount + propertyList.size() - 1, () -> PropertiesPage.getElemenetsFromTable())); + } + + // future removed from ui + @Test(enabled = false) + public void DCAEAssetInstancesInputScreenTest() throws Exception{ + createDCAEAsset(); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager vfCanvasManager = CanvasManager.getCanvasManager(); + + Map elementsIntancesMap = new HashMap(); + for (LeftPanelCanvasItems element : Arrays.asList(LeftPanelCanvasItems.DATABASE)){ + CanvasElement elementOnCanvas = vfCanvasManager.createElementOnCanvas(element); + vfCanvasManager.clickOnCanvaElement(elementOnCanvas); + String selectedInstanceName = CompositionPage.getSelectedInstanceName(); + elementsIntancesMap.put(selectedInstanceName, element.getValue()); + } + + CompositionPage.moveToInputsScreen(); + int canvasElementsSize = vfCanvasManager.getCanvasElements().size() + 2; + List inputsNamesFromTable = InputsPage.getVFCInstancesNamesFromTable(); + assertTrue(String.format("Instances count is not as Expected: %s Actual: %s", canvasElementsSize, inputsNamesFromTable.size()), inputsNamesFromTable.size() == canvasElementsSize); + + for (String instanceName :inputsNamesFromTable){ + String resourceName = instanceName.split(" ")[0]; + ResourceReqDetails resource = new ResourceReqDetails(); + resource.setName(resourceName); + resource.setVersion("1.0"); + if (resourceName.equals("Port")){ + resource.setResourceType(ResourceTypeEnum.CP.toString()); + } else { + resource.setResourceType(ResourceTypeEnum.VFC.toString()); + } + RestResponse restResponse = RestCDUtils.getResource(resource, getUser()); + Map propertiesNameTypeJson = ResponseParser.getPropertiesNameType(restResponse); + + List propertyRowsFromTable = InputsPage.getInstancePropertiesList(resourceName); + assertTrue("Some properties are missing in table. Instance name is : " + resourceName, propertyRowsFromTable.size() == propertiesNameTypeJson.size()); + VfVerificator.verifyVfInputs(instanceName, propertiesNameTypeJson, propertyRowsFromTable); + + GeneralUIUtils.clickOnElementByText(resourceName); + } + } + + @Test + public void addAllInformationalArtifactPlaceholdersInDCAEAssetTest() throws Exception{ + createDCAEAsset(); + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + for(InformationalArtifactsPlaceholders informArtifact : InformationalArtifactsPlaceholders.values()){ + ArtifactUIUtils.fillPlaceHolderInformationalArtifact(informArtifact, filePath,"asc_heat 0 2.yaml", informArtifact.getValue()); + } + + assertTrue(InformationalArtifactPage.checkElementsCountInTable(InformationalArtifactsPlaceholders.values().length)); + } + + @Test + public void verifyToscaArtifactsExistDCAEAssetTest() throws Exception{ + ResourceReqDetails vfMetaData = createDCAEAsset(); + + final int numOfToscaArtifacts = 2; + ResourceGeneralPage.getLeftMenu().moveToToscaArtifactsScreen(); + assertTrue(ToscaArtifactsPage.checkElementsCountInTable(numOfToscaArtifacts)); + + for(int i = 0; i < numOfToscaArtifacts; i++){ + String typeFromScreen = ToscaArtifactsPage.getArtifactType(i); + assertTrue(typeFromScreen.equals(ArtifactTypeEnum.TOSCA_CSAR.getType()) || typeFromScreen.equals(ArtifactTypeEnum.TOSCA_TEMPLATE.getType())); + } + + ToscaArtifactsPage.clickSubmitForTestingButton(vfMetaData.getName()); + VfVerificator.verifyToscaArtifactsInfo(vfMetaData, getUser()); + } + + @Test + public void DCAEAssetCertificationTest() throws Exception{ + ResourceReqDetails vfMetaData = createDCAEAsset(); + + String vfName = vfMetaData.getName(); + + ResourceGeneralPage.clickCheckinButton(vfName); + GeneralUIUtils.findComponentAndClick(vfName); + ResourceGeneralPage.clickSubmitForTestingButton(vfName); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfName); + TesterOperationPage.certifyComponent(vfName); + + vfMetaData.setVersion("1.0"); + VfVerificator.verifyVFLifecycle(vfMetaData, getUser(), LifecycleStateEnum.CERTIFIED); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(vfName); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CERTIFIED); + } + + @Test + public void deleteDCAEAssetCheckedoutTest() throws Exception{ + ResourceReqDetails vfMetaData = createDCAEAsset(); + + GeneralPageElements.clickTrashButtonAndConfirm(); + + vfMetaData.setVersion("0.1"); + VfVerificator.verifyVfDeleted(vfMetaData, getUser()); + } + + @Test + public void revertDCAEAssetMetadataTest() throws Exception{ + ResourceReqDetails vfMetaData = createDCAEAsset(); + + ResourceReqDetails vfRevertDetails = new ResourceReqDetails(); + vfRevertDetails.setName("ciUpdatedName"); + vfRevertDetails.setDescription("kuku"); + vfRevertDetails.setCategories(vfMetaData.getCategories()); + vfRevertDetails.setVendorName("updatedVendor"); + vfRevertDetails.setVendorRelease("updatedRelease"); + ResourceUIUtils.fillResourceGeneralInformationPage(vfRevertDetails, getUser(), false); + + GeneralPageElements.clickRevertButton(); + + VfVerificator.verifyVFMetadataInUI(vfMetaData); + } + + @Test + public void addDeploymentArtifactInCompositionScreenDCAEAssetTest() throws Exception{ + createDCAEAsset(); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + ArtifactInfo artifact = new ArtifactInfo(filePath, "Heat-File.yaml", "kuku", "artifact3","OTHER"); + CompositionPage.showDeploymentArtifactTab(); + CompositionPage.clickAddArtifactButton(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(artifact, CompositionPage.artifactPopup()); + + List actualArtifactList = GeneralUIUtils.getWebElementsListBy(By.className("i-sdc-designer-sidebar-section-content-item-artifact")); + Assert.assertEquals(1, actualArtifactList.size()); + } + + // future removed from ui + @Test(enabled = false) + public void addPropertyInCompositionScreenDCAEAssetTest() throws Exception{ + createDCAEAsset(); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + CompositionPage.showPropertiesAndAttributesTab(); + List propertyList = Arrays.asList(PropertyTypeEnum.STRING, PropertyTypeEnum.INTEGER); + int propertiesCount = CompositionPage.getProperties().size(); + for (PropertyTypeEnum prop : propertyList){ + PropertiesUIUtils.addNewProperty(prop); + } + assertTrue(GeneralUIUtils.checkElementsCountInTable(propertiesCount + propertyList.size(), () -> CompositionPage.getProperties())); + } + + @Test + public void addDeploymentArtifactAndVerifyInCompositionScreenDCAEAssetTest() throws Exception{ + createDCAEAsset(); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + ArtifactInfo deploymentArtifact = new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER"); + DeploymentArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(deploymentArtifact); + assertTrue(DeploymentArtifactPage.checkElementsCountInTable(1)); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + CompositionPage.showDeploymentArtifactTab(); + List deploymentArtifactsFromScreen = CompositionPage.getDeploymentArtifacts(); + assertTrue(1 == deploymentArtifactsFromScreen.size()); + + String actualArtifactFileName = deploymentArtifactsFromScreen.get(0).getText(); + assertTrue("asc_heat-0-2.yaml".equals(actualArtifactFileName)); + } + + @Test + public void checkoutDCAEAssetTest() throws Exception{ + ResourceReqDetails vfMetaData = createDCAEAsset(); + + ResourceGeneralPage.clickCheckinButton(vfMetaData.getName()); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + GeneralPageElements.clickCheckoutButton(); + + vfMetaData.setVersion("0.2"); + VfVerificator.verifyVFLifecycle(vfMetaData, getUser(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKOUT); + + ResourceGeneralPage.clickSubmitForTestingButton(vfMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + TesterOperationPage.certifyComponent(vfMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + ResourceGeneralPage.clickCheckoutButton(); + + vfMetaData.setVersion("1.1"); + vfMetaData.setUniqueId(null); + VfVerificator.verifyVFLifecycle(vfMetaData, getUser(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKOUT); + } + + @Test + public void deleteInstanceFromDCAEAssetCanvas() throws Exception{ + ResourceReqDetails vfMetaData = createDCAEAsset(); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager vfCanvasManager = CanvasManager.getCanvasManager(); + CanvasElement computeElement = CompositionPage.addElementToCanvasScreen(LeftPanelCanvasItems.COMPUTE, vfCanvasManager); + + vfCanvasManager.clickOnCanvaElement(computeElement); + vfCanvasManager.deleteElementFromCanvas(computeElement); + + VfVerificator.verifyNumOfComponentInstances(vfMetaData, 2, getUser()); + } + + @Test + public void changeInstanceNameInDCAEAssetTest() throws Exception{ + createDCAEAsset(); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager vfCanvasManager = CanvasManager.getCanvasManager(); + CanvasElement computeElement = CompositionPage.addElementToCanvasScreen(LeftPanelCanvasItems.COMPUTE, vfCanvasManager); + + String updatedInstanceName = "updatedName"; + vfCanvasManager.updateElementNameInCanvas(computeElement, updatedInstanceName); + + String actualSelectedInstanceName = CompositionPage.getSelectedInstanceName(); + assertTrue(updatedInstanceName.equals(actualSelectedInstanceName)); + } + + @Test + public void submitDCAEAssetForTestingWithNonCertifiedAsset() throws Exception{ + String fileName = "importVFC_VFC17.yml"; + + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(atomicResourceMetaData.getName()); + + ResourceReqDetails vfMetaData = createDCAEAsset(); + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CompositionPage.addElementToCanvasScreen(atomicResourceMetaData.getName(), canvasManager); + + try{ + CompositionPage.clickSubmitForTestingButton(vfMetaData.getName()); + assert(false); + } + catch(Exception e){ + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.VALIDATED_RESOURCE_NOT_FOUND.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + finally{ + ResourceRestUtils.deleteResourceByNameAndVersion(atomicResourceMetaData.getName(), "0.1"); + } + } + + @Test + public void isDisabledAndReadOnlyInCheckinDCAEAssetTest() throws Exception{ + ResourceReqDetails vfMetaData = createDCAEAsset(); + ResourceGeneralPage.clickCheckinButton(vfMetaData.getName()); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + + ResourceMetadataEnum[] fieldsForCheck = {ResourceMetadataEnum.RESOURCE_NAME, + ResourceMetadataEnum.DESCRIPTION, + ResourceMetadataEnum.VENDOR_NAME, + ResourceMetadataEnum.VENDOR_RELEASE, + ResourceMetadataEnum.CONTACT_ID, + ResourceMetadataEnum.CATEGORY, + ResourceMetadataEnum.TAGS}; + + for (ResourceMetadataEnum field: fieldsForCheck){ + VfVerificator.verifyIsElementDisabled(field.getValue(), field.name()); + } + VfVerificator.verifyIsElementDisabled(DataTestIdEnum.LifeCyleChangeButtons.CREATE.getValue(), DataTestIdEnum.LifeCyleChangeButtons.CREATE.name()); + } + + @Test + public void removeFileFromGeneralPageDCAEAssetTest() throws Exception{ + String fileName2 = "service_input_test_VF2.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + ResourceUIUtils.importVfFromCsarNoCreate(resourceMetaData, filePath, fileName2, getUser()); + GeneralPageElements.clickDeleteFile(); + + try{ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.GeneralElementsEnum.CREATE_BUTTON.getValue(), 30); + assert(false); + } + catch(Exception e){ + assert(true); + } + } + + @Test + public void activityLogDCAEAssetTest() throws Exception{ + createDCAEAsset(); + + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + ArtifactInfo informationalArtifact = new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER"); + InformationalArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(informationalArtifact); + + ResourceGeneralPage.getLeftMenu().moveToActivityLogScreen(); + + int numberOfRows = GeneralUIUtils.getElementsByCSS("div[class^='flex-container']").size(); + assertTrue("Wrong rows number, should be 2", numberOfRows == 2); + } + + @Test + public void checkinCheckoutChangeDeleteVersionDCAEAssetTest() throws Exception{ + ResourceReqDetails atomicResourceMetaData = createDCAEAsset(); + + ResourceGeneralPage.clickCheckinButton(atomicResourceMetaData.getName()); + GeneralUIUtils.findComponentAndClick(atomicResourceMetaData.getName()); + GeneralPageElements.clickCheckoutButton(); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKOUT); + + GeneralPageElements.selectVersion("V0.1"); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKIN); + GeneralUIUtils.clickJSOnElementByText("latest version"); + + GeneralPageElements.clickTrashButtonAndConfirm(); + GeneralUIUtils.findComponentAndClick(atomicResourceMetaData.getName()); + String actualVersion = GeneralUIUtils.getSelectedElementFromDropDown(DataTestIdEnum.GeneralElementsEnum.VERSION_HEADER.getValue()).getText(); + assertTrue("Expected version: V0.1, Actual version: " + actualVersion, actualVersion.equals("V0.1")); + } + + @Test + public void badFileDCAEAssetTest() throws Exception { + String customFileName = "badVF.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + try{ + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, customFileName, getUser()); + assert(false); + } + catch(Exception e){ + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.CSAR_INVALID.name()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating error messdge...")); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + } + + @Test + public void validContactAfterCreateDCAEAssetTest() throws Exception{ + String fileName2 = "service_input_test_VF2.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName2, getUser()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating that userID equal to user that was logged in...")); + assertTrue("wrong userId", resourceMetaData.getContactId().equals(ResourceGeneralPage.getContactIdText())); + } + + public ResourceReqDetails createDCAEAsset() throws Exception{ + String fileName2 = "service_input_test_VF2.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName2, getUser()); + resourceMetaData.setVersion("0.1"); + return resourceMetaData; + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/ImportVFCAsset.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/ImportVFCAsset.java new file mode 100644 index 0000000000..92e9a2f6c1 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/ImportVFCAsset.java @@ -0,0 +1,353 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.InformationalArtifactsPlaceholders; +import org.openecomp.sdc.ci.tests.datatypes.LifeCycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openecomp.sdc.ci.tests.pages.InformationalArtifactPage; +import org.openecomp.sdc.ci.tests.pages.PropertiesPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.TesterOperationPage; +import org.openecomp.sdc.ci.tests.pages.UploadArtifactPopup; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.PropertiesUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.verificator.VFCverificator; +import org.openecomp.sdc.ci.tests.verificator.VfVerificator; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; + +public class ImportVFCAsset extends SetupCDTest { + + private ResourceReqDetails atomicResourceMetaData; + + private String filePath; + @BeforeClass + public void beforeClass(){ + filePath = System.getProperty("filepath"); + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath(); + } + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator + ""; + } + } + + @DataProvider(name = "assetFiles", parallel = false) + public Object[][] createDataX() { + return new Object[][] { { "importVFC_VFC9.yml" }, { "CP.yml" }, {"VL.yml"} }; + } + + @Test + public void importVFCTest() throws Exception { + String fileName = "importVFC_VFC1.yml"; + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + } + + @Test + public void importDuplicateVFCTest() throws Exception { + String fileName = "importVFC_VFC2.yml"; + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceGeneralPage.clickCheckinButton(atomicResourceMetaData.getName()); + + ResourceReqDetails atomicResourceMetaDataDup = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_INFRASTRUCTURE, getUser()); + try{ + ResourceUIUtils.importVfc(atomicResourceMetaDataDup, filePath, fileName, getUser()); + assert(false); + } + catch(Exception e){ + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.RESOURCE_ALREADY_EXISTS.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + } + + @Test + public void badFileVFCTest() throws Exception { + String fileName = "importVFC_VFC3.yml"; + String customFileName = "Heat-File 1.yaml"; + + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + try{ + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, customFileName, getUser()); + assert(false); + } + catch(Exception e){ + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.INVALID_TOSCA_TEMPLATE.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + } + + @Test + public void validContactAfterCreateVFCTest() throws Exception{ + String fileName = "importVFC_VFC4.yml"; + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + + assertTrue("wrong userId", atomicResourceMetaData.getContactId().equals(ResourceGeneralPage.getContactIdText())); + } + + @Test + public void validContactAfterUpdateVFCTest() throws Exception{ + String fileName = "importVFC_VFC5.yml"; + String userIdUpdated = "up1234"; + + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + + ResourceUIUtils.defineUserId(userIdUpdated); + assertTrue("userId is not updated",userIdUpdated.equals(ResourceGeneralPage.getContactIdText())); + } + + @Test + public void addUpdateDeleteDeploymentArtifactToVFCTest() throws Exception { + String fileName = "importVFC_VFC6.yml"; + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + List deploymentArtifactList = new ArrayList(); + deploymentArtifactList.add(new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER")); + deploymentArtifactList.add(new ArtifactInfo(filePath, "sample-xml-alldata-1-1.xml", "cuku", "artifact2", "YANG_XML")); + for (ArtifactInfo deploymentArtifact : deploymentArtifactList) { + DeploymentArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(deploymentArtifact, new UploadArtifactPopup(true) ); + } + assertTrue("artifact table does not contain artifacts uploaded", DeploymentArtifactPage.checkElementsCountInTable(deploymentArtifactList.size())); + + String newDescription = "new description"; + DeploymentArtifactPage.updateDescription(newDescription, deploymentArtifactList.get(0)); + String actualArtifactDescription = DeploymentArtifactPage.getArtifactDescription(deploymentArtifactList.get(0).getArtifactLabel()); + assertTrue("artifact description is not updated", newDescription.equals(actualArtifactDescription)); + + DeploymentArtifactPage.clickDeleteArtifact(deploymentArtifactList.get(0).getArtifactLabel()); + DeploymentArtifactPage.clickOK(); + assertTrue("artifact "+ deploymentArtifactList.get(0).getArtifactLabel() + "is not deleted", DeploymentArtifactPage.checkElementsCountInTable(deploymentArtifactList.size() - 1)); + + assertTrue("artifact "+ deploymentArtifactList.get(1).getArtifactLabel() + "is not displayed", DeploymentArtifactPage.clickOnArtifactDescription(deploymentArtifactList.get(1).getArtifactLabel()).isDisplayed()); + } + + @Test + public void addUpdateDeletePlaceholdersInformationalArtefactVFCTest() throws Exception{ + String fileName = "importVFC_VFC7.yml"; + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + // create artifacts + List informationalArtifactList = new ArrayList(); + informationalArtifactList.add(new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER")); + informationalArtifactList.add(new ArtifactInfo(filePath, "sample-xml-alldata-1-1.xml", "cuuuuku", "artifact3", "HEAT")); + for (ArtifactInfo informationalArtifact : informationalArtifactList) { + InformationalArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(informationalArtifact); + } + assertTrue("artifact table does not contain artifacts uploaded", InformationalArtifactPage.checkElementsCountInTable(informationalArtifactList.size())); + + // update artifact description + String newDescription = "new description"; + InformationalArtifactPage.clickEditArtifact(informationalArtifactList.get(0).getArtifactLabel()); + InformationalArtifactPage.artifactPopup().insertDescription(newDescription); + InformationalArtifactPage.artifactPopup().clickDoneButton(); + String actualArtifactDescription = InformationalArtifactPage.getArtifactDescription(informationalArtifactList.get(0).getArtifactLabel()); + assertTrue("artifact description is not updated", newDescription.equals(actualArtifactDescription)); + + // delete artifacts + for (ArtifactInfo informationalArtifact : informationalArtifactList) { + InformationalArtifactPage.clickDeleteArtifact(informationalArtifact.getArtifactLabel()); + InformationalArtifactPage.clickOK(); + } + + assertTrue("not all artifacts is deleted", InformationalArtifactPage.checkElementsCountInTable(0)); + + // fill placeholders + for(InformationalArtifactsPlaceholders informArtifact : InformationalArtifactsPlaceholders.values()){ + ArtifactUIUtils.fillPlaceHolderInformationalArtifact(informArtifact, filePath,"asc_heat 0 2.yaml", informArtifact.getValue()); + } + InformationalArtifactPage.checkElementsCountInTable(InformationalArtifactsPlaceholders.values().length); + } + + @Test + public void addSimplePropertiesToVFCTest() throws Exception{ + String fileName = "importVFC_VFC8.yml"; + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToPropertiesScreen(); + List propertyList = Arrays.asList(PropertyTypeEnum.STRING, PropertyTypeEnum.INTEGER, PropertyTypeEnum.FLOAT); + int propertiesCount = PropertiesPage.getElemenetsFromTable().size(); + for (PropertyTypeEnum prop : propertyList){ + PropertiesUIUtils.addNewProperty(prop); + } + assertTrue(GeneralUIUtils.checkElementsCountInTable(propertiesCount + propertyList.size(), () -> PropertiesPage.getElemenetsFromTable())); + + } + + + @Test(dataProvider = "assetFiles") + public void checkinCheckoutChangeDeleteVersionVFCTest(String customfileName) throws Exception{ + setLog(customfileName); +// getExtendTest().setDescription(customfileName); + + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, customfileName, getUser()); + + ResourceGeneralPage.clickCheckinButton(atomicResourceMetaData.getName()); + GeneralUIUtils.findComponentAndClick(atomicResourceMetaData.getName()); + GeneralPageElements.clickCheckoutButton(); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKOUT); + + GeneralPageElements.selectVersion("V0.1"); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKIN); + GeneralUIUtils.clickJSOnElementByText("latest version"); + + GeneralPageElements.clickTrashButtonAndConfirm(); + GeneralUIUtils.findComponentAndClick(atomicResourceMetaData.getName()); + String actualVersion = GeneralUIUtils.getSelectedElementFromDropDown(DataTestIdEnum.GeneralElementsEnum.VERSION_HEADER.getValue()).getText(); + assertTrue("Expected version: V0.1, Actual version: " + actualVersion, actualVersion.equals("V0.1")); + } + + @Test + public void certificationVFCTest() throws Exception{ + String fileName = "importVFC_VFC10.yml"; + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + + String vfName = atomicResourceMetaData.getName(); + + ResourceGeneralPage.clickCheckinButton(vfName); + GeneralUIUtils.findComponentAndClick(vfName); + ResourceGeneralPage.clickSubmitForTestingButton(vfName); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfName); + TesterOperationPage.certifyComponent(vfName); + + atomicResourceMetaData.setVersion("1.0"); + VfVerificator.verifyVFLifecycle(atomicResourceMetaData, getUser(), LifecycleStateEnum.CERTIFIED); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(vfName); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CERTIFIED); + } + + @Test + public void activityLogVFCTest() throws Exception{ + String fileName = "importVFC_VFC11.yml"; + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + ArtifactInfo informationalArtifact = new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER"); + InformationalArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(informationalArtifact); + + ResourceGeneralPage.getLeftMenu().moveToActivityLogScreen(); + + int numberOfRows = GeneralUIUtils.getElementsByCSS("div[class^='flex-container']").size(); + assertTrue("Wrong rows number, should be 2", numberOfRows == 2); + } + + @Test + public void removeFileFromGeneralPageVFCTest() throws Exception{ + String fileName = "importVFC_VFC12.yml"; + + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfcNoCreate(atomicResourceMetaData, filePath, fileName, getUser()); + + GeneralPageElements.clickDeleteFile(); + + try{ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.GeneralElementsEnum.CREATE_BUTTON.getValue(), 30); + assert(false); + } + catch(Exception e){ + assert(true); + } + } + + @Test + public void maxLengthGeneralInformationVFCTest() throws Exception{ + String fileName = "importVFC_VFC13.yml"; + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, + ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceUIUtils.fillMaxValueResourceGeneralInformationPage(atomicResourceMetaData); + GeneralPageElements.clickUpdateButton(); + VFCverificator.verifyVFCUpdatedInUI(atomicResourceMetaData); + GeneralPageElements.clickDeleteVersionButton(); + } + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Onboard.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Onboard.java new file mode 100644 index 0000000000..39311731c7 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Onboard.java @@ -0,0 +1,355 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.awt.AWTException; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.ArtifactsCorrelationManager; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.GovernorOperationPage; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openecomp.sdc.ci.tests.pages.OpsOperationPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.ServiceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.TesterOperationPage; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.verificator.ServiceVerificator; +import org.openqa.selenium.WebElement; +import org.testng.AssertJUnit; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.clearspring.analytics.util.Pair; +import com.aventstack.extentreports.Status; +import com.aventstack.extentreports.ExtentTest; + +public class Onboard extends SetupCDTest { + + public static Object[][] provideData(Object[] fileNamesFromFolder, String filepath) { + Object[][] arObject = new Object[fileNamesFromFolder.length][]; + + int index = 0; + for (Object obj : fileNamesFromFolder) { + arObject[index++] = new Object[] { filepath, obj }; + } + return arObject; + } + + @DataProvider(name = "VNF_List" , parallel = true) + private static final Object[][] VnfList() throws Exception { + String filepath = getFilePath(); + + Object[] fileNamesFromFolder = FileHandling.getZipFileNamesFromFolder(filepath); + System.out.println(String.format("There are %s zip file(s) to test", fileNamesFromFolder.length)); + return provideData(fileNamesFromFolder, filepath); + } + + public static String getFilePath() { + String filepath = System.getProperty("filepath"); + if (filepath == null && System.getProperty("os.name").contains("Windows")) { + filepath = FileHandling.getResourcesFilesPath() +"VNFs"; + } + + else if(filepath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filepath = FileHandling.getBasePath() + File.separator + "Files" + File.separator +"VNFs"; + } + return filepath; + } + + @Test + public void onboardVNFTestSanity() throws Exception, Throwable { +// String filepath = getFilePath(); +// String vnfFile = "2016-043_vsaegw_fdnt_30_1607_e2e.zip"; + String filepath = getFilePath(); + Object[] fileNamesFromFolder = FileHandling.getZipFileNamesFromFolder(filepath); + String vnfFile = fileNamesFromFolder[0].toString(); + runOnboardToDistributionFlow(filepath, vnfFile); + } + + public void runOnboardToDistributionFlow(String filepath, String vnfFile) throws Exception, AWTException { + Pair> onboardAndValidate = OnboardingUtils.onboardAndValidate(filepath, vnfFile, getUser()); + String vspName = onboardAndValidate.left; + + DeploymentArtifactPage.getLeftPanel().moveToCompositionScreen(); + ExtentTestActions.addScreenshot(Status.INFO, "TopologyTemplate_" + vnfFile ,"The topology template for " + vnfFile + " is as follows : "); + + DeploymentArtifactPage.clickSubmitForTestingButton(vspName); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vspName); + TesterOperationPage.certifyComponent(vspName); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + // create service + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ServiceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CompositionPage.searchForElement(vspName); + CanvasManager serviceCanvasManager = CanvasManager.getCanvasManager(); + CanvasElement vfElement = serviceCanvasManager.createElementOnCanvas(vspName); + ArtifactsCorrelationManager.addVNFtoServiceArtifactCorrelation(serviceMetadata.getName(), vspName); + + assertNotNull(vfElement); + ServiceVerificator.verifyNumOfComponentInstances(serviceMetadata, "0.1", 1, getUser()); + ExtentTestActions.addScreenshot(Status.INFO, "ServiceComposition_" + vnfFile ,"The service topology is as follows : "); + + ServiceGeneralPage.clickSubmitForTestingButton(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + TesterOperationPage.certifyComponent(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.GOVERNOR); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + GovernorOperationPage.approveSerivce(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.OPS); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + OpsOperationPage.distributeService(); + OpsOperationPage.displayMonitor(); + + List rowsFromMonitorTable = OpsOperationPage.getRowsFromMonitorTable(); + AssertJUnit.assertEquals(1, rowsFromMonitorTable.size()); + + OpsOperationPage.waitUntilArtifactsDistributed(0); + +// validateInputArtsVSouput(serviceMetadata.getName()); + + getExtendTest().log(Status.INFO, String.format("The onboarding %s test is passed ! ", vnfFile)); + } + +// protected synchronized void validateInputArtsVSouput(String serviceName) { +// +// +// String filepath = System.getProperty("filepath"); +// if (filepath == null && System.getProperty("os.name").contains("Windows")) { +// filepath = FileHandling.getResourcesFilesPath() + folder + File.separator; +// } +// +// Set>>> serviceArtifactCorrelationMap = ArtifactsCorrelationManager.getServiceArtifactCorrelationMap(serviceName); +// +// } + + @Test(dataProvider = "VNF_List") + public void onboardVNFTest(String filepath, String vnfFile) throws Exception, Throwable { + setLog(vnfFile); + runOnboardToDistributionFlow(filepath, vnfFile); + } + + + @Test + public void onboardUpdateVNFTest() throws Exception, Throwable { + String filepath = getFilePath(); + Object[] fileNamesFromFolder = FileHandling.getZipFileNamesFromFolder(filepath); + String vnfFile = fileNamesFromFolder[0].toString(); + + Pair> vsp = OnboardingUtils.onboardAndValidate(filepath, vnfFile, getUser()); + String vspName = vsp.left; + ResourceGeneralPage.clickSubmitForTestingButton(vspName); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vspName); + TesterOperationPage.certifyComponent(vspName); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + // create service + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ServiceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CompositionPage.searchForElement(vspName); + CanvasManager serviceCanvasManager = CanvasManager.getCanvasManager(); + CanvasElement vfElement = serviceCanvasManager.createElementOnCanvas(vspName); + assertNotNull(vfElement); + ServiceVerificator.verifyNumOfComponentInstances(serviceMetadata, "0.1", 1, getUser()); + + HomePage.navigateToHomePage(); + + ///update flow + String updatedVnfFile = fileNamesFromFolder[1].toString(); + + getExtendTest().log(Status.INFO, String.format("Going to update the VNF with %s......", updatedVnfFile)); + // update VendorSoftwareProduct + OnboardingUtils.updateVnfAndValidate(filepath, vsp, updatedVnfFile, getUser()); + + ResourceGeneralPage.clickSubmitForTestingButton(vspName); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vspName); + TesterOperationPage.certifyComponent(vspName); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + + // replace exiting VFI in service with new updated + + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + ServiceGeneralPage.getLeftMenu().moveToCompositionScreen(); + serviceCanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.changeComponentVersion(serviceCanvasManager, vfElement, "2.0"); + ServiceVerificator.verifyNumOfComponentInstances(serviceMetadata, "0.1", 1, getUser()); + + ServiceGeneralPage.clickSubmitForTestingButton(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + TesterOperationPage.certifyComponent(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.GOVERNOR); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + GovernorOperationPage.approveSerivce(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.OPS); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + OpsOperationPage.distributeService(); + OpsOperationPage.displayMonitor(); + + List rowsFromMonitorTable = OpsOperationPage.getRowsFromMonitorTable(); + AssertJUnit.assertEquals(1, rowsFromMonitorTable.size()); + + OpsOperationPage.waitUntilArtifactsDistributed(0); + + getExtendTest().log(Status.INFO, String.format("onboarding %s test is passed ! ", vnfFile)); + + + } + + @Test + public void threeVMMSCsInServiceTest() throws Exception{ + String filepath = getFilePath(); + + + List vmmscList = new ArrayList(); + vmmscList = Arrays.asList(new File(filepath).list()).stream().filter(e -> e.contains("vmmsc") && e.endsWith(".zip")).collect(Collectors.toList()); + assertTrue("Did not find vMMSCs", vmmscList.size() > 0); + + Map vspNames = new HashMap(); + for (String vnfFile : vmmscList){ + getExtendTest().log(Status.INFO, String.format("going to onboard the VNF %s......", vnfFile)); + System.out.println(String.format("going to onboard the VNF %s......", vnfFile)); + + OnboardingUtils.createVendorLicense(getUser()); + Pair> createVendorSoftwareProduct = OnboardingUtils.createVendorSoftwareProduct(vnfFile, filepath, getUser()); + + getExtendTest().log(Status.INFO, String.format("searching for onboarded %s", vnfFile)); + HomePage.showVspRepository(); + getExtendTest().log(Status.INFO,String.format("going to import %s......", vnfFile.substring(0, vnfFile.indexOf(".")))); + OnboardingUtils.importVSP(createVendorSoftwareProduct); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + DeploymentArtifactPage.verifyArtifactsExistInTable(filepath, vnfFile); + + String vspName = createVendorSoftwareProduct.left; + DeploymentArtifactPage.clickSubmitForTestingButton(vspName); + + vspNames.put(vnfFile, vspName); + } + + reloginWithNewRole(UserRoleEnum.TESTER); + for (String vsp : vspNames.values()){ + GeneralUIUtils.findComponentAndClick(vsp); + TesterOperationPage.certifyComponent(vsp); + } + + reloginWithNewRole(UserRoleEnum.DESIGNER); + // create service + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + ServiceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager serviceCanvasManager = CanvasManager.getCanvasManager(); + + for (String vsp : vspNames.values()){ + CompositionPage.searchForElement(vsp); + CanvasElement vfElement = serviceCanvasManager.createElementOnCanvas(vsp); + assertNotNull(vfElement); + } + ServiceVerificator.verifyNumOfComponentInstances(serviceMetadata, "0.1", vspNames.values().size(), getUser()); + File imageFilePath = GeneralUIUtils.takeScreenshot(null, SetupCDTest.getScreenshotFolder(), "Info_" + getExtendTest().getModel().getName()); + final String absolutePath = new File(SetupCDTest.getReportFolder()).toURI().relativize(imageFilePath.toURI()).getPath(); + SetupCDTest.getExtendTest().log(Status.INFO, "Three kinds of vMMSC are in canvas now." + getExtendTest().addScreenCaptureFromPath(absolutePath)); + + ServiceGeneralPage.clickSubmitForTestingButton(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + TesterOperationPage.certifyComponent(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.GOVERNOR); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + GovernorOperationPage.approveSerivce(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.OPS); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + OpsOperationPage.distributeService(); + OpsOperationPage.displayMonitor(); + + List rowsFromMonitorTable = OpsOperationPage.getRowsFromMonitorTable(); + AssertJUnit.assertEquals(1, rowsFromMonitorTable.size()); + + OpsOperationPage.waitUntilArtifactsDistributed(0); + + } + + + + + + + + + + + + + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/OnboardViaApis.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/OnboardViaApis.java new file mode 100644 index 0000000000..cb647aec6d --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/OnboardViaApis.java @@ -0,0 +1,303 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import static org.testng.AssertJUnit.assertEquals; + +import java.awt.AWTException; +import java.io.File; +import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.bouncycastle.util.encoders.Base64; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.LifeCycleStatesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.clearspring.analytics.util.Pair; +import com.google.gson.Gson; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import fj.data.Either; + +public class OnboardViaApis{ + + + private static final String FULL_PATH = "C://tmp//CSARs//"; + + public static Object[][] provideData(Object[] fileNamesFromFolder, String filepath) { + Object[][] arObject = new Object[fileNamesFromFolder.length][]; + + int index = 0; + for (Object obj : fileNamesFromFolder) { + arObject[index++] = new Object[] { filepath, obj }; + } + return arObject; + } + + @DataProvider(name = "VNF_List" , parallel = false) + private static final Object[][] VnfList() throws Exception { + String filepath = FileHandling.getVnfRepositoryPath(); + + Object[] fileNamesFromFolder = FileHandling.getZipFileNamesFromFolder(filepath); + System.out.println(String.format("There are %s zip file(s) to test", fileNamesFromFolder.length)); + return provideData(fileNamesFromFolder, filepath); + } + + +//------------------------------------------------------------------------------------------------------- + User sdncDesignerDetails1 = ElementFactory.getDefaultUser(UserRoleEnum.DESIGNER); + private static String vendorId; + private static String vendorLicenseName; + private static String vendorLicenseAgreementId; + private static String featureGroupId; + ResourceReqDetails resourceDetails; + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + + + @BeforeMethod + public void before(){ + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + lc.getLogger("org.apache").setLevel(Level.OFF); + lc.getLogger("org.*").setLevel(Level.OFF); + lc.getLogger("org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest").setLevel(Level.OFF); + resourceDetails = ElementFactory.getDefaultResource(); + + } + + @Test(dataProvider = "VNF_List") + public void onboardVNFTestViaApis(String filepath, String vnfFile) throws Exception, Throwable { + Service service = null; + String fullFileName = FULL_PATH + vnfFile + ".csar"; + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + System.err.println(timestamp + " Starting test with VNF: " + vnfFile); + service = runOnboardViaApisOnly(filepath, vnfFile); + timestamp = new Timestamp(System.currentTimeMillis()); + System.err.println(timestamp + " Finished test with VNF: " + vnfFile); + timestamp = new Timestamp(System.currentTimeMillis()); + System.err.println(timestamp + " Starting download service csar file: " + vnfFile); + File file = new File(fullFileName); + downloadToscaCsarToDirectory(service, file); + timestamp = new Timestamp(System.currentTimeMillis()); + System.err.println(timestamp + " Finished download service csar file: " + vnfFile); + System.out.println("end"); + + } + + public static void downloadToscaCsarToDirectory(Service service, File file) { + try { + Either serviceToscaArtifactPayload = AtomicOperationUtils.getServiceToscaArtifactPayload(service, "assettoscacsar"); + if(serviceToscaArtifactPayload.left().value() != null){ + Gson gson = new Gson(); + @SuppressWarnings("unchecked") + Map fromJson = gson.fromJson(serviceToscaArtifactPayload.left().value(), Map.class); + String string = fromJson.get("base64Contents").toString(); + byte[] byteArray = Base64.decode(string.getBytes(StandardCharsets.UTF_8)); + File downloadedFile = new File(file.getAbsolutePath()); + FileOutputStream fos = new FileOutputStream(downloadedFile); + fos.write(byteArray); + fos.flush(); + fos.close(); + } + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + public Service runOnboardViaApisOnly(String filepath, String vnfFile) throws Exception, AWTException { + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + System.err.println(timestamp + " Starting onboard VNF: " + vnfFile); + Pair> onboardAndValidate = onboardAndValidateViaApi(filepath, vnfFile, sdncDesignerDetails1); + String vspName = onboardAndValidate.left; + timestamp = new Timestamp(System.currentTimeMillis()); + System.err.println(timestamp + " Finished onboard VNF: " + vnfFile); + Resource resource = AtomicOperationUtils.getResourceObject(resourceDetails.getUniqueId()); + + AtomicOperationUtils.changeComponentState(resource, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true); + resource = AtomicOperationUtils.getResourceObject(resource.getUniqueId()); + // create service + + Service service = AtomicOperationUtils.createDefaultService(UserRoleEnum.DESIGNER, true).left().value(); + Either addComponentInstanceToComponentContainer = AtomicOperationUtils.addComponentInstanceToComponentContainer(resource, service, UserRoleEnum.DESIGNER, true); + service = (Service) AtomicOperationUtils.changeComponentState(service, UserRoleEnum.DESIGNER, LifeCycleStatesEnum.CERTIFY, true).getLeft(); + return service; + } + + + + public Pair> onboardAndValidateViaApi(String filepath, String vnfFile, User user) throws Exception { + + createVendorLicense(user); + Pair> createVendorSoftwareProduct = createVendorSoftwareProduct(vnfFile, filepath, user); + String vspName = createVendorSoftwareProduct.left; + List tags = new ArrayList<>(); + tags.add(vspName); + Map map = createVendorSoftwareProduct.right; + + resourceDetails.setCsarUUID(map.get("vspId")); + resourceDetails.setCsarVersion("1.0"); + resourceDetails.setName(vspName); + resourceDetails.setTags(tags); + resourceDetails.setResourceType(map.get("componentType")); + resourceDetails.setVendorName(map.get("vendorName")); + resourceDetails.setVendorRelease("1.0"); + resourceDetails.setResourceType("VF"); + RestResponse createResource = ResourceRestUtils.createResource(resourceDetails, sdncDesignerDetails1); + + return createVendorSoftwareProduct; + } + + public static Pair> createVendorSoftwareProduct(String HeatFileName, String filepath, User user) + throws Exception { + Pair> pair = createVSP(HeatFileName, filepath, user); + + String vspid = pair.right.get("vspId"); + + prepareVspForUse(user, vspid); + + return pair; + } + + public static void prepareVspForUse(User user, String vspid) throws Exception { + RestResponse checkin = OnboardingUtils.checkinVendorSoftwareProduct(vspid, user); + assertEquals("did not succeed to checking new VSP", 200, checkin.getErrorCode().intValue()); + + RestResponse submit = OnboardingUtils.submitVendorSoftwareProduct(vspid, user); + assertEquals("did not succeed to submit new VSP", 200, submit.getErrorCode().intValue()); + + RestResponse createPackage = OnboardingUtils.createPackageOfVendorSoftwareProduct(vspid, user); + assertEquals("did not succeed to create package of new VSP ", 200, createPackage.getErrorCode().intValue()); + + } + public static void createVendorLicense(User user) throws Exception { + vendorLicenseName = "ciLicense" + UUID.randomUUID().toString().split("-")[0]; + RestResponse vendorLicenseResponse = OnboardingUtils.createVendorLicenseModels_1(vendorLicenseName, user); + assertEquals("did not succeed to create vendor license model", 200, + vendorLicenseResponse.getErrorCode().intValue()); + vendorId = ResponseParser.getValueFromJsonResponse(vendorLicenseResponse.getResponse(), "value"); + + RestResponse vendorKeyGroupsResponse = OnboardingUtils.createVendorKeyGroups_2(vendorId, user); + assertEquals("did not succeed to create vendor key groups", 200, + vendorKeyGroupsResponse.getErrorCode().intValue()); + String keyGroupId = ResponseParser.getValueFromJsonResponse(vendorKeyGroupsResponse.getResponse(), "value"); + + RestResponse vendorEntitlementPool = OnboardingUtils.createVendorEntitlementPool_3(vendorId, user); + assertEquals("did not succeed to create vendor entitlement pool", 200, + vendorEntitlementPool.getErrorCode().intValue()); + String entitlementPoolId = ResponseParser.getValueFromJsonResponse(vendorEntitlementPool.getResponse(), + "value"); + + RestResponse vendorLicenseFeatureGroups = OnboardingUtils.createVendorLicenseFeatureGroups_4(vendorId, keyGroupId, + entitlementPoolId, user); + assertEquals("did not succeed to create vendor license feature groups", 200, + vendorLicenseFeatureGroups.getErrorCode().intValue()); + featureGroupId = ResponseParser.getValueFromJsonResponse(vendorLicenseFeatureGroups.getResponse(), "value"); + + RestResponse vendorLicenseAgreement = OnboardingUtils.createVendorLicenseAgreement_5(vendorId, featureGroupId, user); + assertEquals("did not succeed to create vendor license agreement", 200, + vendorLicenseAgreement.getErrorCode().intValue()); + vendorLicenseAgreementId = ResponseParser.getValueFromJsonResponse(vendorLicenseAgreement.getResponse(), + "value"); + + RestResponse checkinVendorLicense = OnboardingUtils.checkinVendorLicense(vendorId, user); + assertEquals("did not succeed to checkin vendor license", 200, checkinVendorLicense.getErrorCode().intValue()); + + RestResponse submitVendorLicense = OnboardingUtils.submitVendorLicense(vendorId, user); + assertEquals("did not succeed to submit vendor license", 200, submitVendorLicense.getErrorCode().intValue()); + + } + + + public static Pair> createVSP(String HeatFileName, String filepath, User user) throws Exception { + String vspName = OnboardingUtils.handleFilename(HeatFileName); + + Pair> createNewVspPair = OnboardingUtils.createNewVendorSoftwareProduct(vspName, vendorLicenseName, vendorId, vendorLicenseAgreementId, featureGroupId, user); + RestResponse createNewVendorSoftwareProduct = createNewVspPair.left; + assertEquals("did not succeed to create new VSP", 200,createNewVendorSoftwareProduct.getErrorCode().intValue()); + String vspid = ResponseParser.getValueFromJsonResponse(createNewVendorSoftwareProduct.getResponse(), "vspId"); + String componentId = ResponseParser.getValueFromJsonResponse(createNewVendorSoftwareProduct.getResponse(), "componentId"); + + Map vspMeta = createNewVspPair.right; + Map vspObject = new HashMap(); + Iterator iterator = vspMeta.keySet().iterator(); + while(iterator.hasNext()){ + Object key = iterator.next(); + Object value = vspMeta.get(key); + vspObject.put(key.toString(), value.toString()); + } + vspObject.put("vspId", vspid); + vspObject.put("componentId", componentId); + vspObject.put("vendorName", vendorLicenseName); + vspObject.put("attContact", user.getUserId()); + + RestResponse uploadHeatPackage = OnboardingUtils.uploadHeatPackage(filepath, HeatFileName, vspid, user); + assertEquals("did not succeed to upload HEAT package", 200, uploadHeatPackage.getErrorCode().intValue()); + + RestResponse validateUpload = OnboardingUtils.validateUpload(vspid, user); + assertEquals("did not succeed to validate upload process", 200, validateUpload.getErrorCode().intValue()); + + Pair> pair = new Pair>(vspName, vspObject); + + return pair; + } + + + + + + + + + +// ---------------------------------------------------------------------------------------------------------------------------------------- + + + + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Product.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Product.java new file mode 100644 index 0000000000..e0e13b7036 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Product.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import java.io.File; + +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openecomp.sdc.ci.tests.pages.ProductGeneralPage; +import org.openecomp.sdc.ci.tests.pages.TesterOperationPage; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ProductUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * @author al714h + * + */ + +public class Product extends SetupCDTest { + + private String filePath; + @BeforeMethod + public void beforeTest(){ + filePath = System.getProperty("filepath"); + + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath(); + } + + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator; + } + } + + + @Test + public void createProductAndAddCertifiedServiceInstance() throws Exception { + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ProductReqDetails productReqDetails = ElementFactory.getDefaultProduct(); + + ServiceUIUtils.createService(serviceMetadata, getUser()); + GeneralPageElements.clickSubmitForTestingButton(serviceMetadata.getName()); + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + TesterOperationPage.certifyComponent(serviceMetadata.getName()); + reloginWithNewRole(UserRoleEnum.PRODUCT_MANAGER1); + ProductUIUtils.createProduct(productReqDetails, getUser()); + ProductGeneralPage.getProductLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CanvasElement canvasElement = CompositionPage.addElementToCanvasScreen(serviceMetadata.getName(), canvasManager); + canvasManager.clickOnCanvaElement(canvasElement); + } + + @Test + public void loginAsProductStrateger() throws Exception { + reloginWithNewRole(UserRoleEnum.PRODUCT_STRATEGIST1); + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Service.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Service.java new file mode 100644 index 0000000000..86e52a296d --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Service.java @@ -0,0 +1,698 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import static org.testng.AssertJUnit.assertTrue; + +import java.awt.AWTException; +import java.io.File; +import java.util.Arrays; +import java.util.List; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.TopMenuButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.CompositionScreenEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.ServiceMetadataEnum; +import org.openecomp.sdc.ci.tests.datatypes.LifeCycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentPage; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openecomp.sdc.ci.tests.pages.InputsPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.ServiceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.TesterOperationPage; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.CatalogUIUtilitis; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ServiceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.verificator.DeploymentViewVerificator; +import org.openecomp.sdc.ci.tests.verificator.ServiceVerificator; +import org.openecomp.sdc.ci.tests.verificator.VfVerificator; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.AssertJUnit; +import org.testng.SkipException; +import org.testng.TestException; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; + +public class Service extends SetupCDTest { + + private static final String DESCRIPTION = "kuku"; + private static final String ARTIFACT_LABEL = "artifact3"; + private static final String ARTIFACT_LABEL_UPDATE = "artifactUpdate"; + private static final String GET_ARTIFACT_LIST_BY_CLASS_NAME = "i-sdc-designer-sidebar-section-content-item-artifact"; + private static final String HEAT_FILE_YAML_NAME = "Heat-File.yaml"; + private static final String HEAT_FILE_YAML_UPDATE_NAME = "Heat-File-Update.yaml"; + private String filePath; + + @BeforeMethod + public void beforeTest(){ + filePath = FileHandling.getFilePath(""); + } + + + @Test + public void createService() throws Exception { + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + } + + @Test + public void validDefaultContactAndTagAfterCreateService() throws Exception{ + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createServiceWithDefaultTagAndUserId(serviceMetadata, getUser()); + + assertTrue("wrong userId", getUser().getUserId().equals(ResourceGeneralPage.getContactIdText())); + + List actualTags = Arrays.asList(ServiceGeneralPage.getTags()); + assertTrue("wrong tags", (actualTags.size() == 1) && actualTags.get(0).equals(serviceMetadata.getName())); + } + + @Test + public void updateService() throws Exception { + // Create Service + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + // Update Service + ServiceGeneralPage.deleteOldTags(serviceMetadata); + serviceMetadata.setName("ciUpdatedNameSanity"); + serviceMetadata.setDescription("updatedDescriptionSanity"); + serviceMetadata.setProjectCode("654321"); + serviceMetadata.setContactId("cs6543"); + serviceMetadata.getTags().addAll(Arrays.asList("updatedTag", "oneMoreUpdatedTag", "lastOne UpdatedTag")); + ServiceUIUtils.setServiceCategory(serviceMetadata, ServiceCategoriesEnum.VOIP); + ServiceUIUtils.fillServiceGeneralPage(serviceMetadata, getUser()); + GeneralPageElements.clickCreateButton(); + + ServiceVerificator.verifyServiceUpdatedInUI(serviceMetadata); + } + + @Test + public void deleteService() throws Exception { + + // create service + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + // Delete service + //GeneralUIUtils.HighlightMyElement(GeneralUIUtils.getWebButton("delete_version")); + GeneralPageElements.clickTrashButtonAndConfirm(); + + // Verification + CatalogUIUtilitis.clickTopMenuButton(TopMenuButtonsEnum.CATALOG); + CatalogUIUtilitis.catalogSearchBox(serviceMetadata.getName()); + ServiceVerificator.verifyServiceDeletedInUI(serviceMetadata); + } + + @Test + public void checkoutServiceTest() throws Exception{ + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + ArtifactInfo artifact = new ArtifactInfo(filePath, HEAT_FILE_YAML_NAME, DESCRIPTION, ARTIFACT_LABEL,"OTHER"); + CompositionPage.showDeploymentArtifactTab(); + CompositionPage.clickAddArtifactButton(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(artifact, CompositionPage.artifactPopup()); + + ResourceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + GeneralPageElements.clickCheckoutButton(); + + serviceMetadata.setVersion("0.2"); + ServiceVerificator.verifyServiceLifecycle(serviceMetadata, getUser(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKOUT); + ServiceVerificator.verifyVersionUI(serviceMetadata.getVersion()); + + ResourceGeneralPage.clickSubmitForTestingButton(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + TesterOperationPage.certifyComponent(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + ResourceGeneralPage.clickCheckoutButton(); + + serviceMetadata.setVersion("1.1"); + serviceMetadata.setUniqueId(null); + ServiceVerificator.verifyServiceLifecycle(serviceMetadata, getUser(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKOUT); + ServiceVerificator.verifyVersionUI(serviceMetadata.getVersion()); + } + + @Test + public void submitServiceForTestingWithNonCertifiedAsset() throws Exception{ + + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.createResource(atomicResourceMetaData, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(atomicResourceMetaData.getName()); + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(atomicResourceMetaData.getName()); + canvasManager.createElementOnCanvas(atomicResourceMetaData.getName()); + + try{ + CompositionPage.clickSubmitForTestingButton(serviceMetadata.getName()); + assert(false); + } + catch(Exception e){ + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.VALIDATED_RESOURCE_NOT_FOUND.name()); + assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + finally{ + ResourceRestUtils.deleteResourceByNameAndVersion(atomicResourceMetaData.getName(), "0.1"); + } + + } + + @Test + public void addDeploymentArtifactInCompositionScreenTest() throws Exception{ + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + ArtifactInfo artifact = new ArtifactInfo(filePath, HEAT_FILE_YAML_NAME, DESCRIPTION, ARTIFACT_LABEL,"OTHER"); + CompositionPage.showDeploymentArtifactTab(); + CompositionPage.clickAddArtifactButton(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(artifact, CompositionPage.artifactPopup()); + + List actualArtifactList = GeneralUIUtils.getWebElementsListBy(By.className(GET_ARTIFACT_LIST_BY_CLASS_NAME)); + AssertJUnit.assertEquals(1, actualArtifactList.size()); + + for(WebElement actualArtifactFileName : CompositionPage.getAllAddedArtifacts()){ + assertTrue(HEAT_FILE_YAML_NAME.equals(actualArtifactFileName.getText())); + } + + } + + @Test + public void addInformationArtifactInCompositionScreenTest() throws Exception{ + String fileName = HEAT_FILE_YAML_NAME; + String descriptionText = DESCRIPTION; + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + ArtifactInfo artifactInfo = new ArtifactInfo(filePath, fileName, descriptionText, ARTIFACT_LABEL,"OTHER"); + CompositionPage.showInformationArtifactTab(); + List beforeArtifactList = GeneralUIUtils.getWebElementsListBy(By.className(GET_ARTIFACT_LIST_BY_CLASS_NAME)); + CompositionPage.clickAddArtifactButton(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(artifactInfo, CompositionPage.artifactPopup()); + + List actualArtifactList = GeneralUIUtils.getWebElementsListBy(By.className(GET_ARTIFACT_LIST_BY_CLASS_NAME)); + assertTrue(String.format("Wrong number of artifacts, Expected: %s Actual: %s", beforeArtifactList.size() + 1, actualArtifactList.size()), + (beforeArtifactList.size() + 1) == actualArtifactList.size()); + for(DataTestIdEnum.InformationalArtifactsService artifact: DataTestIdEnum.InformationalArtifactsService.values()){ + ArtifactUIUtils.fillPlaceHolderInformationalArtifact(artifact, filePath, fileName, descriptionText); + } + int numberOfFiles = CompositionPage.getAllAddedArtifacts().size(); + assertTrue(String.format("Wrong number of artifacts, Expected: %s Actual: %s", (beforeArtifactList.size() + 1), numberOfFiles), (beforeArtifactList.size() + 1) == numberOfFiles); + + for(WebElement actualArtifactFileName : CompositionPage.getAllAddedArtifacts()){ + assertTrue(fileName.equals(actualArtifactFileName.getText())); + } + + } + + @Test + public void addAPIArtifactInCompositionScreenTest() throws Exception{ + + if(true){ + throw new SkipException("Open bug 292017"); + } + + String fileName = HEAT_FILE_YAML_NAME, + descriptionText = DESCRIPTION, + url = "http://kuku.com"; + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + ArtifactInfo artifactInfo = new ArtifactInfo(filePath, fileName, descriptionText, ARTIFACT_LABEL,"OTHER"); + CompositionPage.showAPIArtifactTab(); + + for(DataTestIdEnum.APIArtifactsService artifact: DataTestIdEnum.APIArtifactsService.values()){ + ArtifactUIUtils.fillPlaceHolderAPIArtifact(artifact, filePath, fileName, descriptionText, url); + } + int numberOfFiles = CompositionPage.getAllAddedArtifacts().size(), + numberOfPlacehoders = DataTestIdEnum.APIArtifactsService.values().length; + assertTrue(String.format("Wrong file count, should be %s files", numberOfPlacehoders), numberOfPlacehoders == numberOfFiles); + + for(WebElement actualArtifactFileName : CompositionPage.getAllAddedArtifacts()){ + assertTrue(fileName.equals(actualArtifactFileName.getText())); + } + } + + @Test + public void ManagmentWorkflowTest() throws Exception{ + + if(true){ + throw new SkipException("Open bug 287416"); + } + + String descriptionText = DESCRIPTION, + descriptionTextEdit = "kuku2"; + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ServiceGeneralPage.getServiceLeftMenu().moveToManagmentWorkflow(); + ServiceGeneralPage.fillAndAddNewWorkflow(descriptionText, descriptionText); + ServiceVerificator.verifyManagmentWorkflow(descriptionText, descriptionText); + + ServiceGeneralPage.clickAddWorkflow(); + ServiceGeneralPage.fillAndAddNewWorkflow(descriptionTextEdit, descriptionTextEdit); + } + + @Test + public void deleteChangeVersionTest() throws Exception{ + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + ArtifactInfo artifact = new ArtifactInfo(filePath, HEAT_FILE_YAML_NAME, DESCRIPTION, ARTIFACT_LABEL,"OTHER"); + CompositionPage.showDeploymentArtifactTab(); + CompositionPage.clickAddArtifactButton(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(artifact, CompositionPage.artifactPopup()); + + ResourceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + GeneralPageElements.clickCheckoutButton(); + + changeDeleteAndValidateVersionOnGeneralPage("0.1", "0.2", serviceMetadata.getName()); + + GeneralPageElements.clickCheckoutButton(); + ResourceGeneralPage.clickSubmitForTestingButton(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + TesterOperationPage.certifyComponent(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + ResourceGeneralPage.clickCheckoutButton(); + + changeDeleteAndValidateVersionOnGeneralPage("1.0", "1.1", serviceMetadata.getName()); + } + + @Test + public void compositionScreenRightSideButtonsTest() throws Exception{ + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + CompositionPage.showInformationTab(); + ServiceVerificator.verifyOpenTabTitle(CompositionScreenEnum.INFORMATION); + + //feature removed from UI +// CompositionPage.showCompositionTab(); +// ServiceVerificator.verifyOpenTabTitle(CompositionScreenEnum.COMPOSITION); + + CompositionPage.showDeploymentArtifactTab(); + ServiceVerificator.verifyOpenTabTitle(CompositionScreenEnum.DEPLOYMENT_ARTIFACT_TAB); + + CompositionPage.showInputsTab(); + assertTrue(CompositionPage.getOpenTabTitle().size() == 0); + + CompositionPage.showAPIArtifactTab(); + ServiceVerificator.verifyOpenTabTitle(CompositionScreenEnum.API); + + CompositionPage.showInformationArtifactTab(); + ServiceVerificator.verifyOpenTabTitle(CompositionScreenEnum.INFORMATION_ARTIFACTS); + + } + + @Test + public void addDeploymentArtifactToVFInstanceTest() throws Exception{ + + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ArtifactInfo artifact = new ArtifactInfo(filePath, HEAT_FILE_YAML_NAME, DESCRIPTION, ARTIFACT_LABEL,ArtifactTypeEnum.SNMP_POLL.getType()); + + CanvasElement computeElement = createServiceWithRiArtifact(atomicResourceMetaData, serviceMetadata, artifact); + checkArtifactIfAdded(1, HEAT_FILE_YAML_NAME); + checkInService(serviceMetadata); + clickOncanvasElement(computeElement); + CompositionPage.showDeploymentArtifactTab(); + checkArtifactIfAdded(1, HEAT_FILE_YAML_NAME); + } + + @Test + public void deleteDeploymentArtifactFromVFInstanceTest() throws Exception{ + + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ArtifactInfo artifact = new ArtifactInfo(filePath, HEAT_FILE_YAML_NAME, DESCRIPTION, ARTIFACT_LABEL,ArtifactTypeEnum.SNMP_POLL.getType()); + + CanvasElement computeElement = createServiceWithRiArtifact(atomicResourceMetaData, serviceMetadata, artifact); + checkArtifactIfAdded(1, HEAT_FILE_YAML_NAME); + clickOncanvasElement(computeElement); + CompositionPage.showDeploymentArtifactTab(); + List actualArtifactList = GeneralUIUtils.getWebElementsListBy(By.className(GET_ARTIFACT_LIST_BY_CLASS_NAME)); + deleteAndVerifyArtifact(actualArtifactList); + + } + + @Test + public void deleteDeploymentArtifactFromVFInstanceNextVersionTest() throws Exception{ + + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ArtifactInfo artifact = new ArtifactInfo(filePath, HEAT_FILE_YAML_NAME, DESCRIPTION, ARTIFACT_LABEL,ArtifactTypeEnum.SNMP_POLL.getType()); + + CanvasElement computeElement = createServiceWithRiArtifact(atomicResourceMetaData, serviceMetadata, artifact); + checkArtifactIfAdded(1, HEAT_FILE_YAML_NAME); + checkInService(serviceMetadata); + ResourceGeneralPage.clickCheckoutButton(); + clickOncanvasElement(computeElement); + CompositionPage.showDeploymentArtifactTab(); + List actualArtifactList = GeneralUIUtils.getWebElementsListBy(By.className(GET_ARTIFACT_LIST_BY_CLASS_NAME)); + deleteAndVerifyArtifact(actualArtifactList); +// change container version + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.GeneralElementsEnum.VERSION_HEADER.getValue()); + GeneralPageElements.selectVersion("V0.1"); + clickOncanvasElement(computeElement); + CompositionPage.showDeploymentArtifactTab(); + checkArtifactIfAdded(1, HEAT_FILE_YAML_NAME); + + } + +// service version V0.1 default artifact, service version V0.2 updated artifact + @Test + public void updateDeploymentArtifactOnVFInstanceNextVersionTest() throws Exception{ + + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ArtifactInfo artifact = new ArtifactInfo(filePath, HEAT_FILE_YAML_NAME, DESCRIPTION, ARTIFACT_LABEL,ArtifactTypeEnum.SNMP_POLL.getType()); + ArtifactInfo artifactUpdate = new ArtifactInfo(filePath, HEAT_FILE_YAML_UPDATE_NAME, DESCRIPTION, ARTIFACT_LABEL_UPDATE,ArtifactTypeEnum.DCAE_INVENTORY_DOC.getType()); + + CanvasElement computeElement = createServiceWithRiArtifact(atomicResourceMetaData, serviceMetadata, artifact); + checkArtifactIfAdded(1, HEAT_FILE_YAML_NAME); + checkInService(serviceMetadata); + ResourceGeneralPage.clickCheckoutButton(); + clickOncanvasElement(computeElement); + CompositionPage.showDeploymentArtifactTab(); + List actualArtifactList = GeneralUIUtils.getWebElementsListBy(By.className(GET_ARTIFACT_LIST_BY_CLASS_NAME)); + deleteAndVerifyArtifact(actualArtifactList); +// upload new artifact + addDeploymentArtifact(artifactUpdate, CanvasManager.getCanvasManager(), computeElement); + checkArtifactIfAdded(1, HEAT_FILE_YAML_UPDATE_NAME); +// change container version + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.GeneralElementsEnum.VERSION_HEADER.getValue()); + GeneralPageElements.selectVersion("V0.1"); + clickOncanvasElement(computeElement); + CompositionPage.showDeploymentArtifactTab(); + checkArtifactIfAdded(1, HEAT_FILE_YAML_NAME); + + } + + public void clickOncanvasElement(CanvasElement computeElement) { + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + canvasManager.clickOnCanvaElement(computeElement); + } + + public void checkInService(ServiceReqDetails serviceMetadata) throws Exception { + ResourceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + } + + public static void deleteAndVerifyArtifact(List actualArtifactList) { + if (actualArtifactList.size()>0){ + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_ITEM.getValue() + ARTIFACT_LABEL); + SetupCDTest.getExtendTest().log(Status.INFO, "Going to delete " + HEAT_FILE_YAML_NAME + " artifact" + " and check if deleted"); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DELETE.getValue() + ARTIFACT_LABEL); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + assertTrue("Artifact does not deleted", !GeneralUIUtils.waitForElementInVisibilityByTestId(By.className(GET_ARTIFACT_LIST_BY_CLASS_NAME))); + } + } + + + public void checkArtifactIfAdded(Integer expectedNumOfARtifacts, String expectedArtifactName) { + + List actualArtifactList; + actualArtifactList = GeneralUIUtils.getWebElementsListBy(By.className(GET_ARTIFACT_LIST_BY_CLASS_NAME)); + assertTrue("Expected artifact count is: " + expectedNumOfARtifacts + ", but was " + actualArtifactList.size(),expectedNumOfARtifacts==actualArtifactList.size()); + + if(expectedNumOfARtifacts != 0){ + for(WebElement actualArtifactFileName : CompositionPage.getAllAddedArtifacts()){ + assertTrue("Artifact name does not match, expected " + expectedArtifactName + ", but was " + actualArtifactFileName.getText(), expectedArtifactName.equals(actualArtifactFileName.getText())); + } + } + + } + + + public CanvasElement createServiceWithRiArtifact(ResourceReqDetails atomicResourceMetaData, ServiceReqDetails serviceMetadata, ArtifactInfo artifact) throws Exception, AWTException { + ResourceUIUtils.createResource(atomicResourceMetaData, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(atomicResourceMetaData.getName()); + + ServiceUIUtils.createService(serviceMetadata, getUser()); + + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(atomicResourceMetaData.getName()); + CanvasElement computeElement = canvasManager.createElementOnCanvas(atomicResourceMetaData.getName()); + addDeploymentArtifact(artifact, canvasManager, computeElement); + + return computeElement; + } + + + public void addDeploymentArtifact(ArtifactInfo artifact, CanvasManager canvasManager, CanvasElement computeElement) throws Exception { + canvasManager.clickOnCanvaElement(computeElement); + CompositionPage.showDeploymentArtifactTab(); + CompositionPage.clickAddArtifactButton(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(artifact, CompositionPage.artifactPopup()); + } + + @Test + public void isDisabledAndReadOnlyInCheckin() throws Exception{ + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + GeneralPageElements.clickCheckinButton(serviceMetadata.getName()); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + + ServiceMetadataEnum[] fieldsForCheck = {ServiceMetadataEnum.SERVICE_NAME, + ServiceMetadataEnum.CONTACT_ID, + ServiceMetadataEnum.DESCRIPTION, + ServiceMetadataEnum.PROJECT_CODE, + ServiceMetadataEnum.TAGS}; + for (ServiceMetadataEnum field: fieldsForCheck){ + assertTrue(GeneralUIUtils.isElementReadOnly(field.getValue())); + } + + assertTrue(GeneralUIUtils.isElementDisabled(ServiceMetadataEnum.CATEGORY.getValue())); + assertTrue(GeneralUIUtils.isElementDisabled(DataTestIdEnum.LifeCyleChangeButtons.CREATE.getValue())); + } + + // future removed from ui + @Test(enabled = false) + public void inputsTest() throws Exception{ + String fileName = "service_input_test_VF2.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName, getUser()); + GeneralPageElements.clickCheckinButton(resourceMetaData.getName()); + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + String selectedInstanceName = addResourceToServiceInCanvas(resourceMetaData); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + DeploymentArtifactPage.getLeftMenu().moveToInputsScreen(); + + InputsPage.addInputToService(selectedInstanceName, "volume_id"); + InputsPage.deleteServiceInput(selectedInstanceName, "volume_id"); + + // Trying to find deleted service input + try{ + InputsPage.getServiceInput(selectedInstanceName, "volume_id"); + assert(false); + } + catch(TestException e){ + } + } + + @Test + public void deploymentViewServiceTest() throws Exception{ + + if(true){ + throw new SkipException("Open bug 295220, 295180"); + } + + String fileName2 = "vSeGW.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName2, getUser()); + ResourceGeneralPage.clickCheckinButton(resourceMetaData.getName()); + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + addResourceToServiceInCanvas(resourceMetaData); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + DeploymentArtifactPage.getLeftMenu().moveToDeploymentViewScreen(); + + serviceMetadata.setVersion("0.1"); + List instanceRowsFromTable = GeneralUIUtils.getElementsByCSS("div[data-tests-id^='hierarchy-instance'] span[class^='expand-collapse-title-text']"); + for(WebElement instanceRow: instanceRowsFromTable){ + String instanceRowText = instanceRow.getText(); + List instanceModulesList = DeploymentPage.getInstanceModulesList(instanceRowText); + for (WebElement instanceModule: instanceModulesList){ + String instanceModuleText = instanceModule.getText(); + ResourceUIUtils.clickOnElementByText(instanceModuleText, "instance"); + + ServiceVerificator.verifyDeploymentPageSubElements(instanceModuleText.split("\\.\\.")[1], new DeploymentViewVerificator(filePath + fileName2)); + + ServiceVerificator.verifyDisabledServiceProperties(); + String isBaseValue = ServiceVerificator.getVFModulePropertieValue(serviceMetadata, "isBase", instanceModuleText); + if (isBaseValue.equals("false")) + ServiceVerificator.verifyEnabledServiceProperties(); + + ResourceUIUtils.clickOnElementByText(instanceModuleText, "instance"); + } + } + } + + @Test + public void vfModuleCustomizationUUIDServiceTest() throws Exception{ + String fileName2 = "vSeGW.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName2, getUser()); + ResourceGeneralPage.clickCheckinButton(resourceMetaData.getName()); + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + addResourceToServiceInCanvas(resourceMetaData); + + serviceMetadata.setVersion("0.1"); + ServiceVerificator.verifyVFModuleCustomizationUUID(serviceMetadata); + } + + @Test + public void checkoutCertifyRemainSameCustomizationUUIDServiceTest() throws Exception{ + String fileName2 = "vSeGW.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName2, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(resourceMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(resourceMetaData.getName()); + TesterOperationPage.certifyComponent(resourceMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + + ServiceReqDetails serviceMetadata = ElementFactory.getDefaultService(); + ServiceUIUtils.createService(serviceMetadata, getUser()); + + addResourceToServiceInCanvas(resourceMetaData); + + serviceMetadata.setVersion("0.1"); + ServiceVerificator.verifyVFModuleCustomizationUUID(serviceMetadata); + List allVFModuleCustomizationUUIDs = ServiceVerificator.getAllVFModuleCustomizationUUIDs(serviceMetadata); + + ResourceGeneralPage.clickCheckinButton(serviceMetadata.getName()); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + GeneralPageElements.clickCheckoutButton(); + + serviceMetadata.setVersion("0.2"); + assertTrue(ServiceVerificator.isEqualCustomizationUUIDsAfterChanges(allVFModuleCustomizationUUIDs, ServiceVerificator.getAllVFModuleCustomizationUUIDs(serviceMetadata))); + + ResourceGeneralPage.clickSubmitForTestingButton(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + TesterOperationPage.certifyComponent(serviceMetadata.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(serviceMetadata.getName()); + ResourceGeneralPage.clickCheckoutButton(); + + serviceMetadata.setVersion("1.1"); + serviceMetadata.setUniqueId(null); + assertTrue(ServiceVerificator.isEqualCustomizationUUIDsAfterChanges(allVFModuleCustomizationUUIDs, ServiceVerificator.getAllVFModuleCustomizationUUIDs(serviceMetadata))); + } + + + public synchronized String addResourceToServiceInCanvas(ResourceReqDetails resourceMetaData) throws Exception { + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(resourceMetaData.getName()); + CanvasElement computeElement = canvasManager.createElementOnCanvas(resourceMetaData.getName()); + canvasManager.clickOnCanvaElement(computeElement); + String selectedInstanceName = CompositionPage.getSelectedInstanceName(); + return selectedInstanceName; + } + + public static void changeDeleteAndValidateVersionOnGeneralPage(String previousVersion, String currentVersion, String serviceName) throws Exception{ + GeneralPageElements.selectVersion("V" + previousVersion); + ServiceVerificator.verifyVersionUI(previousVersion); + GeneralUIUtils.clickJSOnElementByText("latest version"); + ServiceVerificator.verifyVersionUI(currentVersion); + GeneralPageElements.clickTrashButtonAndConfirm(); + GeneralUIUtils.findComponentAndClick(serviceName); + ServiceVerificator.verifyVersionUI(previousVersion); + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VFCArtifacts.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VFCArtifacts.java new file mode 100644 index 0000000000..2c7dc9868d --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VFCArtifacts.java @@ -0,0 +1,402 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.devCI.ArtifactFromCsar; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.TesterOperationPage; +import org.openecomp.sdc.ci.tests.utilities.DownloadManager; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.verificator.VFCArtifactVerificator; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; +import com.clearspring.analytics.util.Pair; + +public class VFCArtifacts extends SetupCDTest { + + private static final String DEPLOYMENT = "Deployment"; + private static final String INFORMATIONAL = "Informational"; + private static final String ARTIFACTS = "artifacts"; + private static final String DEPLOYMENT_ARTIFACTS = "deploymentArtifacts"; + private String filePath; + private Object object; + @BeforeClass + public void beforeClass(){ + filePath = System.getProperty("filepath"); + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath() + "VFCArtifacts"+ File.separator; + } + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator + "VFCArtifacts"+ File.separator; + } + } + + @Test + public void ImportMultiVFCTest_TC1407998() throws Exception{ + + String csarFile = "Import_Multi_VFC.csar"; + + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + resourceMetaData.setVersion("0.1"); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, csarFile, getUser()); + + RestResponse getResponse = RestCDUtils.getResource(resourceMetaData, getUser()); + assertTrue(getResponse.getErrorCode().intValue() == 200); + + Map> expectedArtifactMap = verifyVfcArtifacts(filePath, csarFile, resourceMetaData, getResponse); + + VFCArtifactVerificator.verifyVFCArtifactsNotInVFArtifactList(resourceMetaData, getUser(), getResponse, expectedArtifactMap); + + + } + + @Test + public void updateCsarWithVFCArtifacts_ModifyArtifacts_TC1449482() throws Exception{ + + String csarFile = "LDSA-ORIG.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + resourceMetaData.setVersion("0.1"); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, csarFile, getUser()); + + Map artifactsFromCsar = ArtifactFromCsar.getVFCArtifacts(filePath + csarFile); + List vfcKeys = artifactsFromCsar.keySet().stream().filter(p -> p.contains("vfc")).collect(Collectors.toList()); + for (String key : vfcKeys){ + VFCArtifactVerificator.setActualVfcArtifactList(key, resourceMetaData, getUser()); + } + + String updatedCsarFile = "LDSA-MODIFY.csar"; + ResourceUIUtils.updateVfWithCsar(filePath, updatedCsarFile); + + Map updatedArtifactsFromCsar = ArtifactFromCsar.getVFCArtifacts(filePath + updatedCsarFile); + List updatedVfcKeys = updatedArtifactsFromCsar.keySet().stream().filter(p -> p.contains("vfc")).collect(Collectors.toList()); + for (String key : updatedVfcKeys){ + verifyVfcInstanceArtifacts(resourceMetaData, null, updatedArtifactsFromCsar, key); + VFCArtifactVerificator.verifyVfcArtifactUpdated(key, resourceMetaData, getUser()); + } + } + + @Test + public void updateCsarWithVFCArtifacts_DeleteAndAddArtifacts_TC1449473() throws Exception{ + String csarFile = "LDSA-ORIG.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + resourceMetaData.setVersion("0.1"); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, csarFile, getUser()); + + String updatedCsarFile = "LDSA-DELETE-ADD.csar"; + ResourceUIUtils.updateVfWithCsar(filePath, updatedCsarFile); + + verifyVfcArtifacts(filePath, updatedCsarFile, resourceMetaData, null); + } + + @Test + public void updateCsarWithVFCArtifacts_AddFirstVFCIdentifier_TC1425896() throws Exception{ + + String csarFile = "LDSA-ORIG-OLD_STRUCTURE.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + resourceMetaData.setVersion("0.1"); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, csarFile, getUser()); + + VFCArtifactVerificator.verifyNoVfcArtifacts(resourceMetaData, getUser(), null); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + String[] artifactNamesFromFile = ArtifactFromCsar.getArtifactNamesFromCsar(filePath, csarFile); + String[] artifactsFromFileBeforeUpdate = DeploymentArtifactPage.verifyArtifactsExistInTable(artifactNamesFromFile); + DeploymentArtifactPage.getLeftMenu().moveToGeneralScreen(); + + String updatedCsarFile = "LDSA-ADD.csar"; + ResourceUIUtils.updateVfWithCsar(filePath, updatedCsarFile); + + verifyVfcArtifacts(filePath, updatedCsarFile, resourceMetaData, null); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + DeploymentArtifactPage.verifyArtifactsExistInTable(artifactsFromFileBeforeUpdate); + } + + + @Test + public void updateCsarWithVFCArtifacts_AddAdditionalVFCIdentifier_TC1425898() throws Exception{ + + String csarFile = "LDSA-SINGLE.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + resourceMetaData.setVersion("0.1"); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, csarFile, getUser()); + + Map artifactsFromCsar = ArtifactFromCsar.getVFCArtifacts(filePath + csarFile); + List vfcKeys = artifactsFromCsar.keySet().stream().filter(p -> p.contains("vfc")).collect(Collectors.toList()); + for (String key : vfcKeys){ + VFCArtifactVerificator.setActualVfcArtifactList(key, resourceMetaData, getUser()); + } + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + String[] artifactNamesFromFile = ArtifactFromCsar.getArtifactNamesFromCsar(filePath, csarFile); + String[] artifactsFromFileBeforeUpdate = DeploymentArtifactPage.verifyArtifactsExistInTable(artifactNamesFromFile); + DeploymentArtifactPage.getLeftMenu().moveToGeneralScreen(); + + String updatedCsarFile = "LDSA-MULTI.csar"; + ResourceUIUtils.updateVfWithCsar(filePath, updatedCsarFile); + + Map updatedArtifactsFromCsar = ArtifactFromCsar.getVFCArtifacts(filePath + updatedCsarFile); + List updatedVfcKeys = updatedArtifactsFromCsar.keySet().stream().filter(p -> p.contains("vfc")).collect(Collectors.toList()); + for (String key : updatedVfcKeys){ + verifyVfcInstanceArtifacts(resourceMetaData, null, updatedArtifactsFromCsar, key); + if (vfcKeys.contains(key)){ + VFCArtifactVerificator.verifyVFCArtifactNotChanged(key, resourceMetaData, getUser()); + } + } + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + DeploymentArtifactPage.verifyArtifactsExistInTable(artifactsFromFileBeforeUpdate); + } + + @Test + public void updateCsarWithVFCArtifacts_DeleteAll_TC1425581() throws Exception{ + String csarFile = "LDSA-ORIG.csar"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType("ciRes", NormativeTypesEnum.ROOT, ResourceCategoryEnum.APPLICATION_L4_DATABASE, getUser().getUserId(), ResourceTypeEnum.VF.toString()); + resourceMetaData.setVersion("0.1"); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, csarFile, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + String[] artifactNamesFromFile = ArtifactFromCsar.getArtifactNamesFromCsar(filePath, csarFile); + String[] artifactsFromFileBeforeUpdate = DeploymentArtifactPage.verifyArtifactsExistInTable(artifactNamesFromFile); + DeploymentArtifactPage.getLeftMenu().moveToGeneralScreen(); + + String updatedCsarFile = "LDSA-DELETE-ALL.csar"; + ResourceUIUtils.updateVfWithCsar(filePath, updatedCsarFile); + + VFCArtifactVerificator.verifyNoVfcArtifacts(resourceMetaData, getUser(), null); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + DeploymentArtifactPage.verifyArtifactsExistInTable(artifactsFromFileBeforeUpdate); + } + + @Test + public void importComplexVFCArtifacts_Onboarding_TC1484153() throws Exception{ + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + String vnfFile = "vProbes_FE.zip"; + String snmpFile = "Fault-alarms-ASDC-vprobes-vLB.zip"; + + OnboardingUtils.createVendorLicense(getUser()); + Pair> createVSP = OnboardingUtils.createVSP(vnfFile, filePath, getUser()); + String vspName = createVSP.left; + resourceMetaData.setName(vspName); + Map resourceMeta = createVSP.right; + String vspid = resourceMeta.get("vspId"); + OnboardingUtils.addVFCArtifacts(filePath, snmpFile, null, vspid, getUser()); + OnboardingUtils.prepareVspForUse(getUser(), vspid); + + String downloadDirectory = getWindowTest().getDownloadDirectory(); + String csarFile = vspid + ".csar"; + + DownloadManager.downloadCsarByNameFromVSPRepository(vspName, vspid); + HomePage.showVspRepository(); + OnboardingUtils.importVSP(createVSP); + resourceMetaData.setVersion("0.1"); + + verifyVfcArtifacts(downloadDirectory, csarFile, resourceMetaData, null); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + DeploymentArtifactPage.verifyArtifactsExistInTable(filePath, vnfFile); + + } + + @Test + public void updateComplexVFCArtifacts_AddRemove_Onboarding_TC1484185() throws Exception{ + + //check of version is 1 + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + String vnfFile = "vProbes_FE.zip"; + String snmpPollFile = "vprobes-vLB.zip"; + String updatedSnmpPollFile = "vprobes-vLBAgent.zip"; + + OnboardingUtils.createVendorLicense(getUser()); + Pair> createVSP = OnboardingUtils.createVSP(vnfFile, filePath, getUser()); + String vspName = createVSP.left; + resourceMetaData.setName(vspName); + Map resourceMeta = createVSP.right; + String vspid = resourceMeta.get("vspId"); + String montoringComponentId = OnboardingUtils.addVFCArtifacts(filePath, snmpPollFile, null, vspid, getUser()); + OnboardingUtils.prepareVspForUse(getUser(), vspid); + + String downloadDirectory = getWindowTest().getDownloadDirectory(); + String csarFile = vspid + ".csar"; + + DownloadManager.downloadCsarByNameFromVSPRepository(vspName, vspid); + HomePage.showVspRepository(); + OnboardingUtils.importVSP(createVSP); + + ResourceGeneralPage.clickSubmitForTestingButton(vspName); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vspName); + TesterOperationPage.certifyComponent(vspName); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + OnboardingUtils.updateVspWithVfcArtifacts(filePath, vspid, updatedSnmpPollFile, null, montoringComponentId, getUser()); + DownloadManager.downloadCsarByNameFromVSPRepository(vspName, vspid); + HomePage.showVspRepository(); + OnboardingUtils.updateVSP(createVSP); + resourceMetaData.setVersion("1.1"); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + DeploymentArtifactPage.verifyArtifactsExistInTable(filePath, vnfFile); + + verifyVfcArtifacts(downloadDirectory, csarFile, resourceMetaData, null); + + } + + @Test + public void updateComplexVFCArtifacts_Modify_Onboarding_TC1484195() throws Exception{ + + //check of version is 2 + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + String vnfFile = "vProbes_FE.zip"; + String snmpFile = "vprobes-vLB.zip"; + String updatedSnmpFile = "vprobes-vLB-Modified.zip"; + + OnboardingUtils.createVendorLicense(getUser()); + Pair> createVSP = OnboardingUtils.createVSP(vnfFile, filePath, getUser()); + String vspName = createVSP.left; + resourceMetaData.setName(vspName); + Map resourceMeta = createVSP.right; + String vspid = resourceMeta.get("vspId"); + String monitoringId = OnboardingUtils.addVFCArtifacts(filePath, snmpFile, null, vspid, getUser()); + OnboardingUtils.prepareVspForUse(getUser(), vspid); + + String downloadDirectory = getWindowTest().getDownloadDirectory(); + String csarFile = vspid + ".csar"; + + DownloadManager.downloadCsarByNameFromVSPRepository(vspName, vspid); + HomePage.showVspRepository(); + OnboardingUtils.importVSP(createVSP); + + Map artifactsFromCsar = ArtifactFromCsar.getVFCArtifacts(downloadDirectory + csarFile); + List vfcKeys = artifactsFromCsar.keySet().stream().filter(p -> p.contains("vfc")).collect(Collectors.toList()); + for (String key : vfcKeys){ + resourceMetaData.setVersion("0.1"); + VFCArtifactVerificator.setActualVfcArtifactList(key, resourceMetaData, getUser()); + } + + ResourceGeneralPage.clickSubmitForTestingButton(vspName); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vspName); + TesterOperationPage.certifyComponent(vspName); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + OnboardingUtils.updateVspWithVfcArtifacts(filePath, vspid, updatedSnmpFile, null, monitoringId, getUser()); + DownloadManager.downloadCsarByNameFromVSPRepository(vspName, vspid); + HomePage.showVspRepository(); + OnboardingUtils.updateVSP(createVSP); + resourceMetaData.setVersion("1.1"); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + DeploymentArtifactPage.verifyArtifactsExistInTable(filePath, vnfFile); + + Map artifactsFromCsarAfterUpdate = ArtifactFromCsar.getVFCArtifacts(downloadDirectory + csarFile); + List vfcKeysAfterUpdate = artifactsFromCsarAfterUpdate.keySet().stream().filter(p -> p.contains("vfc")).collect(Collectors.toList()); + for (String key : vfcKeysAfterUpdate){ + verifyVfcInstanceArtifacts(resourceMetaData, null, artifactsFromCsarAfterUpdate, key); + VFCArtifactVerificator.verifyVfcArtifactUpdated(key, resourceMetaData, getUser()); + } + + } + + + + + + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + + private Map> verifyVfcArtifacts(String filepath, String csarFile, + ResourceReqDetails resourceMetaData, RestResponse getResponse) throws Exception { + ExtentTestActions.log(Status.INFO, "Verifying VFC artifacts"); + Map> expectedArtifactMap = null; + ExtentTestActions.log(Status.INFO, "Reading artifacts in CSAR file"); + Map artifactsFromCsar = ArtifactFromCsar.getVFCArtifacts(filepath + csarFile); + List vfcKeys = artifactsFromCsar.keySet().stream().filter(p -> p.contains("vfc")).collect(Collectors.toList()); + for (String key : vfcKeys){ + expectedArtifactMap = verifyVfcInstanceArtifacts(resourceMetaData, getResponse, artifactsFromCsar, key); + } + return expectedArtifactMap; + } + + private Map> verifyVfcInstanceArtifacts( + ResourceReqDetails resourceMetaData, RestResponse getResponse, Map artifactsFromCsar, String key) { + + Map> expectedArtifactMap; + Map> vfcDeploymentArtifacts = (Map>)artifactsFromCsar.get(key); + LinkedList deploymentList = vfcDeploymentArtifacts.get(DEPLOYMENT); + LinkedList informationalList = (LinkedList) artifactsFromCsar.get(INFORMATIONAL); + + expectedArtifactMap = new HashMap>(); + if(deploymentList == null){ + expectedArtifactMap.put(DEPLOYMENT_ARTIFACTS, new LinkedList()); + }else{ + expectedArtifactMap.put(DEPLOYMENT_ARTIFACTS, deploymentList); + } + if(informationalList == null){ + expectedArtifactMap.put(ARTIFACTS, new LinkedList()); + }else{ + expectedArtifactMap.put(ARTIFACTS, informationalList); + } + + + VFCArtifactVerificator.verifyVfcArtifacts(resourceMetaData, getUser(), key, expectedArtifactMap, getResponse); + return expectedArtifactMap; + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Vf.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Vf.java new file mode 100644 index 0000000000..078bc69001 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/Vf.java @@ -0,0 +1,687 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import java.awt.AWTException; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.InformationalArtifactsPlaceholders; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.ResourceMetadataEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.ToscaArtifactsScreenEnum; +import org.openecomp.sdc.ci.tests.datatypes.LifeCycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.NormativeTypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.AttFtpClient; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openecomp.sdc.ci.tests.pages.InformationalArtifactPage; +import org.openecomp.sdc.ci.tests.pages.InputsPage; +import org.openecomp.sdc.ci.tests.pages.PropertiesPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.TesterOperationPage; +import org.openecomp.sdc.ci.tests.pages.ToscaArtifactsPage; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaDefinition; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; +import org.openecomp.sdc.ci.tests.utilities.PropertiesUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.ci.tests.verificator.ServiceVerificator; +import org.openecomp.sdc.ci.tests.verificator.VfModuleVerificator; +import org.openecomp.sdc.ci.tests.verificator.VfVerificator; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.AssertJUnit; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; +import com.clearspring.analytics.util.Pair; + + +public class Vf extends SetupCDTest { + + private String filePath; + @BeforeClass + public void beforeClass(){ + filePath = System.getProperty("filepath"); + if (filePath == null && System.getProperty("os.name").contains("Windows")) { + filePath = FileHandling.getResourcesFilesPath(); + } + else if(filePath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filePath = FileHandling.getBasePath() + File.separator + "Files" + File.separator; + } + } + + @BeforeMethod + public void beforeTest(){ + System.out.println("File repository is : " + filePath); + getExtendTest().log(Status.INFO, "File repository is : " + filePath); + } + + + @Test + public void updateVF() throws Exception { + + // create Resource + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(resourceMetaData, getUser()); + + // update Resource + ResourceReqDetails updatedResource = new ResourceReqDetails(); + updatedResource.setName("ciUpdatedName"); + updatedResource.setDescription("kuku"); + updatedResource.setVendorName("updatedVendor"); + updatedResource.setVendorRelease("updatedRelease"); + updatedResource.setContactId("ab0001"); + updatedResource.setCategories(resourceMetaData.getCategories()); + updatedResource.setVersion("0.1"); + updatedResource.setResourceType(ResourceTypeEnum.VF.getValue()); + List newTags = resourceMetaData.getTags(); + newTags.remove(resourceMetaData.getName()); + newTags.add(updatedResource.getName()); + updatedResource.setTags(newTags); + ResourceUIUtils.updateResource(updatedResource, getUser()); + + VfVerificator.verifyVFMetadataInUI(updatedResource); + VfVerificator.verifyVFUpdated(updatedResource, getUser()); + } + + @Test + public void vfcLinkedToComputeInVfFlow() throws Exception { + String fileName = "vFW_VFC2.yml"; + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + + try{ + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(atomicResourceMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(atomicResourceMetaData.getName()); + TesterOperationPage.certifyComponent(atomicResourceMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(String.format("%s %s", LeftPanelCanvasItems.COMPUTE.getValue() , "1.0")); + CanvasElement computeElement = canvasManager.createElementOnCanvas(LeftPanelCanvasItems.COMPUTE); + CompositionPage.searchForElement(atomicResourceMetaData.getName()); + CanvasElement cpElement = canvasManager.createElementOnCanvas(atomicResourceMetaData.getName()); + AssertJUnit.assertNotNull(cpElement); + ServiceVerificator.verifyNumOfComponentInstances(vfMetaData, "0.1", 2, getUser()); + canvasManager.linkElements(cpElement, computeElement); + + vfMetaData.setVersion("0.1"); + VfVerificator.verifyLinkCreated(vfMetaData, getUser(), 1); + } + finally{ + ResourceRestUtils.deleteResourceByNameAndVersion(atomicResourceMetaData.getName(), "1.0"); + } + + } + + @Test + public void addUpdateDeleteDeploymentArtifactToVfTest() throws Exception { + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + List deploymentArtifactList = new ArrayList(); + deploymentArtifactList.add(new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER")); + deploymentArtifactList.add(new ArtifactInfo(filePath, "sample-xml-alldata-1-1.xml", "cuku", "artifact2", "YANG_XML")); + for (ArtifactInfo deploymentArtifact : deploymentArtifactList) { + DeploymentArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(deploymentArtifact); + } + AssertJUnit.assertTrue("artifact table does not contain artifacts uploaded", DeploymentArtifactPage.checkElementsCountInTable(deploymentArtifactList.size())); + + String newDescription = "new description"; + DeploymentArtifactPage.clickEditArtifact(deploymentArtifactList.get(0).getArtifactLabel()); + DeploymentArtifactPage.artifactPopup().insertDescription(newDescription); + DeploymentArtifactPage.artifactPopup().clickDoneButton(); + String actualArtifactDescription = DeploymentArtifactPage.getArtifactDescription(deploymentArtifactList.get(0).getArtifactLabel()); + AssertJUnit.assertTrue("artifact description is not updated", newDescription.equals(actualArtifactDescription)); + + DeploymentArtifactPage.clickDeleteArtifact(deploymentArtifactList.get(0).getArtifactLabel()); + DeploymentArtifactPage.clickOK(); + AssertJUnit.assertTrue("artifact "+ deploymentArtifactList.get(0).getArtifactLabel() + "is not deleted", DeploymentArtifactPage.checkElementsCountInTable(deploymentArtifactList.size() - 1)); + + AssertJUnit.assertTrue("artifact "+ deploymentArtifactList.get(1).getArtifactLabel() + "is not displayed", DeploymentArtifactPage.clickOnArtifactDescription(deploymentArtifactList.get(1).getArtifactLabel()).isDisplayed()); + } + + + @Test + public void addUpdateDeleteInformationalArtifact() throws Exception { + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + ArtifactInfo informationalArtifact = new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER"); + InformationalArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(informationalArtifact); + + AssertJUnit.assertTrue("artifact table does not contain artifacts uploaded", InformationalArtifactPage.checkElementsCountInTable(1)); + + String newDescription = "new description"; + InformationalArtifactPage.clickEditArtifact(informationalArtifact.getArtifactLabel()); + InformationalArtifactPage.artifactPopup().insertDescription(newDescription); + InformationalArtifactPage.artifactPopup().clickDoneButton(); + String actualArtifactDescription = InformationalArtifactPage.getArtifactDescription(informationalArtifact.getArtifactLabel()); + AssertJUnit.assertTrue("artifact description is not updated", newDescription.equals(actualArtifactDescription)); + + InformationalArtifactPage.clickDeleteArtifact(informationalArtifact.getArtifactLabel()); + InformationalArtifactPage.clickOK(); + AssertJUnit.assertTrue("artifact "+ informationalArtifact.getArtifactLabel() + "is not deleted", InformationalArtifactPage.checkElementsCountInTable(0)); + } + + + @Test + public void addPropertiesToVfcInstanceInVfTest() throws Exception { + + if(true){ + throw new SkipException("Open bug 292047"); + } + + String fileName = "vFW_VFC.yml"; + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + + try{ + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceGeneralPage.clickCheckinButton(atomicResourceMetaData.getName()); + + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager vfCanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(atomicResourceMetaData.getName()); + CanvasElement vfcElement = vfCanvasManager.createElementOnCanvas(atomicResourceMetaData.getName()); + + vfCanvasManager.clickOnCanvaElement(vfcElement); + CompositionPage.showPropertiesAndAttributesTab(); + List properties = CompositionPage.getProperties(); + String propertyValue = "abc123"; + for (int i = 0; i < 2; i++) { + WebElement findElement = properties.get(i).findElement(By.className("i-sdc-designer-sidebar-section-content-item-property-and-attribute-label")); + findElement.click(); + PropertiesPage.getPropertyPopup().insertPropertyDefaultValue(propertyValue); + PropertiesPage.getPropertyPopup().clickSave(); + + + findElement = properties.get(i).findElement(By.className("i-sdc-designer-sidebar-section-content-item-property-value")); + AssertJUnit.assertTrue(findElement.getText().equals(propertyValue)); + } + } + finally{ + ResourceRestUtils.deleteResourceByNameAndVersion(atomicResourceMetaData.getName(), "0.1"); + } + } + + @Test + public void changeInstanceVersionTest() throws Exception{ + + if(true){ + throw new SkipException("Open bug 291567"); + } + + ResourceReqDetails atomicResourceMetaData = null; + ResourceReqDetails vfMetaData = null; + CanvasManager vfCanvasManager; + CanvasElement vfcElement = null; + String fileName = "vFW_VFC3.yml"; + try{ + atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(atomicResourceMetaData.getName()); + + vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + vfCanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(atomicResourceMetaData.getName()); + vfcElement = vfCanvasManager.createElementOnCanvas(atomicResourceMetaData.getName()); + + + CompositionPage.clickSubmitForTestingButton(vfMetaData.getName()); + assert(false); + } + catch(Exception e){ + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.VALIDATED_RESOURCE_NOT_FOUND.name()); + AssertJUnit.assertTrue(errorMessage.contains(checkUIResponseOnError)); + + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(atomicResourceMetaData.getName()); + TesterOperationPage.certifyComponent(atomicResourceMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + vfCanvasManager = CanvasManager.getCanvasManager(); + CompositionPage.changeComponentVersion(vfCanvasManager, vfcElement, "1.0"); + + //verfication + VfVerificator.verifyInstanceVersion(vfMetaData, getUser(), atomicResourceMetaData.getName(), "1.0"); + } + + finally{ + ResourceRestUtils.deleteResourceByNameAndVersion(atomicResourceMetaData.getName(), "1.0"); + } + + } + + // future removed from ui + @Test(enabled = false) + public void addUpdateDeleteSimplePropertiesToVfTest() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToPropertiesScreen(); + List propertyList = Arrays.asList(PropertyTypeEnum.STRING, PropertyTypeEnum.INTEGER); + int propertiesCount = PropertiesPage.getElemenetsFromTable().size(); + for (PropertyTypeEnum prop : propertyList){ + PropertiesUIUtils.addNewProperty(prop); + } + AssertJUnit.assertTrue(GeneralUIUtils.checkElementsCountInTable(propertiesCount + propertyList.size(), () -> PropertiesPage.getElemenetsFromTable())); + VfVerificator.verifyPropertiesInUI(propertyList); + PropertiesPage.verifyTotalProperitesField(propertiesCount + propertyList.size()); + + + PropertyTypeEnum prop = propertyList.get(0); + prop.setDescription("updatedDescription"); + prop.setValue("value"); + PropertiesUIUtils.updateProperty(prop); + + PropertiesPage.clickDeletePropertyArtifact(prop.getName()); + AssertJUnit.assertTrue(GeneralUIUtils.checkElementsCountInTable(propertiesCount + propertyList.size() - 1, () -> PropertiesPage.getElemenetsFromTable())); + } + + // future removed from ui + @Test(enabled = false) + public void vfcInstancesInputScreenTest() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager vfCanvasManager = CanvasManager.getCanvasManager(); + + Map elementsIntancesMap = new HashMap(); + for (LeftPanelCanvasItems element : Arrays.asList(LeftPanelCanvasItems.DATABASE, LeftPanelCanvasItems.BLOCK_STORAGE)){ + CanvasElement elementOnCanvas = vfCanvasManager.createElementOnCanvas(element); + vfCanvasManager.clickOnCanvaElement(elementOnCanvas); + String selectedInstanceName = CompositionPage.getSelectedInstanceName(); + elementsIntancesMap.put(selectedInstanceName, element.getValue()); + } + + CompositionPage.moveToInputsScreen(); + int canvasElementsSize = vfCanvasManager.getCanvasElements().size(); + AssertJUnit.assertTrue("Instances count is not as expected: " + canvasElementsSize, InputsPage.checkElementsCountInTable(canvasElementsSize)); + + for (String element : elementsIntancesMap.keySet()){ + String resourceName = elementsIntancesMap.get(element); + ResourceReqDetails resource = new ResourceReqDetails(); + resource.setName(resourceName); + resource.setVersion("1.0"); + resource.setResourceType(ResourceTypeEnum.VFC.toString()); + RestResponse restResponse = RestCDUtils.getResource(resource, getUser()); + Map propertiesNameTypeJson = ResponseParser.getPropertiesNameType(restResponse); + + List propertyRowsFromTable = InputsPage.getInstancePropertiesList(element); + AssertJUnit.assertTrue("Some properties are missing in table. Instance name is : " + element, propertyRowsFromTable.size() == propertiesNameTypeJson.size()); + VfVerificator.verifyVfInputs(element, propertiesNameTypeJson, propertyRowsFromTable); + + GeneralUIUtils.clickOnElementByText(element); + } + + } + + + @Test + public void addAllInformationalArtifactPlaceholdersInVfTest() throws Exception{ + + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VF, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + + for(InformationalArtifactsPlaceholders informArtifact : InformationalArtifactsPlaceholders.values()){ + ArtifactUIUtils.fillPlaceHolderInformationalArtifact(informArtifact, filePath,"asc_heat 0 2.yaml", informArtifact.getValue()); + } + + AssertJUnit.assertTrue(InformationalArtifactPage.checkElementsCountInTable(InformationalArtifactsPlaceholders.values().length)); + } + + @Test + public void verifyToscaArtifactsExist() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + final int numOfToscaArtifacts = 2; + ResourceGeneralPage.getLeftMenu().moveToToscaArtifactsScreen(); + AssertJUnit.assertTrue(ToscaArtifactsPage.checkElementsCountInTable(numOfToscaArtifacts)); + + for(int i = 0; i < numOfToscaArtifacts; i++){ + String typeFromScreen = ToscaArtifactsPage.getArtifactType(i); + AssertJUnit.assertTrue(typeFromScreen.equals(ArtifactTypeEnum.TOSCA_CSAR.getType()) || typeFromScreen.equals(ArtifactTypeEnum.TOSCA_TEMPLATE.getType())); + } + + ToscaArtifactsPage.clickSubmitForTestingButton(vfMetaData.getName()); + VfVerificator.verifyToscaArtifactsInfo(vfMetaData, getUser()); + } + + @Test(enabled=false) + public void testDownload() throws Exception{ +// ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); +// ResourceUIUtils.createResource(vfMetaData, getUser()); +// +// final int numOfToscaArtifacts = 2; +// ResourceGeneralPage.getLeftMenu().moveToToscaArtifactsScreen(); +// assertTrue(ToscaArtifactsPage.checkElementsCountInTable(numOfToscaArtifacts)); +// GeneralUIUtils.clickOnElementByTestId("download-Tosca Model"); +// System.out.println("download me"); + + AttFtpClient attFtpClient = AttFtpClient.getInstance(); + + File retrieveLastModifiedFileFromFTP = attFtpClient.retrieveLastModifiedFileFromFTP(); + attFtpClient.deleteFilesFromFTPserver(); + } + + @Test + public void vfCertificationTest() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + String vfName = vfMetaData.getName(); + + ResourceGeneralPage.clickCheckinButton(vfName); + GeneralUIUtils.findComponentAndClick(vfName); + ResourceGeneralPage.clickSubmitForTestingButton(vfName); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfName); + TesterOperationPage.certifyComponent(vfName); + + vfMetaData.setVersion("1.0"); + VfVerificator.verifyVFLifecycle(vfMetaData, getUser(), LifecycleStateEnum.CERTIFIED); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(vfName); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CERTIFIED); + } + + @Test + public void deleteVfCheckedoutTest() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + GeneralPageElements.clickTrashButtonAndConfirm(); + + vfMetaData.setVersion("0.1"); + VfVerificator.verifyVfDeleted(vfMetaData, getUser()); + } + + @Test + public void revertVfMetadataTest() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceReqDetails vfRevertDetails = new ResourceReqDetails(); + vfRevertDetails.setName("ciUpdatedName"); + vfRevertDetails.setDescription("kuku"); + vfRevertDetails.setCategories(vfMetaData.getCategories()); + vfRevertDetails.setVendorName("updatedVendor"); + vfRevertDetails.setVendorRelease("updatedRelease"); + ResourceUIUtils.fillResourceGeneralInformationPage(vfRevertDetails, getUser(), false); + + GeneralPageElements.clickRevertButton(); + + VfVerificator.verifyVFMetadataInUI(vfMetaData); + + } + + @Test + public void addDeploymentArtifactInCompositionScreenTest() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + ArtifactInfo artifact = new ArtifactInfo(filePath, "Heat-File.yaml", "kuku", "artifact3","OTHER"); + CompositionPage.showDeploymentArtifactTab(); + CompositionPage.clickAddArtifactButton(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(artifact, CompositionPage.artifactPopup()); + + List actualArtifactList = GeneralUIUtils.getWebElementsListBy(By.className("i-sdc-designer-sidebar-section-content-item-artifact")); + AssertJUnit.assertEquals(1, actualArtifactList.size()); + } + + // future removed from ui + @Test(enabled = false) + public void addPropertyInCompositionScreenTest() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + CompositionPage.showPropertiesAndAttributesTab(); + List propertyList = Arrays.asList(PropertyTypeEnum.STRING, PropertyTypeEnum.INTEGER); + int propertiesCount = CompositionPage.getProperties().size(); + for (PropertyTypeEnum prop : propertyList){ + PropertiesUIUtils.addNewProperty(prop); + } + AssertJUnit.assertTrue(GeneralUIUtils.checkElementsCountInTable(propertiesCount + propertyList.size(), () -> CompositionPage.getProperties())); + } + + @Test + public void addDeploymentArtifactAndVerifyInCompositionScreen() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + ArtifactInfo deploymentArtifact = new ArtifactInfo(filePath, "asc_heat 0 2.yaml", "kuku", "artifact1", "OTHER"); + DeploymentArtifactPage.clickAddNewArtifact(); + ArtifactUIUtils.fillAndAddNewArtifactParameters(deploymentArtifact); + AssertJUnit.assertTrue(DeploymentArtifactPage.checkElementsCountInTable(1)); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + CompositionPage.showDeploymentArtifactTab(); + List deploymentArtifactsFromScreen = CompositionPage.getDeploymentArtifacts(); + AssertJUnit.assertTrue(1 == deploymentArtifactsFromScreen.size()); + + String actualArtifactFileName = deploymentArtifactsFromScreen.get(0).getText(); + AssertJUnit.assertTrue("asc_heat-0-2.yaml".equals(actualArtifactFileName)); + } + + @Test + public void checkoutVfTest() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.clickCheckinButton(vfMetaData.getName()); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + GeneralPageElements.clickCheckoutButton(); + + vfMetaData.setVersion("0.2"); + VfVerificator.verifyVFLifecycle(vfMetaData, getUser(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKOUT); + + ResourceGeneralPage.clickSubmitForTestingButton(vfMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.TESTER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + TesterOperationPage.certifyComponent(vfMetaData.getName()); + + reloginWithNewRole(UserRoleEnum.DESIGNER); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + ResourceGeneralPage.clickCheckoutButton(); + + vfMetaData.setVersion("1.1"); + vfMetaData.setUniqueId(null); + VfVerificator.verifyVFLifecycle(vfMetaData, getUser(), LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + VfVerificator.verifyVfLifecycleInUI(LifeCycleStateEnum.CHECKOUT); + } + + @Test + public void deleteInstanceFromVfCanvas() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager vfCanvasManager = CanvasManager.getCanvasManager(); + CanvasElement computeElement = vfCanvasManager.createElementOnCanvas(LeftPanelCanvasItems.COMPUTE); + CanvasElement portElement = vfCanvasManager.createElementOnCanvas(LeftPanelCanvasItems.PORT); + + vfCanvasManager.clickOnCanvaElement(computeElement); + vfCanvasManager.deleteElementFromCanvas(computeElement); + + VfVerificator.verifyNumOfComponentInstances(vfMetaData, 1, getUser()); + } + + @Test + public void changeInstanceNameInVfTest() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager vfCanvasManager = CanvasManager.getCanvasManager(); + CanvasElement computeElement = vfCanvasManager.createElementOnCanvas(LeftPanelCanvasItems.COMPUTE); + + String updatedInstanceName = "updatedName"; + vfCanvasManager.updateElementNameInCanvas(computeElement, updatedInstanceName); + + String actualSelectedInstanceName = CompositionPage.getSelectedInstanceName(); + AssertJUnit.assertTrue(updatedInstanceName.equals(actualSelectedInstanceName)); + } + + + @Test + public void submitVfForTestingWithNonCertifiedAsset() throws Exception{ + String fileName = "vFW_VFC4.yml"; + + ResourceReqDetails atomicResourceMetaData = ElementFactory.getDefaultResourceByTypeNormTypeAndCatregory(ResourceTypeEnum.VFC, NormativeTypesEnum.ROOT, ResourceCategoryEnum.NETWORK_L2_3_ROUTERS, getUser()); + ResourceUIUtils.importVfc(atomicResourceMetaData, filePath, fileName, getUser()); + ResourceGeneralPage.clickSubmitForTestingButton(atomicResourceMetaData.getName()); + + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + DeploymentArtifactPage.getLeftMenu().moveToCompositionScreen(); + CanvasManager canvasManager = CanvasManager.getCanvasManager(); + CompositionPage.searchForElement(atomicResourceMetaData.getName()); + canvasManager.createElementOnCanvas(atomicResourceMetaData.getName()); + + try{ + CompositionPage.clickSubmitForTestingButton(vfMetaData.getName()); + assert(false); + } + catch(Exception e){ + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.VALIDATED_RESOURCE_NOT_FOUND.name()); + AssertJUnit.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + finally{ + ResourceRestUtils.deleteResourceByNameAndVersion(atomicResourceMetaData.getName(), "0.1"); + } + } + + @Test + public void isDisabledAndReadOnlyInCheckin() throws Exception{ + ResourceReqDetails vfMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.createResource(vfMetaData, getUser()); + ResourceGeneralPage.clickCheckinButton(vfMetaData.getName()); + GeneralUIUtils.findComponentAndClick(vfMetaData.getName()); + + ResourceMetadataEnum[] fieldsForCheck = {ResourceMetadataEnum.RESOURCE_NAME, + ResourceMetadataEnum.DESCRIPTION, ResourceMetadataEnum.VENDOR_NAME, ResourceMetadataEnum.VENDOR_RELEASE, + ResourceMetadataEnum.CONTACT_ID}; + + for (ResourceMetadataEnum field: fieldsForCheck){ + AssertJUnit.assertTrue(GeneralUIUtils.isElementReadOnly(field.getValue())); + } + + AssertJUnit.assertTrue(GeneralUIUtils.isElementDisabled(ResourceMetadataEnum.CATEGORY.getValue())); + AssertJUnit.assertTrue(GeneralUIUtils.isElementDisabled(DataTestIdEnum.LifeCyleChangeButtons.CREATE.getValue())); + } + + @Test + public void exportToscaWithModulePropertiesVFTest() throws AWTException, Exception { + String vnfFile = "2016-042_vmsp_pxmc_30_1607_e2e.zip"; + Pair> vsp=OnboardingUtils.onboardAndValidate(Onboard.getFilePath(), vnfFile, getUser()); + String vspName = vsp.left; + ResourceGeneralPage.clickSubmitForTestingButton(vsp.left); + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, vspName, "0.1"); + VfModuleVerificator.validateSpecificModulePropertiesFromRequest(resource); + } + + @Test + public void exportToscaWithModulePropertiesTemplateCheckVFTest() throws AWTException, Exception { + String vnfFile = "2016-042_vmsp_pxmc_30_1607_e2e.zip"; + OnboardingUtils.onboardAndValidate(Onboard.getFilePath(), vnfFile, getUser()); + ResourceGeneralPage.getLeftMenu().moveToToscaArtifactsScreen(); + GeneralUIUtils.clickOnElementByTestId(ToscaArtifactsScreenEnum.TOSCA_MODEL.getValue()); + File latestFilefromDir = FileHandling.getLastModifiedFileFromDir(); + ToscaDefinition toscaDefinition = VfModuleVerificator.getToscaTemplate(latestFilefromDir.getAbsolutePath()); + VfModuleVerificator.validateSpecificModulePropertiesFromFile(toscaDefinition); + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VfArtifacts.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VfArtifacts.java new file mode 100644 index 0000000000..2957379ff8 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VfArtifacts.java @@ -0,0 +1,380 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import static org.testng.AssertJUnit.assertTrue; + +import java.awt.AWTException; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.openecomp.sdc.be.datatypes.elements.HeatParameterDataDefinition; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.ci.tests.businesslogic.ArtifactBusinessLogic; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.CompositionScreenEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.StepsEnum; +import org.openecomp.sdc.ci.tests.datatypes.HeatWithParametersDefinition; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.HomeUtils; +import org.openecomp.sdc.ci.tests.utilities.OnboardingUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openqa.selenium.WebElement; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; +import com.clearspring.analytics.util.Pair; + +public class VfArtifacts extends SetupCDTest{ + + private String filePath; + private String vnfsRepositoryPath; + private String updatedVnfsRepositoryPath; + private String createdEnvFilePath; + private static final String PARAMETERS = "parameters"; + + @BeforeMethod + public void beforeTest() throws FileNotFoundException{ + filePath = getWindowTest().getDownloadDirectory(); + vnfsRepositoryPath = FileHandling.getVnfRepositoryPath(); +// vnfsRepositoryPath = FileHandling.getFilePath("Old_VNFs"); + updatedVnfsRepositoryPath = vnfsRepositoryPath + "UpdatedVNFs"; + Config config = Utils.getConfig(); + createdEnvFilePath = config.getWindowsDownloadDirectory(); + } + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + + + @DataProvider(name = "heatEnvAndVersion", parallel = false) +// parameters: VSP, updatedVsp, expectedHeatVersion, expectedHeatEnvVersion + public Object[][] provideData() { + + return new Object[][] { + { "2016-043_vsaegw_fdnt_30_1607_e2e.zip", "FDNT_UpdateHeatParams.zip", "2", "1" }, // expected heat version 2 and heatEnv 1 + { "2016-043_vsaegw_fdnt_30_1607_e2e.zip", "FDNT_WithoutEnvFiles.zip", "1", "1" }, // expected heat version 1 and heatEnv 1 + { "2016-014_vlandslide_ldsa_30_1607_e2e.zip", "2016-209_vjsa_vjsa_30_1610_e2e.zip", "1", "0" }, // expected heat version 1 and heatEnv 0 + { "2016-045_vlb_lmsp_30_1607_e2e.zip", "2016-045_vlb_lmsp_30_1607_e2e.zip", "1", "1" }, // expected heat version 1 and heatEnv 1(DE270634) + { "2016-109_mobt_mobt_30_1607_e2e.zip", "2016-109_mobt_mobt_30_1607_e2e_DifferentParams.zip", "2", "1" } // expected heat version 2 and heatEnv 1 + }; + } + +// update first env file and verify parameters value + @Test + public void uploadUpdatedHeatEnv() throws Exception{ + + String vnfFile = "2016-042_vmsp_pxmc_30_1607_e2e.zip"; + File updateEnvFile = null; + Pair> vsp = OnboardingUtils.onboardAndValidate(vnfsRepositoryPath, vnfFile, getUser()); + String vspName = vsp.left; + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, vspName, "0.1"); + Map deploymentArtifacts = resource.getDeploymentArtifacts(); + List envFilesList = ArtifactBusinessLogic.extractHeatWithParametersDefinition(deploymentArtifacts); +// create env file and update it + if(envFilesList.size()>0){ +// select index of env file to be updated + HeatWithParametersDefinition selectedEnvFileToUpdate = envFilesList.get(0); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPageEnum.EDIT_ARTIFACT.getValue()+selectedEnvFileToUpdate.getHeatEnvLabel()); + updateEnvFile = ArtifactUIUtils.uploadCreatedUpdateParametersEnvFile(selectedEnvFileToUpdate, createdEnvFilePath); + ArtifactUIUtils.verifyUpdatedEnvParameters(selectedEnvFileToUpdate, updateEnvFile); + } + else{ + SetupCDTest.getExtendTest().log(Status.INFO, "Resource does not contain HEAT files"); + } + } + +// update all env files and verify parameters value in Deployment Artifact View + @Test + public void uploadUpdatedAllHeatEnv() throws Exception{ + + String vnfFile = "2016-044_vfw_fnat_30_1607_e2e.zip"; + File updateEnvFile = null; + Pair> vsp = OnboardingUtils.onboardAndValidate(vnfsRepositoryPath, vnfFile, getUser()); + String vspName = vsp.left; + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, vspName, "0.1"); + Map deploymentArtifacts = resource.getDeploymentArtifacts(); + List envFilesList = ArtifactBusinessLogic.extractHeatWithParametersDefinition(deploymentArtifacts); + if(envFilesList.size()>0){ + for(HeatWithParametersDefinition selectedEnvFileToUpdate : envFilesList){ + // create env file and update it + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPageEnum.EDIT_ARTIFACT.getValue()+selectedEnvFileToUpdate.getHeatEnvLabel()); + updateEnvFile = ArtifactUIUtils.uploadCreatedUpdateParametersEnvFile(selectedEnvFileToUpdate, createdEnvFilePath); + ArtifactUIUtils.verifyUpdatedEnvParameters(selectedEnvFileToUpdate, updateEnvFile); + } + }else{ + SetupCDTest.getExtendTest().log(Status.INFO, "Resource does not contain HEAT files"); + } + } + +// update all env files and verify parameters value in Composition + @Test + public void uploadUpdatedAllHeatEnvComposition() throws Exception{ + + String vnfFile = "2016-014_vlandslide_ldst_30_1607_e2e.zip"; + File updateEnvFile = null; + Pair> vsp = OnboardingUtils.onboardAndValidate(vnfsRepositoryPath, vnfFile, getUser()); + String vspName = vsp.left; + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, vspName, "0.1"); + Map deploymentArtifacts = resource.getDeploymentArtifacts(); + List envFilesList = ArtifactBusinessLogic.extractHeatWithParametersDefinition(deploymentArtifacts); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.StepsEnum.COMPOSITION.getValue()); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CompositionScreenEnum.DEPLOYMENT_ARTIFACT_TAB.getValue()); + if(envFilesList.size()>0){ + for(HeatWithParametersDefinition selectedEnvFileToUpdate : envFilesList){ + // create env file and update it + String dataTestId = DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_ITEM.getValue()+selectedEnvFileToUpdate.getHeatArtifactDisplayName(); + GeneralUIUtils.hoverOnAreaByTestId(dataTestId); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPageEnum.EDIT_ARTIFACT.getValue()+selectedEnvFileToUpdate.getHeatArtifactDisplayName()); + updateEnvFile = ArtifactUIUtils.uploadCreatedUpdateParametersEnvFile(selectedEnvFileToUpdate, createdEnvFilePath); + ArtifactUIUtils.verifyUpdatedEnvParameters(selectedEnvFileToUpdate, updateEnvFile, dataTestId); + } + }else{ + SetupCDTest.getExtendTest().log(Status.INFO, "Resource does not contain HEAT files"); + } + } + +// expected heat version 1 and heatEnv 0 + @Test + // Download ENV file from VF level Update VSP. + public void downloadEnvFromVFLevelUpdateVSP() throws Throwable { + String vnfFile = "2016-043_vsaegw_fdnt_30_1607_e2e.zip"; + String updatedVnfFile="2016-014_vlandslide_ldsa_30_1607_e2e.zip"; + String downloadDirPath=SetupCDTest.getConfig().getWindowsDownloadDirectory(); + Pair> CreatedVsp=OnboardingUtils.onboardAndValidate(vnfsRepositoryPath, vnfFile, getUser()); + String vspName = CreatedVsp.left; + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtonsFromInsideFrame.HOME_BUTTON.getValue()).click(); + OnboardingUtils.updateVnfAndValidate(vnfsRepositoryPath, CreatedVsp, updatedVnfFile, getUser()); + //get updated vsp env files + Map currentZipEnvfiles=ArtifactBusinessLogic.createEnvFilesListFromCsar(vspName, downloadDirPath); + GeneralUIUtils.findComponentAndClick(vspName); + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + List deploymentArtifcatsList = DeploymentArtifactPage.getDeploymentArtifactsNamesWorkSpace(); + + for (int i = 0; i < deploymentArtifcatsList.size(); i++) { + if (DeploymentArtifactPage.getArtifactType(deploymentArtifcatsList.get(i)).equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType())) { + DeploymentArtifactPage.clickDownloadEnvArtifact(deploymentArtifcatsList.get(i)); + GeneralUIUtils.ultimateWait(); + File latestFilefromDir = FileHandling.getLastModifiedFileFromDir(downloadDirPath); + ArtifactUIUtils.compareYamlFilesByPattern(latestFilefromDir, currentZipEnvfiles.get(deploymentArtifcatsList.get(i)), PARAMETERS); + } + } + } + + @Test + // Download ENV file from VF level Work-Space. + public void downloadEnvFromVFLevelWorkSpace() throws AWTException, Exception { + String vnfFile = "2016-043_vsaegw_fdnt_30_1607_e2e.zip"; + String downloadDirPath=SetupCDTest.getConfig().getWindowsDownloadDirectory(); + + Pair> vsp=OnboardingUtils.onboardAndValidate(Onboard.getFilePath(), vnfFile, getUser()); + + Map currentZipEnvfiles=ArtifactBusinessLogic.createEnvFilesListFromCsar(vsp.left,downloadDirPath); + GeneralUIUtils.findComponentAndClick(vsp.left); + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + List deploymentArtifcatsList = DeploymentArtifactPage.getDeploymentArtifactsNamesWorkSpace(); + + for (int i = 0; i < deploymentArtifcatsList.size(); i++) { + + if (DeploymentArtifactPage.getArtifactType(deploymentArtifcatsList.get(i)).equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType())) { + DeploymentArtifactPage.clickDownloadEnvArtifact(deploymentArtifcatsList.get(i)); + GeneralUIUtils.ultimateWait(); + File latestFilefromDir = FileHandling.getLastModifiedFileFromDir(downloadDirPath); + ArtifactUIUtils.compareYamlFilesByPattern(latestFilefromDir,currentZipEnvfiles.get(deploymentArtifcatsList.get(i)), PARAMETERS); + } + } + } + + @Test + // Download ENV file from VF level Composition. + public void downloadEnvVFLevelComposition() throws AWTException, Exception { + + String downloadDirPath=SetupCDTest.getConfig().getWindowsDownloadDirectory(); + String vnfFile = "2016-043_vsaegw_fdnt_30_1607_e2e.zip"; + + Pair> vsp=OnboardingUtils.onboardAndValidate(Onboard.getFilePath(), vnfFile, getUser()); + Map currentZipEnvfiles=ArtifactBusinessLogic.createEnvFilesListFromCsar(vsp.left,downloadDirPath); + GeneralUIUtils.findComponentAndClick(vsp.left); + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + CompositionPage.clickOnTabTestID(CompositionScreenEnum.DEPLOYMENT_ARTIFACT_TAB); + List deploymentArtifcatsList = CompositionPage.getCompositionEnvArtifacts(); + + for (int i = 0; i < deploymentArtifcatsList.size(); i++) { + String fileName = GeneralUIUtils.getDataTestIdAttributeValue(deploymentArtifcatsList.get(i)).replace(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_ENV.getValue(), ""); + if (GeneralUIUtils.isElementVisibleByTestId(GeneralUIUtils.getDataTestIdAttributeValue(deploymentArtifcatsList.get(i)))) { + CompositionPage.clickDownloadEnvArtifactComposition(fileName).click(); + GeneralUIUtils.ultimateWait(); + File latestFilefromDir = FileHandling.getLastModifiedFileFromDir(downloadDirPath); + ArtifactUIUtils.compareYamlFilesByPattern(latestFilefromDir,currentZipEnvfiles.get(fileName), PARAMETERS); + } + } + } + + @Test + // Download ENV file from VF level Update parameters in UI. + public void downloadEnvVFLevelUpdateParameters() throws AWTException, Exception { + + String vnfFile = "2016-044_vfw_fcgi_30_1607_e2e.zip"; + String downloadDirPath=SetupCDTest.getConfig().getWindowsDownloadDirectory(); + Pair> CreatedVsp=OnboardingUtils.onboardAndValidate(Onboard.getFilePath(), vnfFile, getUser()); + + Resource resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, CreatedVsp.left, "0.1"); + Map deploymentArtifacts = resource.getDeploymentArtifacts(); + List envFilesList = ArtifactBusinessLogic.extractHeatWithParametersDefinition(deploymentArtifacts); + + for (int i = 0; i < envFilesList.size(); i++) { + String artifactName = envFilesList.get(i).getHeatArtifactDisplayName(); + if (envFilesList.get(i).getHeatArtifactType().equalsIgnoreCase(ArtifactTypeEnum.HEAT.getType())) { + ExtentTestActions.log(Status.INFO, String.format("Opening the edit/view artifact parameters form of %s resource...", vnfFile)); + DeploymentArtifactPage.clickEditEnvArtifact(envFilesList.get(i).getHeatArtifactDisplayName()); + + ExtentTestActions.log(Status.INFO, String.format("Going To locating all artifact parameters from UI of %s artifact...", artifactName)); + Map dataToWriteInUI = ArtifactUIUtils.getDataToWriteInUI(envFilesList.get(i).getHeatParameterDefinition()); + Map data = dataToWriteInUI; + ExtentTestActions.log(Status.INFO, String.format("Success to locate all artifact parameters from UI of %s artifact...", artifactName)); + + List listToSearchEnvParametersInUI = envFilesList.get(i).getHeatParameterDefinition(); + fillHeatEnvParametersInUi(data, listToSearchEnvParametersInUI); + + DeploymentArtifactPage.clickSaveEnvParameters(); + GeneralUIUtils.waitForLoader(); + ExtentTestActions.log(Status.INFO, String.format("Going to get the %s updated resource ...", CreatedVsp.left)); + resource = AtomicOperationUtils.getResourceObjectByNameAndVersion(UserRoleEnum.DESIGNER, CreatedVsp.left, "0.1"); + deploymentArtifacts = resource.getDeploymentArtifacts(); + Map> envFilesListupdated = new HashMap<>(); + ExtentTestActions.log(Status.INFO, String.format("Mapping the %s artifact parameters ...", artifactName)); + envFilesListupdated.put(artifactName,ArtifactBusinessLogic.extractHeatWithParametersDefinition(deploymentArtifacts)); + List heatEnvUpdatedParameters=envFilesListupdated.get(artifactName); + DeploymentArtifactPage. clickDownloadEnvArtifact(artifactName); + + Map mapExpectedProperties = new HashMap<>(); + for (HeatParameterDataDefinition param : heatEnvUpdatedParameters.get(i).getHeatParameterDefinition()) { + mapExpectedProperties.put(param.getName(), ArtifactUIUtils.getValue(param)); + } + ArtifactUIUtils.compareYamlParametersByPattern(mapExpectedProperties, FileHandling.getLastModifiedFileFromDir(downloadDirPath), PARAMETERS); + } + } + } + + + @Test + public void checkDefaultCreatedEnvArtifacts() throws Exception{ + String vnfFile = "2016-017_vixia_ixla_30_1607_e2e.zip"; + Pair> vsp = OnboardingUtils.onboardAndValidate(vnfsRepositoryPath, vnfFile, getUser()); + String vspName = vsp.left; + Map generatedEnvFileList = ArtifactBusinessLogic.createEnvFilesListFromCsar(vspName, filePath); + HomeUtils.findComponentAndClick(vspName); + GeneralUIUtils.moveToStep(StepsEnum.DEPLOYMENT_ARTIFACT); + for(Entry envFileEntry : generatedEnvFileList.entrySet()){ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT_ENV.getValue()+envFileEntry.getKey()); + ArtifactUIUtils.compareYamlFilesByPattern(envFileEntry.getValue(), FileHandling.getLastModifiedFileFromDir(), PARAMETERS); + ArtifactUIUtils.validateArtifactVersionByTypeAndLabel(envFileEntry.getKey(), "0", ArtifactTypeEnum.HEAT_ENV); + ArtifactUIUtils.validateArtifactVersionByTypeAndLabel(envFileEntry.getKey(), "1", ArtifactTypeEnum.HEAT); + } + } + +// ------------------------------------------------------------------------------- + @Test(dataProvider = "heatEnvAndVersion") + public void checkDefaultCreatedEnvArtifactsAfterVspUpdate(String vnfFile, String updatedVnfFile, String expectedHeatVersion, String expectedHeatEnvVersion) throws Throwable{ + String stringForLog = String.format("%s:%s:%s:%s", vnfFile, updatedVnfFile, expectedHeatVersion, expectedHeatEnvVersion); + setLog(stringForLog); + + Pair> vsp = OnboardingUtils.onboardAndValidate(vnfsRepositoryPath, vnfFile, getUser()); + String vspName = vsp.left; + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtonsFromInsideFrame.HOME_BUTTON.getValue()).click(); + OnboardingUtils.updateVnfAndValidate(updatedVnfsRepositoryPath, vsp, updatedVnfFile, getUser()); + Map generatedUpdatedEnvFileList = ArtifactBusinessLogic.createEnvFilesListFromCsar(vspName, filePath); + HomeUtils.findComponentAndClick(vspName); + GeneralUIUtils.moveToStep(StepsEnum.DEPLOYMENT_ARTIFACT); + for(Entry envFileEntry : generatedUpdatedEnvFileList.entrySet()){ +// TODO test will pass on case all objects on deployment view are visible + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT_ENV.getValue()+envFileEntry.getKey()); + ArtifactUIUtils.compareYamlFilesByPattern(envFileEntry.getValue(), FileHandling.getLastModifiedFileFromDir(), PARAMETERS); + ArtifactUIUtils.validateArtifactVersionByTypeAndLabel(envFileEntry.getKey(), expectedHeatEnvVersion, ArtifactTypeEnum.HEAT_ENV); + ArtifactUIUtils.validateArtifactVersionByTypeAndLabel(envFileEntry.getKey(), expectedHeatVersion, ArtifactTypeEnum.HEAT); + } + } + +// expected heat version 1 and heatEnv 2 + @Test + public void checkDefaultCreatedEnvArtifactsVspUpdatedWithSameVspTwice() throws Throwable{ + String vnfFile = "2016-044_vfw_fcgi_30_1607_e2e.zip"; + String updatedVnfFile = "2016-044_vfw_fcgi_30_1607_e2e.zip"; + Pair> vsp = OnboardingUtils.onboardAndValidate(vnfsRepositoryPath, vnfFile, getUser()); + String vspName = vsp.left; + + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtonsFromInsideFrame.HOME_BUTTON.getValue()).click(); + OnboardingUtils.updateVnfAndValidate(vnfsRepositoryPath, vsp, updatedVnfFile, getUser()); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtonsFromInsideFrame.HOME_BUTTON.getValue()).click(); + OnboardingUtils.updateVnfAndValidate(vnfsRepositoryPath, vsp, updatedVnfFile, getUser()); + Map generatedUpdatedSecondTimeEnvFileList = ArtifactBusinessLogic.createEnvFilesListFromCsar(vspName, filePath); + HomeUtils.findComponentAndClick(vspName); + GeneralUIUtils.moveToStep(StepsEnum.DEPLOYMENT_ARTIFACT); + for(Entry envFileEntry : generatedUpdatedSecondTimeEnvFileList.entrySet()){ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT_ENV.getValue()+envFileEntry.getKey()); + ArtifactUIUtils.compareYamlFilesByPattern(envFileEntry.getValue(), FileHandling.getLastModifiedFileFromDir(), PARAMETERS); + ArtifactUIUtils.validateArtifactVersionByTypeAndLabel(envFileEntry.getKey(), "2", ArtifactTypeEnum.HEAT_ENV); + ArtifactUIUtils.validateArtifactVersionByTypeAndLabel(envFileEntry.getKey(), "1", ArtifactTypeEnum.HEAT); + } + } + + + public void downloadFile(Entry envFileEntry) { + int fileCountBefore = FileHandling.getFileCountFromDefaulDownloadDirectory(); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT_ENV.getValue()+envFileEntry.getKey()); + int fileCountAfter = FileHandling.getFileCountFromDefaulDownloadDirectory(); + assertTrue("Downloaded file is missing", (fileCountAfter - fileCountBefore) == 1 ); + } + + public static void fillHeatEnvParametersInUi(Map data,List listToSearchEnvParametersInUI) { + ExtentTestActions.log(Status.INFO, String.format("Going to search parameters in UI and insert new current value to each parameter in UI...")); + + for (HeatParameterDataDefinition paramDefinition : listToSearchEnvParametersInUI){ + DeploymentArtifactPage.searchBoxEnv(paramDefinition.getName()); + WebElement currenValueField=GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.EnvParameterView.ENV_CURRENT_VALUE.getValue()+paramDefinition.getName()); + currenValueField.clear(); + currenValueField.sendKeys(data.get(paramDefinition.getName()).toString()); + GeneralUIUtils.ultimateWait(); + DeploymentArtifactPage.clearSearchBoxEnv(); + } + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VfDeploymentInformationalArtifacts.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VfDeploymentInformationalArtifacts.java new file mode 100644 index 0000000000..42c43f3ac8 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/sanity/VfDeploymentInformationalArtifacts.java @@ -0,0 +1,862 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.sanity; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.Dashboard; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.ArtifactUIUtils; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openqa.selenium.WebElement; +import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.Test; + + +public class VfDeploymentInformationalArtifacts extends SetupCDTest { + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // START US824719 + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // US824719 - Import VSP - VF informational artifacts + // TC1434241 - Import VF Artifacts - Deployment Artifacts - One Artifact, One Type + @Test + public void importVfArtifactsDeploymentArtifactsOneArtifactOneType() throws Exception { + String fileName = "TC1434241.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "heatartifactname1.yaml", null, "heatartifactname1", ArtifactTypeEnum.HEAT.getType(), "1")); + + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + } + + // US824719 - Import VSP - VF informational artifacts + // TC1434245 - Import VF Artifacts - Deployment Artifacts - Multiple Artifacts, Multiple Types + @Test + public void importVfArtifactsDeploymentArtifactsMultipleArtifactsMultipleTypes() throws Exception { + String fileName = "TC1434245.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "heatartifactname1.yaml", null, "heatartifactname1", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "heatartifactname2.yaml", null, "heatartifactname2", ArtifactTypeEnum.HEAT.getType(), "1")); + + deploymentArtifacts.add(new ArtifactInfo(null, "HeatVolArtifactName1.yaml", null, "HeatVolArtifactName1", ArtifactTypeEnum.HEAT_VOL.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "HeatVolArtifactName2.yaml", null, "HeatVolArtifactName2", ArtifactTypeEnum.HEAT_VOL.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "HeatVolArtifactName3.yaml", null, "HeatVolArtifactName3", ArtifactTypeEnum.HEAT_VOL.getType(), "1")); + + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName,folder, deploymentArtifacts, null); + } + + // US824719 - Import VSP - VF informational artifacts + // TC1434247 - Import VF Artifacts - Informational Artifacts - One Artifact, One Type + @Test + public void importVfArtifactsInformationalArtifactsOneArtifactOneType() throws Exception { + String fileName = "TC1434247.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + List informationalArtifacts = new ArrayList(); + informationalArtifacts.add(new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, informationalArtifacts); + } + + // US824719 - Import VSP - VF informational artifacts + // TC1434248 - Import VF Artifacts - Informational Artifacts - Multiple Artifacts, Multiple Types + @Test + public void importVfArtifactsInformationalArtifactsMultipleArtifactsMultipleTypes() throws Exception { + String fileName = "TC1434248.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + List informationalArtifacts = new ArrayList(); + informationalArtifacts.add(new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1")); + informationalArtifacts.add(new ArtifactInfo(null, "GuideInfoArtifact1.yml", null, "GuideInfoArtifact1", ArtifactTypeEnum.GUIDE.getType(), "1")); + informationalArtifacts.add(new ArtifactInfo(null, "GuideInfoArtifact2.yml", null, "GuideInfoArtifact2", ArtifactTypeEnum.GUIDE.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, informationalArtifacts); + } + + // US824719 - Import VSP - VF informational artifacts + // TC1434249 - Import VF Artifacts - Deployment and Informational Artifacts - Multiple Artifacts, Multiple Types + @Test + public void importVfArtifactsDeploymentAndInformationalArtifactsMultipleArtifactsMultipleTypes() throws Exception { + String fileName = "TC1434249.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "heatartifactname1.yaml", null, "heatartifactname1", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "heatartifactname2.yaml", null, "heatartifactname2", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "HeatVolArtifactName1.yaml", null, "HeatVolArtifactName1", ArtifactTypeEnum.HEAT_VOL.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "HeatVolArtifactName2.yaml", null, "HeatVolArtifactName2", ArtifactTypeEnum.HEAT_VOL.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "HeatVolArtifactName3.yaml", null, "HeatVolArtifactName3", ArtifactTypeEnum.HEAT_VOL.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + List informationalArtifacts = new ArrayList(); + informationalArtifacts.add(new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1")); + informationalArtifacts.add(new ArtifactInfo(null, "GuideInfoArtifact1.yml", null, "GuideInfoArtifact1", ArtifactTypeEnum.GUIDE.getType(), "1")); + informationalArtifacts.add(new ArtifactInfo(null, "GuideInfoArtifact2.yml", null, "GuideInfoArtifact2", ArtifactTypeEnum.GUIDE.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, informationalArtifacts); + } + + // TODO: there is defect in flow: "Updated button enabled for artifact in invalid type folder" + // TODO: re-check it after defect fix + // US824719 - Import VSP - VF informational artifacts + // TC1438310 - Import VF Artifacts - Deployment Artifacts - Artifact Type Invalid + @Test + public void importVFArtifactsDeploymentArtifactsArtifactTypeInvalid() throws Exception { + String fileName = "DeploymentArtifactWithInvalidType.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "ArtifactName.yaml", null, "ArtifactName", ArtifactTypeEnum.OTHER.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + } + + // US824719 - Import VSP - VF informational artifacts + // TC1438311 - Import VF Artifacts - Informational Artifacts - Artifact Type Invalid + @Test + public void importVfArtifactsInformationalArtifactsArtifactTypeInvalid() throws Exception { + String fileName = "InformationArtifactWithInvalidType.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + List informationalArtifacts = new ArrayList(); + informationalArtifacts.add(new ArtifactInfo(null, "ArtifactName.yaml", null, "ArtifactName", ArtifactTypeEnum.OTHER.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, informationalArtifacts); + } + + // US824719 - Import VSP - VF informational artifacts + // TC1438231 - Import VF Artifacts - Deployment Artifacts - Artifact Name To Long + @Test + public void importVfArtifactsDeploymentArtifactsArtifactNameToLong() throws Exception { + String folder = "US825779"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + String fileName = "DeploymentArtifactWithLongName.csar"; + + importVfFromCsar(resourceMetaData, folder, fileName, getUser()); + + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.EXCEEDS_LIMIT.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + + // US824719 - Import VSP - VF informational artifacts + // TC1438232 - Import VF Artifacts - Informational Artifacts - Artifact Name To Long + // TODO: make informational artifact name longer then 255 + // TODO: windows/linux not allowed it + @Test(enabled=false) + public void importVfArtifactsInformationalArtifactsArtifactNameToLong() throws Exception { + String folder ="US825779"; + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + + String fileName = "InformationArtifactWithLongName.csar"; + + importVfFromCsar(resourceMetaData, folder, fileName, getUser()); + + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.EXCEEDS_LIMIT.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // END US824719 + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // START US825779 + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1443736 - Update With One New Deployment Artifact + @Test + public void updateWithOneNewDeploymentArtifact() throws Exception { + String fileName = "ImportTC1443736.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1443736.csar"; + deploymentArtifacts.add(new ArtifactInfo(null, "artifactname1.yaml", null, "artifactname1", ArtifactTypeEnum.HEAT.getType(), "1")); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, deploymentArtifacts, null, null, null); + } + + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1443737 - Update With One Removed Deployment Artifact + @Test + public void updateWithOneRemovedDeploymentArtifact() throws Exception { + String fileName = "ImportTC1443737.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + ArtifactInfo artifactInfo = new ArtifactInfo(null, "artifactname1.yaml", null, "artifactname1", ArtifactTypeEnum.HEAT.getType(), "1"); + deploymentArtifacts.add(artifactInfo); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1443737.csar"; + deploymentArtifacts.remove(artifactInfo); + + List deploymentArtifactsNotExist = new ArrayList(); + deploymentArtifactsNotExist.add(artifactInfo); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, deploymentArtifacts, null, deploymentArtifactsNotExist, null); + } + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1443738 - Update With One New Version Deployment Artifact + @Test + public void updateWithOneNewVersionDeploymentArtifact() throws Exception { + String fileName = "ImportTC1443738.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + ArtifactInfo artifactInfo = new ArtifactInfo(null, "artifactname1.yaml", null, "artifactname1", ArtifactTypeEnum.HEAT.getType(), "1"); + deploymentArtifacts.add(artifactInfo); + + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1443738.csar"; + artifactInfo.setArtifactVersion("2"); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, deploymentArtifacts, null, null, null); + } + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1443887 - Update With One New Informational Artifact + @Test + public void updateWithOneNewInformationalArtifact() throws Exception { + String fileName = "ImportTC1443887.csar"; + String folder ="US825779"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1443887.csar"; + + List informationalArtifacts = new ArrayList(); + informationalArtifacts.add(new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1")); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, deploymentArtifacts, informationalArtifacts, null, null); + } + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1443888 - Update With One Removed Informational Artifact + @Test + public void updateWithOneRemovedInformationalArtifact() throws Exception { + String folder ="US825779"; + String fileName = "ImportTC1443888.csar"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + List informationalArtifacts = new ArrayList(); + ArtifactInfo artifactInfo = new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1"); + informationalArtifacts.add(artifactInfo); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, informationalArtifacts); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1443888.csar"; + + informationalArtifacts.remove(artifactInfo); + + List informationalArtifactNotExist = new ArrayList(); + informationalArtifactNotExist.add(artifactInfo); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, deploymentArtifacts, informationalArtifacts, null, informationalArtifactNotExist); + } + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1443890 - Update With One New Artifact Version Informational Artifact + @Test + public void updateWithOneNewArtifactVersionInformationalArtifact() throws Exception { + String folder ="US825779"; + String fileName = "ImportTC1443890.csar"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + List informationalArtifacts = new ArrayList(); + ArtifactInfo artifactInfo = new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1"); + informationalArtifacts.add(artifactInfo); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, informationalArtifacts); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1443890.csar"; + artifactInfo.setArtifactVersion("2"); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, deploymentArtifacts, informationalArtifacts, null, null); + } + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1443893 - Update CSAR With Same Artifacts As Imported + @Test + public void updateCSARWithSameArtifactsAsImported() throws Exception { + String folder ="US825779"; + String fileName = "ImportUpdateTC1443893.csar"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "heatartifactname1.yaml", null, "heatartifactname1", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "heatartifactname2.yaml", null, "heatartifactname2", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "HeatVolArtifactName1.yaml", null, "HeatVolArtifactName1", ArtifactTypeEnum.HEAT_VOL.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "HeatVolArtifactName2.yaml", null, "HeatVolArtifactName2", ArtifactTypeEnum.HEAT_VOL.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "HeatVolArtifactName3.yaml", null, "HeatVolArtifactName3", ArtifactTypeEnum.HEAT_VOL.getType(), "1")); + + List informationalArtifacts = new ArrayList(); + informationalArtifacts.add(new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1")); + informationalArtifacts.add(new ArtifactInfo(null, "GuideInfoArtifact1.yml", null, "GuideInfoArtifact1", ArtifactTypeEnum.GUIDE.getType(), "1")); + informationalArtifacts.add(new ArtifactInfo(null, "GuideInfoArtifact2.yml", null, "GuideInfoArtifact2", ArtifactTypeEnum.GUIDE.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, informationalArtifacts); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "ImportUpdateTC1443893.csar"; + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, deploymentArtifacts, informationalArtifacts, null, null); + } + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1443954 - Update With Multiple Changes In Deployment And Informational Artifacts + @Test + public void updateWithMultipleChangesInDeploymentAndInformationalArtifacts() throws Exception { + String folder ="US825779"; + String fileName = "ImportTC1443954.csar"; + + ArtifactInfo deploymentHeat1 = new ArtifactInfo(null, "heatartifactname1.yaml", null, "heatartifactname1", ArtifactTypeEnum.HEAT.getType(), "1"); + ArtifactInfo deploymentHeat2 = new ArtifactInfo(null, "heatartifactname2.yaml", null, "heatartifactname2", ArtifactTypeEnum.HEAT.getType(), "1"); + ArtifactInfo deploymentHeat3 = new ArtifactInfo(null, "heatartifactname3.yaml", null, "heatartifactname3", ArtifactTypeEnum.HEAT.getType(), "1"); + + ArtifactInfo deploymentHeatVol1 = new ArtifactInfo(null, "HeatVolArtifactName1.yaml", null, "HeatVolArtifactName1", ArtifactTypeEnum.HEAT_VOL.getType(), "1"); + ArtifactInfo deploymentHeatVol2 = new ArtifactInfo(null, "HeatVolArtifactName2.yaml", null, "HeatVolArtifactName2", ArtifactTypeEnum.HEAT_VOL.getType(), "1"); + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(deploymentHeat1); + deploymentArtifacts.add(deploymentHeat2); + deploymentArtifacts.add(deploymentHeat3); + deploymentArtifacts.add(deploymentHeatVol1); + deploymentArtifacts.add(deploymentHeatVol2); + + ArtifactInfo infoGuide1 = new ArtifactInfo(null, "GuideInfoArtifact1.yml", null, "GuideInfoArtifact1", ArtifactTypeEnum.GUIDE.getType(), "1"); + ArtifactInfo infoGuide2 = new ArtifactInfo(null, "GuideInfoArtifact2.yml", null, "GuideInfoArtifact2", ArtifactTypeEnum.GUIDE.getType(), "1"); + + ArtifactInfo infoOther1 = new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1"); + ArtifactInfo infoOther2 = new ArtifactInfo(null, "artifactname2.txt", null, "artifactname2", ArtifactTypeEnum.OTHER.getType(), "1"); + ArtifactInfo infoOther3 = new ArtifactInfo(null, "artifactname3.txt", null, "artifactname3", ArtifactTypeEnum.OTHER.getType(), "1"); + + List informationalArtifacts = new ArrayList(); + informationalArtifacts.add(infoGuide1); + informationalArtifacts.add(infoGuide2); + informationalArtifacts.add(infoOther1); + informationalArtifacts.add(infoOther2); + informationalArtifacts.add(infoOther3); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, informationalArtifacts); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1443954.csar"; + + List informationalArtifactsNotExist = new ArrayList(); + List deploymentArtifactsNotExist = new ArrayList(); + + // Changes in deployment artifacts + deploymentArtifactsNotExist.add(deploymentHeat1); + deploymentArtifactsNotExist.add(deploymentHeat2); + deploymentArtifacts.remove(deploymentHeat1); + deploymentArtifacts.remove(deploymentHeat2); + deploymentArtifacts.add(new ArtifactInfo(null, "heatartifactname4.yaml", null, "heatartifactname4", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "heatartifactname5.yaml", null, "heatartifactname5", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentHeatVol1.setArtifactVersion("2"); + deploymentHeatVol2.setArtifactVersion("2"); + + // Changes in informational artifacts + infoGuide1.setArtifactVersion("2"); + infoOther1.setArtifactVersion("2"); + informationalArtifactsNotExist.add(infoGuide2); + informationalArtifactsNotExist.add(infoOther2); + informationalArtifacts.remove(infoGuide2); + informationalArtifacts.remove(infoOther2); + informationalArtifacts.add(new ArtifactInfo(null, "GuideInfoArtifact3.yml", null, "GuideInfoArtifact3", ArtifactTypeEnum.GUIDE.getType(), "1")); + informationalArtifacts.add(new ArtifactInfo(null, "artifactname4.txt", null, "artifactname4", ArtifactTypeEnum.OTHER.getType(), "1")); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, deploymentArtifacts, informationalArtifacts, deploymentArtifactsNotExist, informationalArtifactsNotExist); + } + + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1444206 - Update With Existed Deployment Artifact By Artifact With Different Type + @Test + public void updateWithExistedDeploymentArtifactByArtifactWithDifferentType() throws Exception { + String folder ="US825779"; + String fileName = "ImportTC1444206.csar"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "artifactname1.yaml", null, "artifactname1", ArtifactTypeEnum.HEAT.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1444206.csar"; + String filePath = FileHandling.getFilePath(folder); ; + + ResourceUIUtils.updateVfWithCsar(filePath, fileName); + + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.ARTIFACT_ALRADY_EXIST_IN_DIFFERENT_TYPE_IN_CSAR.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1444207 - Update With Existed Informational Artifact By Artifact With Different Type + @Test + public void updateWithExistedInformationalArtifactByArtifactWithDifferentType() throws Exception { + String folder ="US825779"; + String fileName = "ImportTC1444207.csar"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + List informationalArtifacts = new ArrayList(); + informationalArtifacts.add(new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, informationalArtifacts); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1444207.csar"; + String filePath = FileHandling.getFilePath(folder); ; + + ResourceUIUtils.updateVfWithCsar(filePath, fileName); + + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.ARTIFACT_ALRADY_EXIST_IN_DIFFERENT_TYPE_IN_CSAR.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1444208 - Update With Existed Informational Artifact By Deployment Artifact With Different Type + @Test + public void updateWithExistedInformationalArtifactByDeploymentArtifactWithDifferentType() throws Exception { + String folder ="US825779"; + String fileName = "ImportTC1444208.csar"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "artifactname1.yaml", null, "artifactname1", ArtifactTypeEnum.HEAT.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1444208.csar"; + String filePath = FileHandling.getFilePath(folder); ; + + ResourceUIUtils.updateVfWithCsar(filePath, fileName); + + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.ARTIFACT_ALRADY_EXIST_IN_DIFFERENT_TYPE_IN_CSAR.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1444520 - Update Deployment Artifact With Name To Long + @Test + public void updateDeploymentArtifactWithNameToLong() throws Exception { + String folder ="US825779"; + + String fileName = "ImportTC1444520.csar"; + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, null, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1444520.csar"; + String filePath = FileHandling.getFilePath(folder); ; + + ResourceUIUtils.updateVfWithCsar(filePath, fileName); + + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.EXCEEDS_LIMIT.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1444521 - Update Informational Artifact With Name To Long + @Test + public void updateInformationalArtifactWithNameToLong() throws Exception { + + String folder = "US825779"; + String fileName = "ImportTC1444521.csar"; + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, null, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1444521.csar"; + String filePath = FileHandling.getFilePath(folder); ; + + ResourceUIUtils.updateVfWithCsar(filePath, fileName); + + String errorMessage = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + String checkUIResponseOnError = ErrorValidationUtils.checkUIResponseOnError(ActionStatus.EXCEEDS_LIMIT.name()); + Assert.assertTrue(errorMessage.contains(checkUIResponseOnError)); + } + + // TODO: only after below TODO's it complete test + // TODO: verify that if delete/edit button need to be disabled then check that there is no such buttons + // TODO: in composition & artifact pages + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1444530 - Update Deployment Artifact With Invalid Type + @Test + public void updateDeploymentArtifactWithInvalidType() throws Exception { + String folder ="US825779"; + String fileName = "ImportTC1444530.csar"; + + List deploymentArtifacts = new ArrayList(); + + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1444530.csar"; + deploymentArtifacts.add(new ArtifactInfo(null, "artifactname1.yaml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1")); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, deploymentArtifacts, null, null, null); + } + + + // US825779 - Story: [BE] Import VSP - VF informational artifacts - Update + // TC1444531 - Update Informational Artifact With Invalid Type + @Test + public void updateInformationalArtifactWithInvalidType() throws Exception { + String folder ="US825779"; + String fileName = "ImportTC1444531.csar"; + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, null, null); + + GeneralUIUtils.clickOnElementByTestId("breadcrumbs-button-1"); + + fileName = "UpdateTC1444531.csar"; + + List informationalArtifacts = new ArrayList(); + informationalArtifacts.add(new ArtifactInfo(null, "artifactname1.xml", null, "artifactname1", ArtifactTypeEnum.OTHER.getType(), "1")); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, fileName, null, informationalArtifacts, null, null); + } + + + @Test + public void importValidInformationalArtifactInInvalidFolerTest_TC1438313() throws Exception{ + String fileName = "ValidArtifactNameInInvalidFolder.csar"; + String folder = "US824719"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(fileName, folder, deploymentArtifacts, null); + } + + @Test + public void updateValidInformationalArtifactInInvalidFolerTest_TC1444533() throws Exception{ + String fileName = "ImportTC1444533.csar"; + String folder = "US824719"; + String filePath = FileHandling.getFilePath(folder); + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName, getUser()); + + String updatedCsarFileName = "UpdateTC1444533.csar"; + + List deploymentArtifacts = new ArrayList(); + deploymentArtifacts.add(new ArtifactInfo(null, "base_ldsa.yaml", null, "base_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + deploymentArtifacts.add(new ArtifactInfo(null, "module_1_ldsa.yaml", null, "module_1_ldsa", ArtifactTypeEnum.HEAT.getType(), "1")); + + updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(folder, updatedCsarFileName, deploymentArtifacts, null, null, null); + } + + + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // END US825779 + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + public void updateVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(String folder, String fileName, + List deploymentArtifacts, List informationalArtifacts, + List deploymentArtifactsNotExist, List informationalArtifactsNotExist) throws Exception { + String filePath = FileHandling.getFilePath(folder); + ResourceUIUtils.updateVfWithCsar(filePath, fileName); + + validateDeploymentArtifactPage(deploymentArtifacts, null); + validateInformationalArtifactPage(informationalArtifacts, null); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + validateDeploymentArtifactInComposition(deploymentArtifacts, null); + validateInformationalArtifactInComposition(informationalArtifacts, null); + + } + + + public void importVfFromCsar(ResourceReqDetails resourceMetaData, String folder, String fileName, User user) { + String filePath = FileHandling.getFilePath(folder); + GeneralUIUtils.hoverOnAreaByTestId(Dashboard.IMPORT_AREA.getValue()); + // Insert file to the browse dialog + WebElement browseWebElement = GeneralUIUtils.getInputElement(DataTestIdEnum.Dashboard.IMPORT_VF_FILE.getValue()); + browseWebElement.sendKeys(filePath + fileName); + + // Fill the general page fields. + GeneralUIUtils.waitForLoader(); + ResourceUIUtils.fillResourceGeneralInformationPage(resourceMetaData, getUser(), true); + GeneralUIUtils.clickOnAreaJS(DataTestIdEnum.GeneralElementsEnum.CREATE_BUTTON.getValue()); + } + + + + + public void importVfAndValidateInformationalDeploymentArtifactPagesOnPagesAndComposition(String fileName, String folder, List deploymentArtifacts, List informationalArtifacts) throws Exception { + String filePath = FileHandling.getFilePath(folder); + ResourceReqDetails resourceMetaData = ElementFactory.getDefaultResourceByType(ResourceTypeEnum.VF, getUser()); + ResourceUIUtils.importVfFromCsar(resourceMetaData, filePath, fileName, getUser()); + + validateDeploymentArtifactPage(deploymentArtifacts, null); + validateInformationalArtifactPage(informationalArtifacts, null); + + ResourceGeneralPage.getLeftMenu().moveToCompositionScreen(); + + validateDeploymentArtifactInComposition(deploymentArtifacts, null); + validateInformationalArtifactInComposition(informationalArtifacts, null); + } + + public void validateInformationalArtifactInComposition(List informationalArtifacts, List informationalArtifactsNotExist) throws Exception { + CompositionPage.showInformationArtifactTab(); + // Composition informational + if(informationalArtifacts != null && informationalArtifacts.size() > 0) { + validateEachArtifactOnCompositionRightMenuInformationPage(informationalArtifacts); + } + if(informationalArtifactsNotExist != null && informationalArtifactsNotExist.size() > 0) { + validateEachArtifactNotExistOnCompositionRightMenuInformationPage(informationalArtifactsNotExist); + } + } + + public void validateDeploymentArtifactInComposition(List deploymentArtifacts, List deploymentArtifactsNotExist) throws Exception { + CompositionPage.showDeploymentArtifactTab(); + // Composition deployment + if(deploymentArtifacts != null && deploymentArtifacts.size() > 0) { + validateEachArtifactOnCompositionRightMenuDeploymentPage(deploymentArtifacts); + } + if(deploymentArtifactsNotExist != null && deploymentArtifactsNotExist.size() > 0) { + validateEachArtifactNotExistOnCompositionRightMenuDeploymentPage(deploymentArtifactsNotExist); + } + } + + public void validateInformationalArtifactPage(List informationalArtifacts, List informationalArtifactsNotExist) { + ResourceGeneralPage.getLeftMenu().moveToInformationalArtifactScreen(); + // Informational page + if(informationalArtifacts != null && informationalArtifacts.size() > 0) { + validateEachArtifactInformationPage(informationalArtifacts); + } + if(informationalArtifactsNotExist != null && informationalArtifactsNotExist.size() > 0) { + validateEachArtifactNotExistInformationPage(informationalArtifactsNotExist); + } + } + + public void validateDeploymentArtifactPage(List deploymentArtifacts, List deploymentArtifactsNotExist) { + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + // Deployment page + if(deploymentArtifacts != null && deploymentArtifacts.size() > 0) { + validateEachArtifactOnDeploymentPage(deploymentArtifacts); + } + if(deploymentArtifactsNotExist != null && deploymentArtifactsNotExist.size() > 0) { + validateEachArtifactNotExistOnDeploymentPage(deploymentArtifactsNotExist); + } + } + + // TODO: add validation that if not editable / deleteable then button should not appear + public void validateEachArtifactOnDeploymentPage(List artifactInfoList) { + for(ArtifactInfo artifact: artifactInfoList) { + String type = artifact.getArtifactType(); + String label = artifact.getArtifactLabel(); + String version = artifact.getArtifactVersion(); + + if (type.equals(ArtifactTypeEnum.HEAT.getType()) || type.equals(ArtifactTypeEnum.HEAT_VOL.getType()) || type.equals(ArtifactTypeEnum.HEAT_NET.getType())){ + ArtifactUIUtils.validateExistArtifactOnDeploymentInformationPage(label, null, version, type, true, false, false, true); + } + else{ + ArtifactUIUtils.validateExistArtifactOnDeploymentInformationPage(label, null, version, type, true, true, true, false); + } + } + } + + public void validateEachArtifactNotExistOnDeploymentPage(List artifactInfoList) { + for(ArtifactInfo artifact: artifactInfoList) { + ArtifactUIUtils.validateNotExistArtifactOnDeploymentInformationPage(artifact.getArtifactLabel()); + } + } + + public void validateEachArtifactInformationPage(List artifactInfoList) { + for(ArtifactInfo artifact: artifactInfoList) { + ArtifactUIUtils.validateExistArtifactOnDeploymentInformationPage(artifact.getArtifactLabel(), null, artifact.getArtifactVersion(), artifact.getArtifactType(), true, true, true, false); + } + } + + public void validateEachArtifactNotExistInformationPage(List artifactInfoList) { + for(ArtifactInfo artifact: artifactInfoList) { + ArtifactUIUtils.validateNotExistArtifactOnDeploymentInformationPage(artifact.getArtifactLabel()); + } + } + + public void validateEachArtifactOnCompositionRightMenuDeploymentPage(List artifactInfoList) { + for(ArtifactInfo artifact: artifactInfoList) { + + String type = artifact.getArtifactType(); + String label = artifact.getArtifactLabel(); + String filename = artifact.getFilename(); + + if (type.equals(ArtifactTypeEnum.HEAT.getType()) || type.equals(ArtifactTypeEnum.HEAT_VOL.getType()) || type.equals(ArtifactTypeEnum.HEAT_NET.getType())){ + ArtifactUIUtils.validateExistArtifactOnCompositionRightMenuDeploymentInformationPage(filename, label, false, true, true, false); + } + else{ + ArtifactUIUtils.validateExistArtifactOnCompositionRightMenuDeploymentInformationPage(filename, label, true, false, true, true); + } + } + } + + public void validateEachArtifactNotExistOnCompositionRightMenuDeploymentPage(List artifactInfoList) { + for(ArtifactInfo artifact: artifactInfoList) { + ArtifactUIUtils.validateNotExistArtifactOnCompositionRightMenuDeploymentInformationPage(artifact.getArtifactLabel()); + } + } + + // TODO: there is defect in this flow + // TODO: change isEditable to false when defect fix + public void validateEachArtifactOnCompositionRightMenuInformationPage(List artifactInfoList) { + for(ArtifactInfo artifact: artifactInfoList) { + ArtifactUIUtils.validateExistArtifactOnCompositionRightMenuDeploymentInformationPage(artifact.getFilename(), artifact.getArtifactLabel(), true, false, true, true); + } + } + + public void validateEachArtifactNotExistOnCompositionRightMenuInformationPage(List artifactInfoList) { + for(ArtifactInfo artifact: artifactInfoList) { + ArtifactUIUtils.validateNotExistArtifactOnCompositionRightMenuDeploymentInformationPage(artifact.getArtifactLabel()); + } + } + + + + @Override + protected UserRoleEnum getRole() { + return UserRoleEnum.DESIGNER; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ArtifactsCorrelationManager.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ArtifactsCorrelationManager.java new file mode 100644 index 0000000000..7f67978aea --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ArtifactsCorrelationManager.java @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map.Entry; +import java.util.Set; + +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; + +public class ArtifactsCorrelationManager { + + private static HashMap> vNFArtifactsCorrelationMap = new HashMap>(); + private static HashMap>> serviceVNFCorrelationMap = new HashMap>>(); + + public static void addVNFartifactDetails(String vspName, + LinkedList deploymentArtifacts) { + + vNFArtifactsCorrelationMap.put(vspName, deploymentArtifacts); + + + } + + public static Entry> getVNFartifactDetails(String vnfName){ + + + Set>> entrySet = vNFArtifactsCorrelationMap.entrySet(); + for (Entry> entry : entrySet) { + String key = entry.getKey(); + if (key.equals(vnfName)) { + return entry; + } + + } + return null; + + } + + + public static void addVNFtoServiceArtifactCorrelation(String service, String vnfName){ + + serviceVNFCorrelationMap.put(service, getVNFartifactDetails(vnfName)); + + } + + public static Set>>> getServiceArtifactCorrelationMap(String service){ + + return serviceVNFCorrelationMap.entrySet(); + + } + +} + diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/AttFtpClient.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/AttFtpClient.java new file mode 100644 index 0000000000..1d7c4ae554 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/AttFtpClient.java @@ -0,0 +1,221 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.commons.net.ftp.FTP; +import org.apache.commons.net.ftp.FTPClient; +import org.apache.commons.net.ftp.FTPFile; +import org.apache.commons.net.ftp.FTPReply; + +public class AttFtpClient { + + private static final AttFtpClient instance = new AttFtpClient(); + + public static AttFtpClient getInstance() { + return instance; + } + + private FTPClient apacheFtpClient; + + private AttFtpClient() { + apacheFtpClient = new FTPClient(); + }; + + + public void init(String server, int port, String user, String pass) { + + try { + apacheFtpClient.connect(server, port); + showServerReply(apacheFtpClient); + + + int replyCode = apacheFtpClient.getReplyCode(); + if (!FTPReply.isPositiveCompletion(replyCode)) { + System.out.println("Connect failed"); + return; + } + + boolean success = apacheFtpClient.login(user, pass); + showServerReply(apacheFtpClient); + + if (!success) { + System.out.println("Could not login to the server"); + return; + } + +// else{ +// apacheFtpClient.enterLocalPassiveMode(); +// apacheFtpClient.setFileType(FTP.BINARY_FILE_TYPE); +// } + } catch (IOException ex) { + System.out.println("Oops! Something wrong happened"); + ex.printStackTrace(); + } + + } + + public File retrieveLastModifiedFileFromFTP() throws IOException { + FTPFile[] files1 = retrieveListOfFile(); + + // sort list by TimeStamp + List sorted = Arrays.asList(files1).stream() + .sorted((e1, e2) -> e1.getTimestamp().compareTo(e2.getTimestamp())).collect(Collectors.toList()); + printFileDetailsList(sorted); + + // retrieve file from FTP + FTPFile ftpFile = sorted.get(sorted.size() - 1); + + return retrieveFileFromFTP(ftpFile); + + } + + public FTPFile[] retrieveListOfFile() throws IOException { + // Lists files and directories + FTPFile[] files = apacheFtpClient.listFiles(""); + + printNames(files); + return files; + } + + public File retrieveFileFromFTP(FTPFile ftpFile) throws IOException { + + File downloadFile1 = new File("tmp"); + OutputStream outputStream1 = new BufferedOutputStream(new FileOutputStream(downloadFile1)); + boolean success = apacheFtpClient.retrieveFile(ftpFile.getName(), outputStream1); + outputStream1.close(); + + if (success) { + System.out.println("File #1 has been downloaded successfully."); + } + + + return downloadFile1; + + } + + public void deleteFilesFromFTPserver() throws IOException { + FTPFile[] files = retrieveListOfFile(); + deleteFiles(files); + } + + public void terminateClient() throws IOException { + + String status = apacheFtpClient.getStatus(); + + // logs out and disconnects from server + try { + if (apacheFtpClient.isConnected()) { + apacheFtpClient.logout(); + apacheFtpClient.disconnect(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + private void printFileDetailsList(List list) { + DateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + for (FTPFile ftpFile : list) { + + String details = ftpFile.getName(); + if (ftpFile.isDirectory()) { + details = "[" + details + "]"; + } + details += "\t\t" + ftpFile.getSize(); + details += "\t\t" + dateFormater.format(ftpFile.getTimestamp().getTime()); + + System.out.println(details); + } + } + + private void printNames(FTPFile[] files) { + if (files != null && files.length > 0) { + for (FTPFile aFile : files) { + System.out.println(aFile); + } + } + } + + private void showServerReply(FTPClient ftpClient) { + String[] replies = ftpClient.getReplyStrings(); + if (replies != null && replies.length > 0) { + for (String aReply : replies) { + System.out.println("SERVER: " + aReply); + } + } + } + + public class LastModifiedComparator implements Comparator { + + public int compare(FTPFile f1, FTPFile f2) { + return f1.getTimestamp().compareTo(f2.getTimestamp()); + } + } + + public FTPFile getMaxLastModified(FTPFile[] ftpFiles) { + return Collections.max(Arrays.asList(ftpFiles), new LastModifiedComparator()); + } + + public static void displayFiles(File[] files) { + for (File file : files) { + System.out.printf("File: %-20s Last Modified:" + new Date(file.lastModified()) + "\n", file.getName()); + } + } + + public void deleteFiles(FTPFile[] files) { + + for (FTPFile file : files) { + + boolean deleted = false; + try { + deleted = apacheFtpClient.deleteFile(file.getName()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if (deleted) { + System.out.println("The file was deleted successfully."); + } else { + System.out.println("Could not delete the  file, it may not exist."); + } + } + + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/DriverFactory.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/DriverFactory.java new file mode 100644 index 0000000000..7d0d77acfa --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/DriverFactory.java @@ -0,0 +1,125 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import org.apache.commons.io.FileUtils; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.firefox.FirefoxProfile; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeSuite; + + +public class DriverFactory { + + private static ThreadLocal driverThread; + private static List webDriverThreadPool = Collections.synchronizedList(new ArrayList()); + private static Config config; + + public DriverFactory() { + try { + config = Utils.getConfig(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + @BeforeSuite(alwaysRun = true) + public static void instantiateDriverObject() { + + + File basePath = new File(FileHandling.getBasePath()); + File[] listFiles = basePath.listFiles(new FilenameFilter() { + + @Override + public boolean accept(File basePath, String name) { + return name.startsWith(WebDriverThread.AUTOMATION_DOWNLOAD_DIR); + } + }); + Arrays.asList(listFiles).forEach(e -> FileHandling.deleteDirectory(e.getAbsolutePath())); + + + + driverThread = new ThreadLocal() { + @Override + protected WebDriverThread initialValue() { + WebDriverThread webDriverThread = new WebDriverThread(config); + webDriverThreadPool.add(webDriverThread); + return webDriverThread; + } + }; + } + + public static WebDriver getDriver() throws Exception { + return driverThread.get().getDriver(); + } + + public static FirefoxProfile getDriverFirefoxProfile() throws Exception { + return driverThread.get().getFirefoxProfile(); + } + + @AfterSuite(alwaysRun = true) + public static void quitDriverAfterSuite() throws Exception { + for (WebDriverThread webDriverThread : webDriverThreadPool) { + if (webDriverThread.getDriver() != null) + webDriverThread.quitDriver(); + } + deleteDownloadDirs(); + } + + private static void deleteDownloadDirs() throws IOException { +// System.gc(); + HashMap windowMap = WindowTestManager.getWholeMap(); + for (WindowTest win : windowMap.values()){ + String downloadDirectory = win.getDownloadDirectory(); + FileUtils.deleteDirectory(new File(downloadDirectory)); + } + } + + public static void quitDriver() throws Exception{ + driverThread.get().quitDriver(); + driverThread.remove(); + WindowTestManager.removeWindowTest(); + } + + public static Config getConfig() { + return config; + } + + public static void setConfig(Config config) { + DriverFactory.config = config; + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentManager.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentManager.java new file mode 100644 index 0000000000..09dcad7c36 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentManager.java @@ -0,0 +1,169 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.io.File; + +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.rest.AutomationUtils; +import org.testng.ITestContext; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.reporter.ExtentHtmlReporter; +import com.aventstack.extentreports.reporter.ExtentXReporter; +import com.aventstack.extentreports.reporter.configuration.Protocol; +import com.aventstack.extentreports.reporter.configuration.Theme; + +public class ExtentManager { + + private static final String VERSIONS_INFO_FILE_NAME = "versions.info"; + private static ExtentReports extent; + private static ExtentHtmlReporter htmlReporter; + private static ExtentXReporter extentxReporter; + private static final String icon = "$(document).ready(function() {" +"\n"+ + "$('.brand-logo').html('').prepend(\"\").width(\"120px\").css(\"float\",\"left\").css(\"padding-left\",\"0\");$('.report-name').css(\"font-weight\",\"bold\");"+"\n"+ +// "$('.logo-content' ).remove();"+"\n"+ +// "$('#slide-out li:first-child').on('click', function(){ $('#charts-row').hide() }) ; $('#slide-out li:last-child').on('click', function(){ $('#charts-row').show() });"+"\n"+ +// "$('.charts div:nth-child(2)').remove();"+"\n"+ + "})"; + + public enum suiteNameXml { + + TESTNG_FAILED_XML_NAME("testng-failed.xml"); + + suiteNameXml(String value) { + this.value = value; + } + + private String value; + + public String getValue() { + return value; + } + + } + + public synchronized static ExtentReports setReporter(String filePath, String htmlFile, Boolean isAppend) throws Exception { + String dbIp = DriverFactory.getConfig().getReportDBhost(); + int dbPort = DriverFactory.getConfig().getReportDBport(); + + if (extent == null) { + extentxReporter = new ExtentXReporter(dbIp, dbPort); + extent = new ExtentReports(); + initAndSetExtentHtmlReporter(filePath, htmlFile, isAppend); + + if(extentxReporter.config().getReportObjectId() != null){ + setExtentXReporter(isAppend); + }else{ + extentxReporter.stop(); + } + } + return extent; + } + + public synchronized static void setExtentXReporter(Boolean isAppend){ + extentxReporter.setAppendExisting(isAppend); + extent.attachReporter(extentxReporter); + } + + public synchronized static void initAndSetExtentHtmlReporter(String filePath, String htmlFile, Boolean isAppend) throws Exception{ + htmlReporter = new ExtentHtmlReporter(filePath + htmlFile); + setConfiguration(htmlReporter); + htmlReporter.setAppendExisting(isAppend); + extent.attachReporter(htmlReporter); + } + + public synchronized static ExtentReports getReporter() { + return extent; + } + + public static void initReporter(String filepath, String htmlFile, ITestContext context) throws Exception { + + String onboardVersion = AutomationUtils.getOnboardVersion(); + String osVersion = AutomationUtils.getOSVersion(); + Config config = Utils.getConfig(); + String envData = config.getUrl(); + String suiteName = getSuiteName(context); + + if(suiteName.equals(suiteNameXml.TESTNG_FAILED_XML_NAME.getValue())){ + if (config.getUseBrowserMobProxy()) + setTrafficCaptue(config); + + setReporter(filepath, htmlFile, true); + String suiteNameFromVersionInfoFile = FileHandling.getKeyByValueFromPropertyFormatFile(filepath + VERSIONS_INFO_FILE_NAME, "suiteName"); + reporterDataDefinition(onboardVersion, osVersion, envData, suiteNameFromVersionInfoFile); + }else{ + FileHandling.deleteDirectory(SetupCDTest.getReportFolder()); + FileHandling.createDirectory(filepath); + setReporter(filepath, htmlFile, false); + reporterDataDefinition(onboardVersion, osVersion, envData, suiteName); + AutomationUtils.createVersionsInfoFile(filepath + VERSIONS_INFO_FILE_NAME, onboardVersion, osVersion, envData, suiteName); + } + + } + + public static void reporterDataDefinition(String onboardVersion, String osVersion, String envData, String suiteNameFromVersionInfoFile) throws Exception { + extent.setSystemInfo("Onboard Version", onboardVersion); + extent.setSystemInfo("OS Version", osVersion); + extent.setSystemInfo("Host Name Address", RestCDUtils.getExecutionHostAddress()); + extent.setSystemInfo("ExecutedOn", envData); + extent.setSystemInfo("SuiteName", suiteNameFromVersionInfoFile); + } + + public static String getSuiteName(ITestContext context) { + String suitePath = context.getSuite().getXmlSuite().getFileName(); + if(suitePath != null){ + File file = new File(suitePath); + String suiteName = file.getName(); + return suiteName; + } + return null; + } + + public synchronized static ExtentHtmlReporter setConfiguration(ExtentHtmlReporter htmlReporter) throws Exception { + + htmlReporter.config().setTheme(Theme.STANDARD); + htmlReporter.config().setEncoding("UTF-8"); + htmlReporter.config().setProtocol(Protocol.HTTPS); + htmlReporter.config().setDocumentTitle("SDC Automation Report"); + htmlReporter.config().setChartVisibilityOnOpen(true); +// htmlReporter.config().setReportName(AutomationUtils.getATTVersion()); + htmlReporter.config().setReportName("SDC Automation Report"); + htmlReporter.config().setChartVisibilityOnOpen(false); + htmlReporter.config().setJS(icon); + return htmlReporter; + } + + public static void closeReporter(){ + extent.flush(); + } + + public static void setTrafficCaptue(Config config) { + boolean mobProxyStatus = config.getUseBrowserMobProxy(); + if (mobProxyStatus){ + config.setCaptureTraffic(true);; + } + } +} + diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentTestActions.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentTestActions.java new file mode 100644 index 0000000000..0523647c16 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentTestActions.java @@ -0,0 +1,114 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.io.File; +import java.io.IOException; +import java.util.UUID; + +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; + +import com.aventstack.extentreports.ExtentTest; +import com.aventstack.extentreports.MediaEntityBuilder; +import com.aventstack.extentreports.Status; +import com.aventstack.extentreports.markuputils.ExtentColor; +import com.aventstack.extentreports.markuputils.Markup; +import com.aventstack.extentreports.markuputils.MarkupHelper; + +public class ExtentTestActions { + + public static void log(Status logStatus, Markup mark){ + ExtentTest test = ExtentTestManager.getTest(); + test.log(logStatus, mark); + } + + public static void log(Status logStatus, String message){ + ExtentTest test = ExtentTestManager.getTest(); + test.log(logStatus, message); + } + + public static void log(Status logStatus, String message, String duration){ + log(logStatus, message + addDurationTag(duration)); + } + + public static void log(Status logStatus, Throwable throwabel){ + ExtentTest test = ExtentTestManager.getTest(); + test.log(logStatus, throwabel); + } + + public static void addTag(Status logStatus, String message){ + Markup m = null; + switch(logStatus){ + case PASS: + m = MarkupHelper.createLabel(message, ExtentColor.GREEN); + break; + case FAIL: + m = MarkupHelper.createLabel(message, ExtentColor.RED); + break; + case SKIP: + m = MarkupHelper.createLabel(message, ExtentColor.BLUE); + break; + case FATAL: + m = MarkupHelper.createLabel(message, ExtentColor.BROWN); + break; + default: + break; + } + + if (m != null){ + log(logStatus, m); + } + } + + public static String addScreenshot(Status logStatus, String screenshotName, String message) throws IOException{ + String imageFilePath = null; + String uuid = UUID.randomUUID().toString(); + String[] stringArray = uuid.split("-"); + screenshotName = screenshotName + "-" + stringArray[stringArray.length - 1]; + try { + File imageFile = GeneralUIUtils.takeScreenshot(screenshotName, SetupCDTest.getScreenshotFolder()); + imageFilePath = new File(SetupCDTest.getReportFolder()).toURI().relativize(imageFile.toURI()).getPath(); + } catch (IOException e) { + e.printStackTrace(); + } + + ExtentTest test = ExtentTestManager.getTest(); + test.log(logStatus, message, MediaEntityBuilder.createScreenCaptureFromPath(imageFilePath).build()); + return imageFilePath; + } + + private static String addDurationTag(String duration){ + return "" + duration + ""; + } + + public static String addLinkTag(String fileName, String pathToFile){ + return String.format("HAR file", fileName, pathToFile); + } + + public static void addFileToReportAsLink(File harFile, String pathToFileFromReportDirectory, String message) { + log(Status.INFO, message, addLinkTag(harFile.getName(), pathToFileFromReportDirectory)); + } + + + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentTestManager.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentTestManager.java new file mode 100644 index 0000000000..b5ed1ea498 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ExtentTestManager.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.util.HashMap; + +import com.aventstack.extentreports.ExtentReports; +import com.aventstack.extentreports.ExtentTest; + +public class ExtentTestManager { + + private static HashMap extentTestMap = new HashMap(); + private static ExtentReports extent = ExtentManager.getReporter(); + + public static synchronized ExtentTest getTest() { + return extentTestMap.get(Thread.currentThread().getId()); + } + + public static synchronized void endTest() { +// extent.endTest(extentTestMap.get(Thread.currentThread().getId())); + extent.flush(); + } + + public static synchronized ExtentTest startTest(String testName) { + return startTest(testName, ""); + } + + public static synchronized ExtentTest startTest(String testName, String desc) { + ExtentTest test = extent.createTest(testName, desc); + extentTestMap.put(Thread.currentThread().getId(), test); + + return test; + } + + public static synchronized void assignCategory(Class clazz){ + String[] parts = clazz.getName().split("\\."); + String lastOne1 = parts[parts.length-1]; + String lastOne2 = parts[parts.length-2]; + getTest().assignCategory(lastOne2 + "-" + lastOne1); + } +} + diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/MobProxy.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/MobProxy.java new file mode 100644 index 0000000000..78cf2709af --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/MobProxy.java @@ -0,0 +1,103 @@ +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +import org.slf4j.LoggerFactory; + +import com.aventstack.extentreports.ExtentTest; +import com.github.markusbernhardt.proxy.ProxySearch; +import com.github.markusbernhardt.proxy.ProxySearch.Strategy; +import com.github.markusbernhardt.proxy.util.PlatformUtil; +import com.github.markusbernhardt.proxy.util.PlatformUtil.Platform; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import net.lightbody.bmp.BrowserMobProxyServer; + +public class MobProxy { + + private static HashMap mobProxyServerMap = new HashMap(); + public static InetSocketAddress localProxyAddress = getProxy(); + + public static InetSocketAddress getProxy(){ + setLogger(); + + ProxySearch proxySearch = new ProxySearch(); +// proxySearch.addStrategy(Strategy.JAVA); +// proxySearch.addStrategy(Strategy.BROWSER); +// proxySearch.addStrategy(Strategy.OS_DEFAULT); +// proxySearch.addStrategy(Strategy.ENV_VAR); + if (PlatformUtil.getCurrentPlattform() == Platform.WIN) { + proxySearch.addStrategy(Strategy.IE); + proxySearch.addStrategy(Strategy.FIREFOX); + proxySearch.addStrategy(Strategy.JAVA); + } else if (PlatformUtil.getCurrentPlattform() == Platform.LINUX) { + proxySearch.addStrategy(Strategy.GNOME); + proxySearch.addStrategy(Strategy.KDE); + proxySearch.addStrategy(Strategy.FIREFOX); + proxySearch.addStrategy(Strategy.ENV_VAR); + return null; + } else { + proxySearch.addStrategy(Strategy.OS_DEFAULT); + } + ProxySelector proxySelector = proxySearch.getProxySelector(); + + ProxySelector.setDefault(proxySelector); + URI home = URI.create("http://www.google.com"); + System.out.println("ProxySelector: " + proxySelector); + System.out.println("URI: " + home); + List proxyList = proxySelector.select(home); + String host = null; + String port = null; + if (proxyList != null && !proxyList.isEmpty()) { + for (Proxy proxy : proxyList) { + System.out.println(proxy); + SocketAddress address = proxy.address(); + if (address instanceof InetSocketAddress) { + host = ((InetSocketAddress) address).getHostName(); + port = Integer.toString(((InetSocketAddress) address).getPort()); + System.setProperty("http.proxyHost", host); + System.setProperty("http.proxyPort", port); + } + } + } + InetSocketAddress address = new InetSocketAddress(host, Integer.parseInt(port)); + return address; + } + + // set logger for all classes connected to MobProxy + public static void setLogger() { + LoggerContext lc = (LoggerContext) LoggerFactory. getILoggerFactory(); +// lc.getLogger("ROOT").setLevel(Level.DEBUG); + for(Logger logger:lc.getLoggerList()){ + logger.setLevel(Level.INFO); + } + } + + public static synchronized void setProxyServer() { + BrowserMobProxyServer server = new BrowserMobProxyServer(); + server.setTrustAllServers(true); + if (localProxyAddress != null){ + server.setChainedProxy(localProxyAddress); + server.start(); + } else { + server.start(); + // filter firefox requests to mozilla when system proxy is absent + server.blacklistRequests(".*mozilla.*", 200); + } + mobProxyServerMap.put(Thread.currentThread().getId(), server); + } + + public static synchronized BrowserMobProxyServer getPoxyServer() { + return mobProxyServerMap.get(Thread.currentThread().getId()); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/OnboardCSVReport.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/OnboardCSVReport.java new file mode 100644 index 0000000000..03c9b0281f --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/OnboardCSVReport.java @@ -0,0 +1,63 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; + +public class OnboardCSVReport { + + private StringBuilder sb; + private PrintWriter pw; + + public OnboardCSVReport(String filepath, String filename) { + sb = new StringBuilder(); + try { + File csvFile = new File(filepath + filename); + pw = new PrintWriter(csvFile); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + } + + public StringBuilder appendStringToFile(String content) { + return sb.append(content + ","); + } + + public void openNewRow() { + sb.append("\n"); + } + + public void writeRow(String... content) { + for (String str : content) { + appendStringToFile(str); + } + openNewRow(); + } + + public void closeFile() { + pw.write(sb.toString()); + pw.close(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ReportAfterTestManager.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ReportAfterTestManager.java new file mode 100644 index 0000000000..ad923d5a1a --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/ReportAfterTestManager.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.io.IOException; + +import org.openecomp.sdc.ci.tests.execute.setup.ExtentManager.suiteNameXml; +import org.testng.ITestContext; +import org.testng.ITestResult; + +import com.aventstack.extentreports.Status; + +public class ReportAfterTestManager extends ExtentTestActions { + + private static String testName; + private static Throwable throwable; + private static int status; + + private static void logSuccessAfterTest(){ + final Status logStatus = Status.PASS; + addTag(logStatus, "Success"); + try{ + String message = "Finished the test with the following screenshot : "; + addScreenshotToReport(logStatus, testName, message); + }catch(Exception e){ + log(logStatus, "SUCCESS - The following exepction occured : " + e.getMessage()); + } + } + + private static void logFailAfterTest(){ + addTag(Status.FAIL, "Failure"); + try{ + log(Status.ERROR, "ERROR - The following exepction occured : "); + log(Status.ERROR, throwable); + String message = "Failure is described in the following screenshot : "; + addScreenshotToReport(Status.FAIL, testName, message); + }catch(Exception e){ + log(Status.ERROR, "ERROR - The following exepction occured : " + e.getMessage()); + } + } + + private static void logSkipAfterTest(){ + final Status logStatus = Status.SKIP; + addTag(logStatus, "Skipped"); + try{ + log(logStatus, "SKIP - The following exepction occured : "); + log(logStatus, throwable); + String message = "Skip is described in the following screenshot : "; + addScreenshotToReport(logStatus, testName, message); + }catch(Exception e){ + log(logStatus, "SKIP - The following exepction occured : " + e.getMessage()); + } + } + private static void logFatalAfterTest(){ + final Status logStatus = Status.FATAL; + addTag(logStatus, "Fatal"); + try{ + log(logStatus, "FATAL - The following exepction occured : "); + log(logStatus, throwable); + String message = "Fatal is described in the following screenshot : "; + addScreenshotToReport(logStatus, testName, message); + }catch(Exception e){ + log(logStatus, "FATAL - The following exepction occured : " + e.getMessage()); + } + } + + private static String addScreenshotToReport(Status logStatus, String testName, String message) throws IOException{ + + String addedValueFromDataProvider = WindowTestManager.getWindowMap().getAddedValueFromDataProvider(); + if (addedValueFromDataProvider != null){ + addedValueFromDataProvider = addedValueFromDataProvider.replace(":", "-"); + testName = testName + "...." + addedValueFromDataProvider; + } + + return addScreenshot(logStatus, testName, message); + } + + public static void report(ITestResult result, ITestContext context){ + + testName = result.getName(); + throwable = result.getThrowable(); + status = result.getStatus(); + + String suiteName = ExtentManager.getSuiteName(context); + + switch(status){ + case ITestResult.SUCCESS: + logSuccessAfterTest(); + break; + + case ITestResult.FAILURE: + + if (suiteName.equals(suiteNameXml.TESTNG_FAILED_XML_NAME.getValue())) { + logFatalAfterTest(); + }else{ + logFailAfterTest(); + } + break; + + case ITestResult.SKIP: + logSkipAfterTest(); + break; + + default: + break; + } + + } + +} + diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/Retry.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/Retry.java new file mode 100644 index 0000000000..0a01da06c3 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/Retry.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import org.testng.Assert; +import org.testng.IRetryAnalyzer; +import org.testng.ITestResult; +import org.testng.annotations.Test; + +public class Retry implements IRetryAnalyzer { + private int retryCount = 0; + private int maxRetryCount = 1; + + public boolean retry(ITestResult result) { + + if (retryCount < maxRetryCount) { + retryCount++; + return true; + } + return false; + } + + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/SetupCDTest.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/SetupCDTest.java new file mode 100644 index 0000000000..1838d3969d --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/SetupCDTest.java @@ -0,0 +1,573 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.UUID; +import java.util.logging.FileHandler; +import java.util.logging.Handler; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +import org.littleshoot.proxy.impl.ClientToProxyConnection; +import org.littleshoot.proxy.impl.ProxyToServerConnection; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.UserCredentials; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.sanity.Onboard; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentManager.suiteNameXml; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openecomp.sdc.ci.tests.run.StartTest; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.ITestContext; +import org.testng.ITestResult; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.ExtentTest; +import com.aventstack.extentreports.Status; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.LoggerContext; +import groovyjarjarantlr.Utils; +import net.lightbody.bmp.BrowserMobProxyServer; +import net.lightbody.bmp.core.har.Har; + +public abstract class SetupCDTest extends DriverFactory { + +// private static final String RE_RUN = "ReRun - "; + private static final String RE_RUN = "ReRun - "; + private static final String WEB_SEAL_PASSWORD = "123123a"; + + public SetupCDTest() { + LoggerContext lc = (LoggerContext) LoggerFactory. getILoggerFactory(); + lc.getLogger("org.apache").setLevel(Level.INFO); + } + + /**************** CONSTANTS ****************/ + private static final String CREDENTIALS_FILE = "credentials.yaml"; + private static final String REPORT_FILE_NAME = "SDC_UI_Extent_Report.html"; + protected static final String REPORT_FOLDER = "." + File.separator + "ExtentReport" + File.separator; + protected static final String SCREENSHOT_FOLDER = REPORT_FOLDER + "screenshots" + File.separator; + protected static final String HAR_FILES_FOLDER_NAME = "har_files"; + protected static final String HAR_FILES_FOLDER = REPORT_FOLDER + HAR_FILES_FOLDER_NAME + File.separator; + + + private static final String SHORT_CSV_REPORT_FILE_NAME = "ShortReport.csv"; + private static final int NUM_OF_ATTEMPTS_TO_REFTRESH = 2; + + + /**************** PRIVATES ****************/ + private static String url; + private static boolean localEnv = true; + private static OnboardCSVReport csvReport; + private static Map credentials; + + protected static ITestContext myContext; + + + /**************** METHODS ****************/ + public static ExtentTest getExtendTest() { + return ExtentTestManager.getTest(); + } + public static WindowTest getWindowTest(){ + return WindowTestManager.getWindowMap(); + } + + public OnboardCSVReport getCsvReport() { + return csvReport; + } + + public static String getReportFolder() { + return REPORT_FOLDER; + } + + public static String getScreenshotFolder() { + return SCREENSHOT_FOLDER; + } + + public static String getHarFilesFolder() { + return HAR_FILES_FOLDER; + } + + + protected abstract UserRoleEnum getRole(); + + /**************** BEFORE ****************/ + + @BeforeSuite(alwaysRun = true) + public void setupBeforeSuite(ITestContext context) throws Exception { + RestCDUtils.deleteOnDemand(); + myContext=context; + setErrorConfigurationFile(); + setUrl(); + ExtentManager.initReporter(getReportFolder(), REPORT_FILE_NAME, context); + csvReport = new OnboardCSVReport(getReportFolder(), SHORT_CSV_REPORT_FILE_NAME); + } + + private static void setErrorConfigurationFile() { + if (!System.getProperty("os.name").contains("Windows")){ + String errorConfigurationFilename = getConfig().getErrorConfigurationFile(); + errorConfigurationFilename = errorConfigurationFilename.substring(errorConfigurationFilename.lastIndexOf("/") + 1, errorConfigurationFilename.length()); + getConfig().setErrorConfigurationFile(FileHandling.getBasePath() + File.separator + "conf" + File.separator + errorConfigurationFilename); + if (new File(getConfig().getErrorConfigurationFile()).exists()){ + System.out.println("Found error-configuration.yaml in : " + getConfig().getErrorConfigurationFile()); + } + } + } + + @BeforeMethod(alwaysRun = true ) + public void setBrowserBeforeTest(java.lang.reflect.Method method, ITestContext context) throws Exception { + + boolean emptyDataProvider = method.getAnnotation(Test.class).dataProvider().isEmpty(); + if (emptyDataProvider) { + System.out.println("ExtentReport instance started from BeforeMethod..."); + String suiteName = ExtentManager.getSuiteName(context); + if (suiteName.equals(suiteNameXml.TESTNG_FAILED_XML_NAME.getValue())) { + ExtentTestManager.startTest(RE_RUN + method.getName()); + }else{ + ExtentTestManager.startTest(method.getName()); + } + + ExtentTestManager.assignCategory(this.getClass()); + setBrowserBeforeTest(getRole()); + } else { + System.out.println("ExtentReport instance started from Test..."); + } + + getConfig().setWindowsDownloadDirectory(getWindowTest().getDownloadDirectory()); + + if (getConfig().getCaptureTraffic()){ + try{ + MobProxy.getPoxyServer().newHar(method.getName() + ".har"); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + /**************** AFTER ****************/ + @AfterMethod(alwaysRun = true) + public void quitAfterTest(ITestResult result, ITestContext context) throws Exception { + + try{ + ReportAfterTestManager.report(result, context); + GeneralUIUtils.closeErrorMessage(); + } + finally{ + try { + if (getConfig().getCaptureTraffic()){ + addTrafficFileToReport(result); + } + + if (result.getInstanceName().equals(Onboard.class.getName()) && result.getStatus() == ITestResult.FAILURE){ + System.out.println("Onboarding test failed, closign browser...."); + getExtendTest().log(Status.INFO, "Onboarding test failed, closign browser...."); + quitDriver(); + } + else if (!getUser().getRole().toLowerCase().equals(UserRoleEnum.ADMIN.name().toLowerCase())){ + boolean navigateToHomePageSuccess = HomePage.navigateToHomePage(); + if (!navigateToHomePageSuccess){ + System.out.println("Navigating to homepage failed, reopening driver...."); + getExtendTest().log(Status.INFO, "Navigating to homepage failed, reopening driver...."); + quitDriver(); + } + } + + } catch (Exception e) { + e.printStackTrace(); + getExtendTest().log(Status.ERROR, "Exception:"+ e.toString()); + } + + + + ExtentTestManager.endTest(); + addResultToCSV(result, context); +// ExtentManager.closeReporter(); + FileHandling.cleanCurrentDownloadDir(); + } + + } + public void addResultToCSV(ITestResult result, ITestContext context) { + String suiteName = ExtentManager.getSuiteName(context); + ExtentTest test = ExtentTestManager.getTest(); + com.aventstack.extentreports.model.Test model = test.getModel(); + String name = model.getName(); + String status = model.getStatus().toString(); + if (suiteName.equals(suiteNameXml.TESTNG_FAILED_XML_NAME.getValue()) && !(result.getStatus() == ITestResult.SUCCESS)) { + getCsvReport().writeRow(result.getInstanceName(), name.replace(RE_RUN,""), status); + } + } + + @AfterSuite(alwaysRun = true) + public void afterSuite() throws Exception { + + if (getConfig().getUseBrowserMobProxy()){ + MobProxy.getPoxyServer().stop(); + } + + csvReport.closeFile(); + RestCDUtils.deleteOnDemand(); + } + + protected static String setUrl() { + url = getConfig().getUrl(); + if (url == null) { + String message = "no URL found"; + System.out.println(message); + Assert.fail(message); + } else if (!url.contains("localhost") && !url.contains("127.0.0.1")) { + localEnv = false; + } + return url; + } + + public static void loadCredentialsFile() throws Exception { + if (credentials != null){ + return; + } + File credentialsFileRemote = new File(FileHandling.getBasePath() + File.separator + "conf" + File.separator + CREDENTIALS_FILE); + File credentialsFileLocal = new File(FileHandling.getConfFilesPath() + CREDENTIALS_FILE); + File[] credentialFiles = {credentialsFileRemote, credentialsFileLocal}; + for (File credentialsFile : credentialFiles){ + if (credentialsFile.exists()){ + credentials = FileHandling.parseYamlFile(credentialsFile.getAbsolutePath()); + break; + } + } + } + + private UserCredentials getUserCredentialsFromFile(String userRole) throws Exception { + @SuppressWarnings("unchecked") + Map credentialsMap = (Map) credentials.get(userRole); + String user = (String) credentialsMap.get("username"); + String password = (String) credentialsMap.get("password"); + String firstname = (String) credentialsMap.get("firstname"); + String lastname = (String) credentialsMap.get("lastname"); + + return new UserCredentials(user, password, firstname, lastname, userRole); + } + + + public static void navigateToUrl(String url) throws Exception { + try { + System.out.println("Deleting cookies..."); + deleteCookies(); + + System.out.println("Navigating to URL : " + url); + getDriver().navigate().to(url); + GeneralUIUtils.waitForLoader(); + + System.out.println("Zooming out..."); + GeneralUIUtils.windowZoomOutUltimate(); + + } + catch (Exception e) { + String msg = "Browser is unreachable"; + System.out.println(msg); + getExtendTest().log(Status.ERROR, msg); + Assert.fail(msg); + } + } + private static void deleteCookies() throws Exception { + getDriver().manage().deleteAllCookies(); + Thread.sleep(1000); + + int attempts = 0; + final int max_attempts = 3; + + while (!getDriver().manage().getCookies().isEmpty() && attempts < max_attempts){ + getExtendTest().log(Status.INFO, "Trying to delete cookies one more time - " + (attempts + 1) + "/" + max_attempts + "attempts"); + String deleteCookiesJS = "document.cookie.split(';').forEach(function(c) { document.cookie = c.replace(/^ +/, '').replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/'); });"; + ((JavascriptExecutor) getDriver()).executeScript(deleteCookiesJS); + attempts++; + + if (attempts == max_attempts){ + String msg = "Did not delete cookies, can't login as user " + WindowTestManager.getWindowMap().getUser().getRole(); + System.out.println(msg); + getExtendTest().log(Status.ERROR, msg); + Assert.fail(msg); + } + } + } + + protected void loginToSystem(UserRoleEnum role) throws Exception { + UserCredentials credentials; + if (localEnv){ + loginToSimulator(role); + credentials = new UserCredentials(role.getUserId(), WEB_SEAL_PASSWORD, role.getFirstName(), role.getLastName(), role.name()); + } + else{ + credentials = getUserFromFileByRole(role); + sendUserAndPasswordKeys(credentials); + WebElement submitButton = GeneralUIUtils.getWebElementBy(By.name("btnSubmit"), 30); + submitButton.click(); + WebElement buttonOK = GeneralUIUtils.getWebElementBy(By.name("successOK"), 30); + Assert.assertTrue(buttonOK.isDisplayed(), "OK button is not displayed."); + buttonOK.click(); + } + GeneralUIUtils.ultimateWait(); + getWindowTest().setUser(credentials); + } + protected UserCredentials getUserFromFileByRole(UserRoleEnum role) throws Exception { + loadCredentialsFile(); + return getUserCredentialsFromFile(role.name().toLowerCase()); + } + private void goToHomePage(UserRoleEnum role) throws Exception { + try { + getWindowTest().setRefreshAttempts(getWindowTest().getRefreshAttempts() == 0 ? NUM_OF_ATTEMPTS_TO_REFTRESH : getWindowTest().getRefreshAttempts()); + if (!role.equals(UserRoleEnum.ADMIN)) { + + WebElement closeButton = GeneralUIUtils.getClickableButtonBy(By.className("sdc-welcome-close"), 10); + if (closeButton != null){ + closeButton.click(); + } + + if (!GeneralUIUtils.isElementVisibleByTestId(DataTestIdEnum.MainMenuButtons.HOME_BUTTON.getValue())) + { + restartBrowser(role); + } + } + } + catch (Exception e) { + restartBrowser(role); + } + } + private void restartBrowser(UserRoleEnum role) throws Exception { + getWindowTest().setRefreshAttempts(getWindowTest().getRefreshAttempts() - 1); + if (getWindowTest().getRefreshAttempts() <= 0) { + System.out.println("ERR : Something is wrong with browser!"); + Assert.fail("ERR : Something is wrong with browser!"); + } + System.out.println("Trying again..."); + getExtendTest().log(Status.INFO, "Trying again..."); + getExtendTest().log(Status.INFO, String.format("%s attempt(s) left", getWindowTest().getRefreshAttempts() )); + System.out.println(String.format("%s attempt(s) left", getWindowTest().getRefreshAttempts() )); + + reloginWithNewRole(role); + } + + public void loginToSimulator(UserRoleEnum role){ + WebDriver driver = GeneralUIUtils.getDriver(); + WebDriverWait wait = new WebDriverWait(driver, 30); + + wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.xpath("//*[@method='" + "post" + "']")))); + + WebElement userIdTextbox = GeneralUIUtils.getWebElementBy(By.name("userId")); + userIdTextbox.sendKeys(role.getUserId()); + WebElement passwordTextbox = GeneralUIUtils.getWebElementBy(By.name("password")); + passwordTextbox.sendKeys(WEB_SEAL_PASSWORD); + + wait.until(ExpectedConditions.elementToBeClickable(driver.findElement(By.xpath("//*[@value='" + "Login" + "']")))).click(); + } + + private void sendUserAndPasswordKeys(UserCredentials userId) { + System.out.println("Login as user : " + userId.getUserId()); + WebElement userNameTextbox = GeneralUIUtils.getWebElementBy(By.name("userid")); + userNameTextbox.sendKeys(userId.getUserId()); + WebElement passwordTextbox = GeneralUIUtils.getWebElementBy(By.name("password")); + passwordTextbox.sendKeys(userId.getPassword()); + } + + public void loginWithUser(UserRoleEnum role) { + try { + getExtendTest().log(Status.INFO, String.format("Login as user %s", role.name().toUpperCase())); + loginToSystem(role); + goToHomePage(role); + } catch (Exception e) { + throw new RuntimeException(e); + } + finally{ + getWindowTest().setPreviousRole(getWindowTest().getUser().getRole()); + } + } + + private void setUser(UserRoleEnum role) { + User user = new User(); + user.setUserId(role.getUserId()); + user.setFirstName(role.getFirstName()); + user.setRole(role.name()); + user.setLastName(role.getLastName()); + + getWindowTest().setUser(user); + } + + public User getUser() { + return getWindowTest().getUser(); + } + + private void setBrowserBeforeTest(UserRoleEnum role) { + System.out.println(String.format("Setup before test as %s.", role.toString().toUpperCase() )); + try { + System.out.println("Previous role is : " + getWindowTest().getPreviousRole() + " ; Current role is : " + role.name()); + if (!getWindowTest().getPreviousRole().toLowerCase().equals(role.name().toLowerCase())){ + System.out.println("Roles are different, navigate and login"); + navigateAndLogin(role); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void navigateAndLogin(UserRoleEnum role) throws Exception { + getWindowTest().setRefreshAttempts(getWindowTest().getRefreshAttempts() != 0 ? getWindowTest().getRefreshAttempts() : 0); + setUser(role); + navigateToUrl(url); + loginWithUser(role); + GeneralUIUtils.ultimateWait(); + } + + public User getUser(UserRoleEnum role) { + User user = new User(); + user.setUserId(role.getUserId()); + user.setFirstName(role.getFirstName()); + user.setLastName(role.getLastName()); + user.setRole(role.name()); + return user; + } + + protected void reloginWithNewRole(UserRoleEnum role) throws Exception { + System.out.println(String.format("Setup before relogin as %s", role.toString().toUpperCase())); + navigateAndLogin(role); + } + + public static void setLocalUrl(UserRoleEnum role) { + switch (role) { + case ADMIN: { + url = "http://localhost:8181/sdc1/proxy-admin1#/dashboard"; + break; + } + case DESIGNER: { + url = "http://localhost:8181/sdc1/proxy-designer1#/dashboard"; + break; + } + case GOVERNOR: { + url = "http://localhost:8181/sdc1/proxy-governor1#/dashboard"; + break; + } + case OPS: { + url = "http://localhost:8181/sdc1/proxy-ops1#/dashboard"; + break; + } + case TESTER: { + url = "http://localhost:8181/sdc1/proxy-tester1#/dashboard"; + break; + } + case PRODUCT_MANAGER1: { + url = "http://localhost:8181/sdc1/proxy-pm1#/dashboard"; + break; + } + case PRODUCT_MANAGER2: { + url = "http://localhost:8181/sdc1/proxy-pm2#/dashboard"; + break; + } + case PRODUCT_STRATEGIST1: { + url = "http://localhost:8181/sdc1/proxy-ps1#/dashboard"; + break; + } + case PRODUCT_STRATEGIST2: { + url = "http://localhost:8181/sdc1/proxy-ps2#/dashboard"; + break; + } + default: { + break; + } + } + } + + public void addTrafficFileToReport(ITestResult result) { + try { + // Get the HAR data + Har har = MobProxy.getPoxyServer().getHar(); + String shortUUID = UUID.randomUUID().toString().split("-")[0]; + File harFile = new File(getHarFilesFolder() + result.getName() + shortUUID + ".har"); + new File(getHarFilesFolder()).mkdirs(); + + har.writeTo(harFile); + + String pathToFileFromReportDirectory = HAR_FILES_FOLDER_NAME + File.separator + harFile.getName(); + ExtentTestActions.addFileToReportAsLink(harFile, pathToFileFromReportDirectory, "File with captured traffic"); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + + /* + * * Start section of test in ExtentReport with DataProvider parameters, + * should be started from test method, see example in onboardVNFTest + */ + public void setLog(String fromDataProvider) { + + String suiteName = ExtentManager.getSuiteName(myContext); + if (suiteName.equals(suiteNameXml.TESTNG_FAILED_XML_NAME.getValue())) { + ExtentTestManager.startTest(RE_RUN +Thread.currentThread().getStackTrace()[2].getMethodName() + "      " + fromDataProvider); + }else{ + ExtentTestManager.startTest(Thread.currentThread().getStackTrace()[2].getMethodName() + "      " + fromDataProvider); + } + + + + getWindowTest().setAddedValueFromDataProvider(fromDataProvider); + ExtentTestManager.assignCategory(this.getClass()); + setBrowserBeforeTest(getRole()); + } + + + + /**************** MAIN ****************/ + public static void main(String[] args) { + System.out.println("---------------------"); + System.out.println("running test from CLI"); + System.out.println("---------------------"); + + String attsdcFilePath = FileHandling.getBasePath() + File.separator + "conf" + File.separator + "attsdc.yaml"; + System.setProperty("config.resource", attsdcFilePath); + System.out.println("attsdc.yaml file path is : " + attsdcFilePath); + + String filepath = FileHandling.getBasePath() + File.separator + "Files" + File.separator; + System.setProperty("filepath", filepath); + System.out.println("filepath is : " + System.getProperty("filepath")); + + Object[] testSuitsList = FileHandling.filterFileNamesFromFolder(FileHandling.getBasePath() + File.separator + "testSuites", ".xml"); + if (testSuitsList != null) { + System.out.println(String.format("Found %s testSuite(s)", testSuitsList.length)); + args = Arrays.copyOf(testSuitsList, testSuitsList.length, String[].class); + StartTest.main(args); + } + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/TestFtp.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/TestFtp.java new file mode 100644 index 0000000000..0268c69f59 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/TestFtp.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +import org.openqa.selenium.remote.internal.ApacheHttpClient; + +public class TestFtp { + + public static void main(String[] args) throws IOException { + // TODO Auto-generated method stub + AttFtpClient instance = AttFtpClient.getInstance(); + + String server = "135.177.130.113"; + int port = 2121; + String user = "admin"; + String pass = "admin"; + AttFtpClient.getInstance().init(server, port, user, pass); + + try { + AttFtpClient.getInstance().retrieveListOfFile(); + + File retrieveLastModifiedFileFromFTP = instance.retrieveLastModifiedFileFromFTP(); + String content = new String(Files.readAllBytes(Paths.get(retrieveLastModifiedFileFromFTP.getPath())), StandardCharsets.UTF_8); +// instance.deleteFilesFromFTPserver(); + System.out.println(content); + readFile(retrieveLastModifiedFileFromFTP); + + } finally { + instance.terminateClient(); + } + + + + + + + + } + public static void readFile(File retrieveLastModifiedFileFromFTP) { + + StringBuilder sb = new StringBuilder(); + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(retrieveLastModifiedFileFromFTP.getPath())); + String line; + while ((line = br.readLine()) != null) { + if (sb.length() > 0) { + sb.append("\n"); + } + sb.append(line); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (br != null) { + br.close(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + String contents = sb.toString(); + System.out.println(contents); + + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WebDriverThread.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WebDriverThread.java new file mode 100644 index 0000000000..5a95df39f8 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WebDriverThread.java @@ -0,0 +1,164 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.UUID; + +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openqa.selenium.Platform; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.firefox.FirefoxProfile; +import org.openqa.selenium.remote.CapabilityType; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.LocalFileDetector; +import org.openqa.selenium.remote.RemoteWebDriver; + +import net.lightbody.bmp.BrowserMobProxyServer; +import net.lightbody.bmp.client.ClientUtil; +import net.lightbody.bmp.proxy.CaptureType; + +public class WebDriverThread { + + public static final String AUTOMATION_DOWNLOAD_DIR = "automationDownloadDir"; + private WebDriver webdriver; + private FirefoxProfile firefoxProfile; + public static final String SELENIUM_NODE_URL = "http://%s:%s/wd/hub"; + + public WebDriverThread(Config config) { + initDriver(config); + webdriver.manage().window().maximize(); + } + + public WebDriver getDriver() throws Exception { + return webdriver; + } + + public void quitDriver() { + if (webdriver != null) { + webdriver.quit(); + webdriver = null; + } + } + + + public void initDriver(Config config){ + try { + boolean remoteTesting = config.isRemoteTesting(); + if (!remoteTesting) { + boolean mobProxyStatus = config.getUseBrowserMobProxy(); + if (mobProxyStatus){ + setWebDriverWithMobProxy(); + } else { + System.out.println("Opening LOCAL browser"); + DesiredCapabilities cap = new DesiredCapabilities(); + + cap = DesiredCapabilities.firefox(); + cap.setBrowserName("firefox"); + cap.setCapability(FirefoxDriver.PROFILE, initFirefoxProfile()); + + firefoxProfile.setPreference("network.proxy.type", 2); + firefoxProfile.setPreference("network.proxy.autoconfig_url", "http://emea-auto.proxy.att.com:8001/"); + firefoxProfile.setPreference("network.proxy.no_proxies_on", "localhost"); + + webdriver = new FirefoxDriver(cap); + } + } else { + System.out.println("Opening REMOTE browser"); + String remoteEnvIP = config.getRemoteTestingMachineIP(); + String remoteEnvPort = config.getRemoteTestingMachinePort(); + + DesiredCapabilities cap = new DesiredCapabilities(); + cap = DesiredCapabilities.firefox(); + cap.setPlatform(Platform.ANY); + cap.setBrowserName("firefox"); + + String remoteNodeUrl = String.format(SELENIUM_NODE_URL, remoteEnvIP, remoteEnvPort); + RemoteWebDriver remoteWebDriver = new RemoteWebDriver(new URL(remoteNodeUrl), cap); + remoteWebDriver.setFileDetector(new LocalFileDetector()); + webdriver = remoteWebDriver; + } + + + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + private FirefoxProfile initFirefoxProfile() { + firefoxProfile = new FirefoxProfile(); + firefoxProfile.setPreference("browser.download.folderList",2); + firefoxProfile.setPreference("browser.download.manager.showWhenStarting",false); + firefoxProfile.setPreference("browser.download.dir", getDownloadDirectory()); + firefoxProfile.setPreference("browser.helperApps.neverAsk.saveToDisk","application/octet-stream, application/xml, text/plain, text/xml, image/jpeg"); + return firefoxProfile; + } + + private String getDownloadDirectory() { + String downloadDirectory = FileHandling.getBasePath() + File.separator + AUTOMATION_DOWNLOAD_DIR + UUID.randomUUID().toString().split("-")[0] + File.separator; + File dir = new File(downloadDirectory); + if(!dir.exists()) { + dir.mkdirs(); + } + return dir.getAbsolutePath(); + } + + public FirefoxProfile getFirefoxProfile() { + return firefoxProfile; + } + + private void setWebDriverWithMobProxy(){ + WebDriver driver = null; + MobProxy.setProxyServer(); + BrowserMobProxyServer proxyServer = MobProxy.getPoxyServer(); + + firefoxProfile = new FirefoxProfile(); + firefoxProfile.setPreference("browser.download.folderList",2); + firefoxProfile.setPreference("browser.download.manager.showWhenStarting",false); + firefoxProfile.setPreference("browser.download.dir", getDownloadDirectory()); + firefoxProfile.setPreference("browser.helperApps.neverAsk.saveToDisk","application/octet-stream, application/xml, text/plain, text/xml, image/jpeg"); + firefoxProfile.setAcceptUntrustedCertificates(true); + firefoxProfile.setAssumeUntrustedCertificateIssuer(true); +// firefoxProfile.setPreference("network.proxy.http", "localhost"); +// firefoxProfile.setPreference("network.proxy.http_port", proxyServer.getPort()); +// firefoxProfile.setPreference("network.proxy.ssl", "localhost"); +// firefoxProfile.setPreference("network.proxy.ssl_port", proxyServer.getPort()); +// firefoxProfile.setPreference("network.proxy.type", 1); +// firefoxProfile.setPreference("network.proxy.no_proxies_on", ""); + + DesiredCapabilities capabilities = new DesiredCapabilities(); + + capabilities.setCapability(FirefoxDriver.PROFILE, firefoxProfile); + capabilities.setCapability(CapabilityType.PROXY, ClientUtil.createSeleniumProxy(proxyServer)); + capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true); + + webdriver = new FirefoxDriver(capabilities); + proxyServer.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT, CaptureType.REQUEST_COOKIES, CaptureType.REQUEST_BINARY_CONTENT, + CaptureType.REQUEST_HEADERS, CaptureType.RESPONSE_COOKIES, CaptureType.RESPONSE_HEADERS, CaptureType.RESPONSE_BINARY_CONTENT); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WindowTest.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WindowTest.java new file mode 100644 index 0000000000..8df3c596fe --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WindowTest.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.io.File; + +import org.openecomp.sdc.be.model.User; + +public class WindowTest { + + public WindowTest(){ + refreshAttempts = 0; + previousRole = ""; + addedValueFromDataProvider = null; + try { + downloadDirectory = DriverFactory.getDriverFirefoxProfile().getStringPreference("browser.download.dir", null) + File.separator; + } catch (Exception e) { + e.printStackTrace(); + } + } + + private int refreshAttempts; + private String previousRole; + private User user; + private String addedValueFromDataProvider; + private String downloadDirectory; + + public int getRefreshAttempts() { + return refreshAttempts; + } + public void setRefreshAttempts(int refreshAttempts) { + this.refreshAttempts = refreshAttempts; + } + public String getPreviousRole() { + return previousRole; + } + public void setPreviousRole(String previousRole) { + this.previousRole = previousRole; + } + public User getUser() { + return user; + } + public void setUser(User user) { + this.user = user; + } + public synchronized String getAddedValueFromDataProvider() { + return addedValueFromDataProvider; + } + public synchronized void setAddedValueFromDataProvider(String addedValueFromDataProvider) { + this.addedValueFromDataProvider = addedValueFromDataProvider; + } + public String getDownloadDirectory() { + return downloadDirectory; + } + public void setDownloadDirectory(String downloadDirectory) { + this.downloadDirectory = downloadDirectory; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WindowTestManager.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WindowTestManager.java new file mode 100644 index 0000000000..5e5ddc4fbd --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/execute/setup/WindowTestManager.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.execute.setup; + +import java.util.HashMap; + +import com.aventstack.extentreports.ExtentTest; + +public class WindowTestManager { + + private static HashMap windowMap = new HashMap(); + + public static synchronized WindowTest getWindowMap() { + Long currentThreadId = Thread.currentThread().getId(); + boolean containsKey = windowMap.containsKey(currentThreadId); + if (!containsKey){ + setWindowMap(currentThreadId); + } + return windowMap.get(currentThreadId); + } + + private static synchronized void setWindowMap(Long currentThreadId) { + WindowTestManager.windowMap.put(currentThreadId, new WindowTest()); + } + + public static synchronized void removeWindowTest(){ + windowMap.remove(Thread.currentThread().getId()); + } + + public static synchronized HashMap getWholeMap(){ + return windowMap; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/AdminGeneralPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/AdminGeneralPage.java new file mode 100644 index 0000000000..98ef4318c8 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/AdminGeneralPage.java @@ -0,0 +1,132 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.UserManagementTab; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.WebElement; + +import com.aventstack.extentreports.Status; + +public class AdminGeneralPage extends GeneralPageElements { + + public AdminGeneralPage() { + super(); + } + + private static UserManagementTab userManagementTab = new UserManagementTab(); + + public static UserManagementTab getUserManagementTab() { + return userManagementTab; + } + + public static void selectCategoryManagmetTab() throws Exception { + + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.AdminPageTabs.CATEGORY_MANAGEMENT.getValue()); + } + + public static void selectUserManagmetTab() throws Exception { + + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.AdminPageTabs.USER_MANAGEMENT.getValue()); + } + + public static List getServiceCategoriesList() throws Exception { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CategoryManagement.SERVICE_CATEGORY_HEADER.getValue()); + GeneralUIUtils.waitForLoader(); + return GeneralUIUtils.getWebElementsListByTestID(DataTestIdEnum.CategoryManagement.SERVICE_CATEGORY_LIST.getValue()); + } + + public static List getResourceCategoriesList() throws Exception { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CategoryManagement.RESOURCE_CATEGORY_HEADER.getValue()); + GeneralUIUtils.waitForLoader(); + return GeneralUIUtils.getWebElementsListByTestID(DataTestIdEnum.CategoryManagement.RESOURCE_CATEGORY_LIST.getValue()); + } + + public static void createNewServiceCategory(String name) throws Exception { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CategoryManagement.SERVICE_CATEGORY_HEADER.getValue()); + SetupCDTest.getExtendTest().log(Status.INFO, "Creating service..."); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CategoryManagement.NEW_CATEGORY_BUTTON.getValue()); + GeneralUIUtils.waitForLoader(); + defineNewResourceCategoryName(name); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + GeneralUIUtils.waitForLoader(); + } + + public static void selectElementFromList(List list, String elementToSelect) throws Exception { + + for (WebElement webElement : list) { + if (webElement.getText().toLowerCase().equals(elementToSelect.toLowerCase())){ + webElement.click(); + } + } + + } + + + + public static void addSubCategoryToResource(List resourceList, String parentResource, String subCategoryName) throws Exception{ + + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CategoryManagement.RESOURCE_CATEGORY_HEADER.getValue()); + selectElementFromList(resourceList, parentResource); + SetupCDTest.getExtendTest().log(Status.INFO, "Creating..."); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CategoryManagement.NEW_SUB_CATEGORY_BUTTON.getValue()); + GeneralUIUtils.waitForLoader(); + defineNewResourceCategoryName(subCategoryName); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + GeneralUIUtils.waitForLoader(); + + + } + + public static void createNewResourceCategory(String name) throws Exception { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CategoryManagement.RESOURCE_CATEGORY_HEADER.getValue()); + SetupCDTest.getExtendTest().log(Status.INFO, "Creating..."); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CategoryManagement.NEW_CATEGORY_BUTTON.getValue()); + GeneralUIUtils.waitForLoader(); + defineNewResourceCategoryName(name); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + GeneralUIUtils.waitForLoader(); + + } + + public void insertPropertyDefaultValue(String value) { + WebElement propertyValue = GeneralUIUtils + .getWebElementByTestID(DataTestIdEnum.PropertiesPopupEnum.PROPERTY_VALUE.getValue()); + propertyValue.clear(); + propertyValue.sendKeys(value); + } + + private static void defineNewResourceCategoryName(String name) { + WebElement categoryNameTextbox = getCategoryName(); + categoryNameTextbox.clear(); + categoryNameTextbox.sendKeys(name); + } + + private static WebElement getCategoryName() { + return GeneralUIUtils.getWebElementByClassName(DataTestIdEnum.CategoryManagement.NEW_CATEGORY_NAME.getValue()); + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ComponentLeftMenu.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ComponentLeftMenu.java new file mode 100644 index 0000000000..d795599f24 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ComponentLeftMenu.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +public interface ComponentLeftMenu { + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/CompositionPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/CompositionPage.java new file mode 100644 index 0000000000..496c537d49 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/CompositionPage.java @@ -0,0 +1,197 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.CanvasElement; +import org.openecomp.sdc.ci.tests.datatypes.CanvasManager; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.Select; + +import com.aventstack.extentreports.Status; + +public class CompositionPage extends GeneralPageElements { + + public CompositionPage() { + super(); + } + + public static UploadArtifactPopup artifactPopup() { + return new UploadArtifactPopup(true); + } + + public static void searchForElement(String elementName) { + SetupCDTest.getExtendTest().log(Status.INFO, "Searching for " + elementName + " in the left panel"); + WebElement searchField = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.CompositionScreenEnum.SEARCH_ASSET.getValue()); + searchField.clear(); + searchField.sendKeys(elementName); + GeneralUIUtils.ultimateWait(); + } + + public static void showDeploymentArtifactTab() throws Exception { + clickOnTabTestID(DataTestIdEnum.CompositionScreenEnum.DEPLOYMENT_ARTIFACT_TAB); + } + + public static void showInformationsTab() throws Exception { + clickOnTabTestID(DataTestIdEnum.CompositionScreenEnum.INFORMATION_TAB); + } + + public static void showPropertiesAndAttributesTab() throws Exception { + clickOnTabTestID(DataTestIdEnum.CompositionScreenEnum.PROPERTIES_AND_ATTRIBUTES_TAB); + } + + public static List getProperties() { + return PropertiesPage.getElemenetsFromTable(); + } + + public static List getDeploymentArtifacts() { + return getAllAddedArtifacts(); + } + + public static List getAllAddedArtifacts() { + String dataTestsId = DataTestIdEnum.CompositionScreenEnum.ARTIFACTS_LIST.getValue(); + return GeneralUIUtils.getWebElementsListBy(By.xpath("//*[contains(@data-tests-id,'" + dataTestsId + "')]")); + } + + public static void moveToInputsScreen() throws Exception { + OpenPagesMenu(); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CompositionScreenEnum.MENU_INPUTS.getValue()); + GeneralUIUtils.ultimateWait(); + } + + private static void OpenPagesMenu() { + Actions actions = new Actions(GeneralUIUtils.getDriver()); + List triangleList = GeneralUIUtils.getWebElementsListByClassName(DataTestIdEnum.CompositionScreenEnum.MENU_TRIANGLE_DROPDOWN.getValue()); + WebElement pagesMenu = triangleList.get(2); + actions.moveToElement(pagesMenu).perform(); + } + + public static void changeComponentVersion(CanvasManager canvasManager, CanvasElement element, String version) { + try{ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Changing component version to %s", version)); + canvasManager.clickOnCanvaElement(element); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.CompositionScreenEnum.CHANGE_VERSION.getValue()); + GeneralUIUtils.ultimateWait(); + Select selectlist = new Select(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.CompositionScreenEnum.CHANGE_VERSION.getValue())); + while (selectlist.getOptions().size() == 0) { + selectlist = new Select(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.CompositionScreenEnum.CHANGE_VERSION.getValue())); + } + GeneralUIUtils.ultimateWait();; + selectlist.selectByValue(version); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.clickSomewhereOnPage(); + } + catch(Exception e){ + throw e; + } + } + + public static void clickAddArtifactButton() throws Exception{ + clickOnTabTestID(DataTestIdEnum.CompositionScreenEnum.ADD_ARTIFACT); + GeneralUIUtils.getWebElementByClassName("sdc-add-artifact"); + } + + public static String getSelectedInstanceName(){ + return GeneralUIUtils.getWebElementByTestID("selectedCompTitle").getText(); + } + + public static void showInformationArtifactTab() throws Exception { + clickOnTab(DataTestIdEnum.CompositionScreenEnum.INFORMATION_ARTIFACTS); + } + + public static void showAPIArtifactTab() throws Exception { + clickOnTab(DataTestIdEnum.CompositionScreenEnum.API); + } + + public static void showInformationTab() throws Exception { + clickOnTab(DataTestIdEnum.CompositionScreenEnum.INFORMATION); + } + + public static void showCompositionTab() throws Exception { + clickOnTab(DataTestIdEnum.CompositionScreenEnum.COMPOSITION); + } + + public static void showInputsTab() throws Exception { + clickOnTab(DataTestIdEnum.CompositionScreenEnum.INPUTS); + } + + public static void showRequirementsAndCapabilitiesTab() throws Exception { + clickOnTab(DataTestIdEnum.CompositionScreenEnum.REQUIREMENTS_AND_CAPABILITIES); + } + + public static List getOpenTabTitle() throws Exception{ +// return GeneralUIUtils.getElementsByCSS("expand-collapse span"); + return GeneralUIUtils.getElementsByCSS("expand-collapse"); + } + + public static void clickOnTab(DataTestIdEnum.CompositionScreenEnum tabSelector) throws Exception{ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s", tabSelector.name())); + GeneralUIUtils.getElementsByCSS(tabSelector.getValue()).get(0).click(); + GeneralUIUtils.ultimateWait(); + } + + public static void clickOnTabTestID(DataTestIdEnum.CompositionScreenEnum tabSelector) throws Exception{ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s", tabSelector.name())); + GeneralUIUtils.getWebElementByTestID(tabSelector.getValue()).click(); + GeneralUIUtils.ultimateWait(); + } + + public static CanvasElement addElementToCanvasScreen(LeftPanelCanvasItems elementName, CanvasManager vfCanvasManager) throws Exception{ + CompositionPage.searchForElement(elementName.name()); + return vfCanvasManager.createElementOnCanvas(elementName); + } + + public static CanvasElement addElementToCanvasScreen(String elementName, CanvasManager vfCanvasManager) throws Exception{ + CompositionPage.searchForElement(elementName); + return vfCanvasManager.createElementOnCanvas(elementName); + } + + public static List getCompositionDeplymentArtifacts() { + return GeneralUIUtils.getWebElementsListByContainTestID(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_DISPLAY_NAME.getValue()); + } + public static WebElement getCustomizationUUID() throws Exception { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.CompositionScreenEnum.CUSTOMIZATION_UUID.getValue()); + } + + + public static List getCompositionEnvArtifacts(){ + return GeneralUIUtils.getWebElementsListByContainTestID(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_ENV.getValue()); + } + + public static WebElement clickDownloadEnvArtifactComposition(String fileName) { + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_ENV.getValue() + fileName); + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT_ENV.getValue() +fileName); + } + + + + + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/DeploymentArtifactPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/DeploymentArtifactPage.java new file mode 100644 index 0000000000..810a1f991c --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/DeploymentArtifactPage.java @@ -0,0 +1,277 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang.WordUtils; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.collections.Lists; + +import com.aventstack.extentreports.Status; + +public class DeploymentArtifactPage extends GeneralPageElements { + + public DeploymentArtifactPage() { + super(); + } + + public static ResourceLeftMenu getLeftPanel() { + return new ResourceLeftMenu(); + } + + public static UploadArtifactPopup artifactPopup() { + return new UploadArtifactPopup(); + } + + protected static void addNewArtifact(ArtifactGroupTypeEnum artifactGroupType) { + switch (artifactGroupType) { + case DEPLOYMENT: + GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.ADD_DEPLOYMENT_ARTIFACT.getValue()).click(); + break; + case INFORMATIONAL: + GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.ADD_INFORMATIONAL_ARTIFACT.getValue()).click(); + break; + default: + break; + } + } + + public static void clickAddNewArtifact() { + addNewArtifact(ArtifactGroupTypeEnum.DEPLOYMENT); + } + + public static void clickAddAnotherArtifact() { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.ADD_ANOTHER_ARTIFACT.getValue()).click(); + } + + public static void clickEditArtifact(String artifactLabel) { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.EDIT_ARTIFACT.getValue() + artifactLabel).click(); + } + + public static void clickEditEnvArtifact(String artifactLabel) { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.EDIT_PARAMETERS_OF_ARTIFACT.getValue() + artifactLabel).click(); + } + + public static void clickDeleteArtifact(String artifactLabel) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Deleting %s Artefact ",artifactLabel)); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.DELETE_ARTIFACT.getValue() + artifactLabel).click(); + } + + public static WebElement clickDownloadArtifact(String artifactLabel) { + WebElement downloadButton = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT.getValue() + artifactLabel); + + return downloadButton; + } + + public static void clickDownloadEnvArtifact(String envFileNameToDownload) { + ExtentTestActions.log(Status.INFO, String.format("Downloading the updated %s artifact for validate parameters with the response after the update...", envFileNameToDownload)); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT_ENV.getValue() + envFileNameToDownload); + ExtentTestActions.log(Status.INFO, String.format("%s Envartifact was downloaded successfully!", envFileNameToDownload)); + } + + public static void clickSaveEnvParameters() { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPopup.SAVE.getValue()).click(); + GeneralUIUtils.ultimateWait(); + } + + public static WebElement getAddOtherArtifactButton(){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.ADD_ANOTHER_ARTIFACT.getValue()); + } + + public static void clickOK(){ + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.OK.getValue()).click(); + GeneralUIUtils.getWebElementBy(By.className("flex-container")); + GeneralUIUtils.waitForAngular(); + } + + public static String getArtifactDescription(String artifactLabel) throws Exception { + clickOnArtifactDescription(artifactLabel); // open artifact + WebElement artifactDescriptionElement = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.GET_DEPLOYMENT_ARTIFACT_DESCRIPTION.getValue()); + String artifactDesc = artifactDescriptionElement.getAttribute("value"); + closeArtifactDescription(artifactLabel); // close artifact + return artifactDesc; + } + + public static void closeArtifactDescription(String artifactLabel) { + GeneralUIUtils.clickOnElementByTestId("popover-x-button"); + } + + public static WebElement clickOnArtifactDescription(String artifactLabel) throws Exception { + try{ + WebElement artifact = GeneralUIUtils.getWebElementByTestID("descriptionIcon_" + artifactLabel); + artifact.click(); + GeneralUIUtils.waitForLoader(); + return artifact; + } + catch(Exception e){ + throw new Exception("Artifact " + artifactLabel + "is not found"); + } + } + + public static boolean checkElementsCountInTable(int expectedElementsCount) { + return GeneralPageElements.checkElementsCountInTable(expectedElementsCount + 1); + } + + public static String[] verifyArtifactsExistInTable(String filepath, String vnfFile) throws Exception{ + String[] artifactNamesFromZipFile = FileHandling.getArtifactsFromZip(filepath, vnfFile); + return verifyArtifactsExistInTable(artifactNamesFromZipFile); + } + + public static String[] verifyArtifactsExistInTable(String[] artifactNamesFromZipFile) throws Exception{ + if (artifactNamesFromZipFile != null){ + checkArtifactsDisplayed(artifactNamesFromZipFile); + checkEnvArtifactsDisplayed(); + } + + return artifactNamesFromZipFile; + } + + public static void checkArtifactsDisplayed(String[] artifactsFromZipFile) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, "Verifying the artifacts in the table"); + List artifactList = Lists.newArrayList(artifactsFromZipFile).stream().filter(p -> !p.contains(".env")).map(p -> getVisualArtifactName(p)).collect(Collectors.toList()); + try{ +// List rows = GeneralUIUtils.getElementsByCSS("div div[data-tests-id^='artifact-item'] span.ng-binding:nth-of-type(2)"); + List rows = GeneralUIUtils.getElementsByCSS("div div[data-tests-id^='artifact-item'] span[data-tests-id^='artifactDisplayName']"); + for (WebElement r : rows){ + String artifactDisplayed = r.getAttribute("textContent").trim(); + if (artifactList.contains(artifactDisplayed)){ + artifactList.remove(artifactDisplayed); + } + else if (artifactDisplayed.toLowerCase().contains("license")){ + artifactList.add(artifactDisplayed); + } + } + checkLicenseArtifactsDisplayed(artifactList); + } + catch(Exception e){ + throw new Exception("Table problem"); + } + + + if (!artifactList.isEmpty()){ + throw new Exception(String.format("missing the following artifact(s) : %s", artifactList.toString())); + } + } + + public static void checkEnvArtifactsDisplayed() throws Exception { + List envRows; + List heatRows; + List heatNetRows; + List heatVolRows; + int envArtifactsSize = 0; + + SetupCDTest.getExtendTest().log(Status.INFO, "Verifying the HEAT_ENV artifacts in the table"); + + try{ + envRows = GeneralUIUtils.getElementsByCSS("div div[data-tests-id='HEAT_ENV']"); + + heatRows = GeneralUIUtils.getElementsByCSS("div div[tooltip-content='HEAT']"); + heatNetRows = GeneralUIUtils.getElementsByCSS("div div[tooltip-content='HEAT_NET']"); + heatVolRows = GeneralUIUtils.getElementsByCSS("div div[tooltip-content='HEAT_VOL']"); + + envArtifactsSize = heatRows.size() + heatNetRows.size() + heatVolRows.size(); + } + catch(Exception e){ + throw new Exception("Table problem"); + } + + if (envArtifactsSize !=envRows.size()){ + throw new Exception(String.format("some env artifacts are missing... there is %s instead of %s", envRows.size(), envArtifactsSize)); + } + + } + + public static void checkLicenseArtifactsDisplayed(List rowsFromTable) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, "Verifying the license artifacts in the table"); + String vfLicense = getPreparedLicense(ArtifactTypeEnum.VF_LICENSE.getType()); + String[] split = vfLicense.split(" "); + vfLicense = vfLicense.replaceAll(split[0], split[0].toUpperCase()); + if (rowsFromTable.contains(vfLicense)){ + rowsFromTable.remove(vfLicense); + } + + String vendorLicense = getPreparedLicense(ArtifactTypeEnum.VENDOR_LICENSE.getType()); + if (rowsFromTable.contains(vendorLicense)){ + rowsFromTable.remove(vendorLicense); + } + + } + + public static String getPreparedLicense(String license) { + return WordUtils.capitalizeFully(license.replaceAll("_", " ")); + } + + + private static String getVisualArtifactName(String artifactName) { + if (artifactName.contains(".")){ + return artifactName.substring(0, artifactName.lastIndexOf(".")); + } + return artifactName; + } + + public static void updateDescription(String newDescription, ArtifactInfo artefact) throws Exception{ + UploadArtifactPopup artifactPopup = new UploadArtifactPopup(true); + DeploymentArtifactPage.clickEditArtifact(artefact.getArtifactLabel()); + artifactPopup.insertDescription(newDescription); + artifactPopup.clickDoneButton(); + } + + public static List getDeploymentArtifactsNamesWorkSpace() { + return GeneralUIUtils.getWebElementListText(GeneralUIUtils.getWebElementsListByContainTestID(DataTestIdEnum.ArtifactPageEnum.ARTIFACT_NAME.getValue())); + } + + //Get Artifact Type by Artifact Name. + public static String getArtifactType(String artifactName){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.TYPE.getValue()+artifactName).getText(); + } + + public static List getHeatParametersInUI(String dataTestId){ + Listelements; + ListNames=new ArrayList<>(); + elements=GeneralUIUtils.getWebElementsListByContainTestID(dataTestId); + for (WebElement webElement : elements) { + String attributevalue=webElement.getAttribute("data-tests-id"); + Names.add(attributevalue.replace("heatParameterName_", "")); + } + return Names; + } + + public static void searchBoxEnv(String parameterName) { + GeneralUIUtils.getWebElementByContainsClassName("w-sdc-env-search-input").sendKeys(parameterName); + } + + public static void clearSearchBoxEnv() { + GeneralUIUtils.getWebElementByContainsClassName("w-sdc-env-search-input").clear(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/DeploymentPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/DeploymentPage.java new file mode 100644 index 0000000000..5ee85e099e --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/DeploymentPage.java @@ -0,0 +1,239 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.DeploymentScreen; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import static org.testng.Assert.assertTrue; + + +import com.aventstack.extentreports.Status; + +public class DeploymentPage { + + public DeploymentPage() { + super(); + } + + public static List getGroupMembersList(String instanceName) { + List propertyRows = null; + clickOnModuleName(instanceName); + propertyRows = getVisibleMembers(); + return propertyRows; + } + + public static void clickOnModuleName(String instanceName) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s", instanceName)); + GeneralUIUtils.clickOnElementByText(instanceName); + GeneralUIUtils.ultimateWait(); + } + + public static List getVisibleMembers() { + List instancesFromTable = GeneralUIUtils.getDriver().findElements(By.cssSelector("div[class^='hierarchy-module-member-list']")); + for (WebElement instance : instancesFromTable){ + Object parentAttributes = GeneralUIUtils.getAllElementAttributes(instance); + if (!parentAttributes.toString().contains("hidden")){ + return instance.findElements(By.cssSelector("div[class^='expand-collapse-sub-title']")); + } + } + return null; + } + + public static void clickOnProperties() throws Exception{ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on Properties button")); + GeneralUIUtils.clickOnElementByCSS(DataTestIdEnum.DeploymentScreen.BUTTON_PROPERTIES.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public static void clickOnArtifacts() throws Exception{ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on Artifacts button")); + GeneralUIUtils.clickOnElementByCSS(DataTestIdEnum.DeploymentScreen.BUTTON_ARTIFACTS.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public static void clickOnSaveButton(){ + clickInDeployment(DataTestIdEnum.DeploymentScreen.SAVE); + GeneralUIUtils.waitForElementInVisibilityByTestId(By.className("popover-inner")); + } + + public static void clickOnCancelButton(){ + clickInDeployment(DataTestIdEnum.DeploymentScreen.CANCEL); + GeneralUIUtils.waitForElementInVisibilityByTestId(By.className("popover-inner")); + } + + public static void clickOnXIcon(){ + clickInDeployment(DataTestIdEnum.DeploymentScreen.X_BUTTON); + GeneralUIUtils.waitForElementInVisibilityByTestId(By.className("popover-inner")); + } + + public static void clickOnEditIcon(){ + clickInDeployment(DataTestIdEnum.DeploymentScreen.PENCIL_ICON); + } + + public static void clickOnProperty(WebElement property) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s propertie ...", property.getText())); + property.click(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPageEnum.POPUP_FORM.getValue()); + } + + private static void clickInDeployment(DataTestIdEnum.DeploymentScreen element){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s ...", element.getValue())); + GeneralUIUtils.clickOnElementByTestId(element.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public static List getPropertyNames() throws Exception{ + clickOnProperties(); + return GeneralUIUtils.getElementsByCSS(DataTestIdEnum.DeploymentScreen.PROPERTY_NAMES.getValue()); + } + + public static List getArtifactNames() throws Exception{ + clickOnArtifacts(); + return GeneralUIUtils.getInputElements(DataTestIdEnum.DeploymentScreen.ARTIFACT_NAME.getValue()); + } + + public static String updateModuleName(String currentModuleName, String newModuleName) throws Exception { + GeneralUIUtils.ultimateWait(); + ResourceUIUtils.clickOnElementByText(currentModuleName, null); + GeneralUIUtils.ultimateWait(); + clickOnEditIcon(); + WebElement moduleNameField = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DeploymentScreen.NAME_INPUT.getValue()); + String oldModuleName = moduleNameField.getAttribute("value"); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating %s module name ...", currentModuleName)); + moduleNameField.clear(); + GeneralUIUtils.ultimateWait(); + moduleNameField.sendKeys(newModuleName); + GeneralUIUtils.ultimateWait(); + clickOnSaveButton(); + String newReconstructedModuleName = reconstructModuleName(currentModuleName.split("\\.\\."), newModuleName); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Name of element instance changed from %s to %s", currentModuleName, newReconstructedModuleName)); + return oldModuleName; + } + + public static String reconstructModuleName(String[] splittedName, String middleName){ + int i = 0; + StringBuilder builder = new StringBuilder(); + for(String s : splittedName) { + if (i == 1){ + builder.append(middleName); + } else { + builder.append(s); + } + if (i < 2 ){ + builder.append(".."); + } + i++; + } + return builder.toString(); + } + + public static List getVisibleModulesService() { + List instancesFromTable = GeneralUIUtils.getDriver().findElements(By.cssSelector("div[class^='hierarchy-modules-list']")); + for (WebElement instance : instancesFromTable){ + Object parentAttributes = GeneralUIUtils.getAllElementAttributes(instance); + if (!parentAttributes.toString().contains("hidden")){ + return instance.findElements(By.cssSelector("span[class^='expand-collapse-title-text']")); + } + } + return null; + } + + public static List getInstanceModulesList(String instanceName) { + List propertyRows = null; + ResourceUIUtils.clickOnElementByText(instanceName, null); + GeneralUIUtils.ultimateWait(); + propertyRows = getVisibleModulesService(); + return propertyRows; + } + + public static String getGroupVersion() throws Exception{ + return GeneralUIUtils.getElementsByCSS("div[data-tests-id='selected-module-version']").get(0).getText(); + } + + public static String getModuleID() throws Exception{ + return GeneralUIUtils.getElementsByCSS("div[data-tests-id='selected-module-group-uuid'] span[class^='small-font']").get(0).getText(); + } + + public static Map> collectMetaDataFromUI() throws Exception{ + ResourceGeneralPage.getLeftMenu().moveToDeploymentViewScreen(); + Map> deploymentViewMetaData = new HashMap>(); + List moduleRowsFromTable = GeneralUIUtils.getElementsByCSS("span[class^='expand-collapse-title-text']"); + for(WebElement moduleRow :moduleRowsFromTable){ + HashMap tempGroupMap = new HashMap(); + String moduleRowText = moduleRow.getText(); + GeneralUIUtils.clickOnElementByText(moduleRowText); + tempGroupMap.put("moduleID", getModuleID()); + tempGroupMap.put("version", DeploymentPage.getGroupVersion().split(":")[1].trim()); + deploymentViewMetaData.put(moduleRowText.split("\\.\\.")[1], tempGroupMap); + GeneralUIUtils.clickOnElementByText(moduleRowText); + } + return deploymentViewMetaData; + } + + public static void updateAndCancel(String newModuleName, DataTestIdEnum.DeploymentScreen buttonToClick){ + WebElement moduleNameField = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DeploymentScreen.NAME_INPUT.getValue()); + String oldModuleName = moduleNameField.getAttribute("value"); + moduleNameField.clear(); + GeneralUIUtils.ultimateWait(); + moduleNameField.sendKeys(newModuleName); + GeneralUIUtils.ultimateWait(); + if (buttonToClick.equals(DataTestIdEnum.DeploymentScreen.X_BUTTON)) + clickOnXIcon(); + else + clickOnCancelButton(); + } + + public static String getPropertyValueFromPropertiesList(String property) throws InterruptedException{ + List propertyDataElements = GeneralUIUtils.getElementsByCSS("div[class^='list-item property-data']"); + for(WebElement propertyDataElement: propertyDataElements){ + WebElement propertyNameElement = GeneralUIUtils.getElementfromElementByCSS(propertyDataElement, DeploymentScreen.PROPERTY_NAMES.getValue()); + if (propertyNameElement.getText().equals(property)){ + WebElement propertyValueElement = GeneralUIUtils.getElementfromElementByCSS(propertyDataElement, String.format("div[data-tests-id='%s']", DeploymentScreen.PROPERTY_SCHEMA_TYPE.getValue())); + return propertyValueElement.getText().trim().split(":")[1].trim(); + } + } + return null; + } + + public static List getPropertyErrorValidationMessdge() throws Exception{ + List propertyErrorElements = GeneralUIUtils.getElementsByCSS("div[class='input-error'] span[class='ng-scope']"); + return propertyErrorElements; + } + + public static boolean isPropertySaveButtonDisabled(){ + WebElement saveButtonElement = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPopupEnum.SAVE.getValue()); + return GeneralUIUtils.isElementDisabled(saveButtonElement); + } + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/GeneralPageElements.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/GeneralPageElements.java new file mode 100644 index 0000000000..04e3a8bb28 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/GeneralPageElements.java @@ -0,0 +1,160 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.List; +import java.util.function.Supplier; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.aventstack.extentreports.Status; + +public class GeneralPageElements { + + public GeneralPageElements() { + super(); + } + + public static ResourceLeftMenu getLeftMenu() { + return new ResourceLeftMenu(); + } + + public static void clickOKButton() { + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on the OK button"); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + GeneralUIUtils.waitForLoader(); + } + + public static void clickCreateButton() { + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on the CREATE/UPDATE button."); + GeneralUIUtils.clickOnAreaJS(DataTestIdEnum.GeneralElementsEnum.CREATE_BUTTON.getValue()); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralElementsEnum.CHECKIN_BUTTON.getValue()); + ExtentTestActions.log(Status.INFO, "Succeeded."); + } + + public static void clickCreateButton(int timeout) { + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on the CREATE/UPDATE button"); + GeneralUIUtils.clickOnAreaJS(DataTestIdEnum.GeneralElementsEnum.CREATE_BUTTON.getValue(), timeout); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralElementsEnum.CHECKIN_BUTTON.getValue()); + } + + public static void clickUpdateButton(){ + clickCreateButton(); + } + + public static void clickCheckinButton(String componentName) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on the CHECKIN button"); + GeneralUIUtils.clickOnAreaJS(DataTestIdEnum.GeneralElementsEnum.CHECKIN_BUTTON.getValue()); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.ACCEP_TESTING_MESSAGE.getValue()).sendKeys("Checkin " + componentName); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtons.SEARCH_BOX.getValue(), 60); + GeneralUIUtils.ultimateWait(); + } + + public static void clickSubmitForTestingButton(String componentName) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on the submiting for testing button"); + GeneralUIUtils.clickOnAreaJS(DataTestIdEnum.GeneralElementsEnum.SUBMIT_FOR_TESTING_BUTTON.getValue()); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.SUMBIT_FOR_TESTING_MESSAGE.getValue()).sendKeys("Submit for testing " + componentName); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtons.SEARCH_BOX.getValue(), 60); + GeneralUIUtils.ultimateWait();; + } + + public static void clickCheckoutButton() throws Exception{ + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on CHECKOUT button ..."); + GeneralUIUtils.clickOnAreaJS(DataTestIdEnum.GeneralElementsEnum.CHECKOUT_BUTTON.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public static void clickDeleteVersionButton() throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on DELETE VERSION button ..."); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.clickOnAreaJS(DataTestIdEnum.GeneralElementsEnum.DELETE_VERSION_BUTTON.getValue()); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.GeneralElementsEnum.OK.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public static void clickRevertButton() throws Exception{ + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on REVERT button ..."); + GeneralUIUtils.clickOnAreaJS(DataTestIdEnum.GeneralElementsEnum.REVERT_BUTTON.getValue()); + } + + public static String getLifeCycleState() { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralElementsEnum.LIFECYCLE_STATE.getValue()).getText(); + } + + public static void selectVersion(String version) { + GeneralUIUtils.getSelectList(version, DataTestIdEnum.GeneralElementsEnum.VERSION_HEADER.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public static List getElemenetsFromTable() { + GeneralUIUtils.ultimateWait();; + return GeneralUIUtils.getElemenetsFromTable(By.className("flex-container")); + } + + public static boolean checkElementsCountInTable(int expectedElementsCount) { + return checkElementsCountInTable(expectedElementsCount, () -> getElemenetsFromTable()); + } + + + public static void clickTrashButtonAndConfirm() throws InterruptedException{ + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on TRASH button ..."); + GeneralUIUtils.clickOnAreaJS(DataTestIdEnum.GeneralElementsEnum.DELETE_VERSION_BUTTON.getValue()); + clickOKButton(); + } + + public static boolean checkElementsCountInTable(int expectedElementsCount, Supplier> func) { + SetupCDTest.getExtendTest().log(Status.INFO, "Checking the number of elements in the table; should be " + (expectedElementsCount - 1)); +// int maxWaitingPeriodMS = 10*1000; +// int napPeriodMS = 200; +// int sumOfWaiting = 0; +// List elements = null; +// boolean isKeepWaiting = false; +// while (!isKeepWaiting) { +// GeneralUIUtils.sleep(napPeriodMS); +// sumOfWaiting += napPeriodMS; +// elements = func.get(); +// isKeepWaiting = (expectedElementsCount == elements.size()); +// if (sumOfWaiting > maxWaitingPeriodMS) +// return false; +// } + GeneralUIUtils.ultimateWait(); + return true; + } + + public static void clickDeleteFile() throws Exception{ + SetupCDTest.getExtendTest().log(Status.INFO, "Clicking on delete file X-button ..."); + GeneralUIUtils.clickOnAreaJS(GeneralUIUtils.getWebElementBy + (By.cssSelector("div[class='i-sdc-form-file-upload-x-btn']"))); + GeneralUIUtils.ultimateWait();; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/GovernorOperationPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/GovernorOperationPage.java new file mode 100644 index 0000000000..ff964e3a01 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/GovernorOperationPage.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; + +import com.aventstack.extentreports.Status; + +public class GovernorOperationPage { + + public GovernorOperationPage() { + super(); + } + + public static void approveSerivce(String serviceName) { + SetupCDTest.getExtendTest().log(Status.INFO, "Approving the distrbution of the service " + serviceName); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DistributionChangeButtons.APPROVE.getValue()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DistributionChangeButtons.APPROVE_MESSAGE.getValue()) + .sendKeys("service " + serviceName + " tested successfuly"); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.OK.getValue()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtons.SEARCH_BOX.getValue()); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/HomePage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/HomePage.java new file mode 100644 index 0000000000..84451dc905 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/HomePage.java @@ -0,0 +1,109 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.io.File; +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.MainMenuButtonsFromInsideFrame; +import org.openecomp.sdc.ci.tests.utilities.DownloadManager; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +public class HomePage extends GeneralPageElements { + + public HomePage() { + super(); + } + + public static void showVspRepository(){ + GeneralUIUtils.waitForElementInVisibilityBy(By.className("ui-notification"), 30); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.MainMenuButtons.REPOSITORY_ICON.getValue()); + } + + public static boolean searchForVSP(String vspName){ + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ImportVfRepository.SEARCH.getValue()).sendKeys(vspName); + return checkElementsCountInTable(2); + } + + public static void importVSP(String vspName){ + HomePage.showVspRepository(); + boolean vspFound = HomePage.searchForVSP(vspName); + if (vspFound){ + List elemenetsFromTable = getElemenetsFromTable(); +// GeneralUIUtils.waitForLoader(); + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), 30); + WebElement findElement = wait.until(ExpectedConditions.visibilityOf(elemenetsFromTable.get(1))); + findElement.click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ImportVfRepository.IMPORT_VSP.getValue()); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.GeneralElementsEnum.CREATE_BUTTON.getValue()); + GeneralUIUtils.waitForLoader(60*10); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralElementsEnum.CHECKIN_BUTTON.getValue()); + } + } + + + public static boolean navigateToHomePage() { + try{ + System.out.println("Searching for reporsitory icon."); + WebElement repositoryIcon = GeneralUIUtils.getInputElement("repository-icon"); + if (repositoryIcon != null){ + return true; + } + else{ + GeneralUIUtils.ultimateWait(); + List homeButtons = GeneralUIUtils.getElemenetsFromTable(By.xpath("//a[contains(.,'HOME')]")); + if (homeButtons.size() != 0){ + for (WebElement home : homeButtons){ + if (home.isDisplayed()){ + home.click(); + System.out.println("Clicked on home button"); + break; + } + } + GeneralUIUtils.closeErrorMessage(); + WebElement homeButton = GeneralUIUtils.getInputElement(DataTestIdEnum.MainMenuButtons.HOME_BUTTON.getValue()); + return homeButton.isDisplayed(); + } + + } + } + catch(Exception innerException){ + System.out.println("Can't click on home button."); + return false; + } + return false; + } + + public static File downloadVspCsarToDefaultDirectory(String vspName) throws Exception { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtonsFromInsideFrame.HOME_BUTTON.getValue()).click(); + DownloadManager.downloadCsarByNameFromVSPRepository(vspName, ""); + File latestFilefromDir = FileHandling.getLastModifiedFileFromDir(); + return latestFilefromDir; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/IconPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/IconPage.java new file mode 100644 index 0000000000..fd9befa148 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/IconPage.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.ResourceCategoryEnum; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; + +public class IconPage extends GeneralPageElements { + + public IconPage() { + super(); + } + + public static void clickOnIcon(ResourceCategoryEnum iconName) { + GeneralUIUtils.getWebElementByTestID(iconStringBuilder(iconName) + DataTestIdEnum.ServiceMetadataEnum.ICON.getValue()) + .click(); + } + + private static String iconStringBuilder(ResourceCategoryEnum icon) { + String iconName = icon.getSubCategory(); + String[] splitedIconName = iconName.split(" "); + splitedIconName[0] = splitedIconName[0].toLowerCase(); + + StringBuilder sb = new StringBuilder(); + for (String word : splitedIconName) { + sb.append(word); + } + + return sb.toString(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/InformationalArtifactPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/InformationalArtifactPage.java new file mode 100644 index 0000000000..9916292e5b --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/InformationalArtifactPage.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openqa.selenium.WebElement; + +import com.aventstack.extentreports.Status; + +public class InformationalArtifactPage extends DeploymentArtifactPage { + + public InformationalArtifactPage() { + super(); + } + + public static void clickAddNewArtifact() { + addNewArtifact(ArtifactGroupTypeEnum.INFORMATIONAL); + } + + public static String getArtifactDescription(String artifactLabel) throws Exception { + InformationalArtifactPage.clickOnArtifact(artifactLabel); + String artifactDesc = GeneralUIUtils.getWebElementByTestID( + artifactLabel + DataTestIdEnum.ArtifactPageEnum.GET_INFORMATIONAL_ARTIFACT_DESCRIPTION.getValue()) + .getText(); + InformationalArtifactPage.clickOnArtifact(artifactLabel); // close artifact + return artifactDesc; + } + + public static List getElemenetsFromTable() { + return GeneralUIUtils.getWebElementsListByTestID("InformationalArtifactRow"); + } + + public static WebElement clickOnArtifact(String artifactLabel) throws Exception { + try{ + WebElement artifact = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.ARTIFACT_NAME.getValue() + artifactLabel); + artifact.click(); + GeneralUIUtils.waitForLoader(); + return artifact; + } + catch(Exception e){ + throw new Exception("Artifact " + artifactLabel + "is not found"); + } + } + + + public static void clickDeleteArtifact(String artifactLabel) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Deleting %s Artefact ",artifactLabel)); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPageEnum.DELETE_ARTIFACT.getValue() + artifactLabel).click(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/InputsPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/InputsPage.java new file mode 100644 index 0000000000..b977b263a0 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/InputsPage.java @@ -0,0 +1,158 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.List; +import java.util.stream.Collectors; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.InputsScreenService; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.TestException; + +import com.aventstack.extentreports.Status; + +public class InputsPage extends GeneralPageElements { + + public InputsPage() { + super(); + + } + + public static List getInstancePropertiesList(String instanceName) { + List propertyRows = null; + GeneralUIUtils.clickOnElementByText(instanceName); + GeneralUIUtils.ultimateWait(); + propertyRows = getVisibleProperites(); + return propertyRows; + } + + public static List getVisibleProperites() { + List instancesFromTable = GeneralUIUtils.getDriver().findElements(By.cssSelector("div[class^='vf-instance-list']")); + for (WebElement instance : instancesFromTable){ + Object parentAttributes = GeneralUIUtils.getAllElementAttributes(instance); + if (!parentAttributes.toString().contains("hidden")){ + return instance.findElements(By.className("property-row")); + } + } + return null; + } + + public static void addInputToService(String VFInstanceName, String propertyName) throws Exception{ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Adding property %s from VF instance %s to Service", propertyName, VFInstanceName)); + List instaceInputs = getInstanceInputsList(VFInstanceName); + for(WebElement instancInput: instaceInputs){ + String actualPropertyName = instancInput.findElement(By.className("title-text")).getText(); + if (actualPropertyName.equals(propertyName) && clickOnVFInputCheckbox(instancInput)){ + clickOnAddInputButton(); + } + } + } + + public static List getInstanceInputsList(String instanceName) { + List inputRows = null; + GeneralUIUtils.clickOnElementByText(instanceName); + GeneralUIUtils.ultimateWait(); + inputRows = getVisibleInputs(inputRows); + return inputRows; + } + + public static List getVisibleInputs(List inputRows) { + List instancesFromTable = GeneralUIUtils.getDriver().findElements(By.cssSelector("div[class^='vf-instance-list']")); + for (WebElement instance : instancesFromTable){ + Object parentAttributes = GeneralUIUtils.getAllElementAttributes(instance); + if (!parentAttributes.toString().contains("hidden")){ + inputRows = instance.findElements(By.className("input-row")); + break; + } + } + return inputRows; + } + + public static void clickOnAddInputButton(){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on Add Input aka Greater than symbol button")); + GeneralUIUtils.clickOnElementByTestId(InputsScreenService.ADD_SELECTED_INPUTS_BTN.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public static boolean clickOnVFInputCheckbox(WebElement instancInput){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on VF instance input checkbox")); + instancInput.findElement(By.className("tlv-checkbox-label")).click(); + GeneralUIUtils.ultimateWait(); + return instancInput.findElement(By.className("tlv-checkbox-i")).getAttribute("class").contains("ng-not-empty"); + } + + public static WebElement getServiceInput(String VFInstanceName, String propertyName) throws Exception{ + String expectedInputName = String.format("%s_%s", VFInstanceName.replace(" ", "").toLowerCase(), propertyName); + List inputsFromTable = GeneralUIUtils.getElementsByCSS(InputsScreenService.SERVICE_INPUT_ROW.getValue()); + for(WebElement inputFromTable: inputsFromTable){ + String actualInputName = inputFromTable.findElement(By.className("title-text")).getText(); + if(actualInputName.equals(expectedInputName)){ + return inputFromTable; + } + } + throw new TestException(String.format("%s input don't exist", expectedInputName)); + } + + public static void deleteServiceInput(String VFInstanceName, String propertyName) throws Exception{ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Deleting property %s in VF instance %s ", propertyName, VFInstanceName)); + WebElement serviceInput = getServiceInput(VFInstanceName, propertyName); + serviceInput.findElement(By.cssSelector(InputsScreenService.DELETE_INPUT_BTN.getValue())).click(); + GeneralUIUtils.ultimateWait(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on OK button ")); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.GeneralElementsEnum.OK.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public static List getVFCInstancesNamesFromTable() throws Exception{ + WebElement inputsTable = getInputsTable("VFC "); + return inputsTable.findElements(By.cssSelector("span[class^='title-text']")).stream(). + map(e -> e.getText()). + collect(Collectors.toList()); + } + + public static WebElement getInputsTable(String tableName) throws Exception{ + List tableElements = GeneralUIUtils.getElementsByCSS("div.table"); + for(WebElement tableElement: tableElements){ + String tableTitle = GeneralUIUtils.getElementfromElementByCSS(tableElement, "div.table-header").getText(); + if (tableTitle.contains(tableName)){ + return tableElement; + } + } + throw new TestException(String.format("Can't find %s table", tableName)); + } + + public static void clickOnProperty(String propertyName) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on property %s ", propertyName)); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.InputsScreenService.RESOURCE_INSTANCE_PROPERTY_NAME.getValue() + propertyName); + GeneralUIUtils.ultimateWait(); + } + + + + + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/OpsOperationPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/OpsOperationPage.java new file mode 100644 index 0000000000..82171b8de9 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/OpsOperationPage.java @@ -0,0 +1,156 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.StepsEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +import com.aventstack.extentreports.Status; + +public class OpsOperationPage { + + public OpsOperationPage() { + super(); + } + + public static void distributeService() { + SetupCDTest.getExtendTest().log(Status.INFO, "Distributing"); + clickOnButton(DataTestIdEnum.DistributionChangeButtons.DISTRIBUTE); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DistributionChangeButtons.MONITOR.getValue()); + } + + public static void displayMonitor() { + GeneralUIUtils.moveToStep(StepsEnum.MONITOR); + } + + public static void re_distributeService() { + SetupCDTest.getExtendTest().log(Status.INFO, "Redistributing..."); + clickOnButton(DataTestIdEnum.DistributionChangeButtons.RE_DISTRIBUTE); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DistributionChangeButtons.MONITOR.getValue()); + } + + private static void clickOnButton(DataTestIdEnum.DistributionChangeButtons button) { + GeneralUIUtils.getWebElementByTestID(button.getValue()).click(); + GeneralUIUtils.waitForLoader(); + } + + public static List getRowsFromMonitorTable() { + SetupCDTest.getExtendTest().log(Status.INFO, "Counting the rows from the distribution table"); + GeneralPageElements.checkElementsCountInTable(1, () -> GeneralUIUtils.getWebElementsListByTestID("ditributionTable")); + List distributionRecords = GeneralUIUtils.getWebElementsListByTestID("ditributionTable"); + List findElements = distributionRecords.get(0).findElements(By.className("w-sdc-distribute-parent-block")); + return findElements; + } + + public static void showDistributionStatus(int rowIndex) { + GeneralUIUtils.getWebElementByTestID("ShowRecordButton_" + String.valueOf(rowIndex)).click(); + GeneralUIUtils.waitForLoader(); + } + + public static String getTotalArtifactsSum(int rowIndex) { + return GeneralUIUtils.getWebElementByTestID("totalArtifacts_" + String.valueOf(rowIndex)).getText(); + } + + public static String getNotifiedArtifactsSum(int rowIndex) { + return GeneralUIUtils.getWebElementByTestID("notified_" + String.valueOf(rowIndex)).getText(); + } + + public static String getDownloadedArtifactsSum(int rowIndex) { + return GeneralUIUtils.getWebElementByTestID("downloaded_" + String.valueOf(rowIndex)).getText(); + } + + public static String getDeployedArtifactsSum(int rowIndex) { + return GeneralUIUtils.getWebElementByTestID("deployed_" + String.valueOf(rowIndex)).getText(); + } + + public static String getNotNotifiedArtifactsSum(int rowIndex) { + return GeneralUIUtils.getWebElementByTestID("NotNotified_" + String.valueOf(rowIndex)).getText(); + } + + public static String getErrorsSum(int rowIndex) { + return GeneralUIUtils.getWebElementByTestID("errors_" + String.valueOf(rowIndex)).getText(); + } + + public static void clickRefreshTableButton(int rowIndex) { + GeneralUIUtils.getWebElementByTestID("refreshButton").click(); + // wait until total artifacts field disappear + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), 90); + wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//*[@data-tests-id='" + "totalArtifacts_" + String.valueOf(rowIndex) + "']"))); + } + + public static void waitUntilArtifactsDistributed(int rowIndex) throws Exception { + waitUntilArtifactsDistributed("0", 0); + } + + public static void waitUntilArtifactsDistributed(String expectedArtifactsSum, int rowIndex) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, "Waiting until all artifacts are distributed"); + boolean isKeepWaiting = true; + int maxWaitingPeriodMS = 5 * 60 * 1000; + int sumWaitingTime = 0; + int napPeriod = 10000; + while (isKeepWaiting) { + showDistributionStatus(rowIndex); + String actualTotalArtifactsSize = getTotalArtifactsSum(rowIndex); + String actualNotifiedArtifactsSize = getNotifiedArtifactsSum(rowIndex); + String actualDownloadedArtifactsSize = getDownloadedArtifactsSum(rowIndex); + String actualDeployedArtifactsSize = getDeployedArtifactsSum(rowIndex); + String actualNotNotifedArtifactsSize = getNotNotifiedArtifactsSum(rowIndex); + isKeepWaiting = !actualTotalArtifactsSize.equals(actualDownloadedArtifactsSize) + || !actualTotalArtifactsSize.equals(actualNotifiedArtifactsSize) + || !actualTotalArtifactsSize.equals(actualDeployedArtifactsSize) + || actualTotalArtifactsSize.equals("0") || actualDownloadedArtifactsSize.equals("0") + || actualNotifiedArtifactsSize.equals("0") || actualDeployedArtifactsSize.equals("0"); + + if (isKeepWaiting) { + + if (Integer.parseInt(actualNotNotifedArtifactsSize) > 1) { + SetupCDTest.getExtendTest().log(Status.INFO, "Some artifacts are not notified"); + isKeepWaiting = false; + throw new Exception("Some artifacts are not notified..."); + } + + GeneralUIUtils.sleep(napPeriod); + sumWaitingTime += napPeriod; + + if (sumWaitingTime > maxWaitingPeriodMS) { + SetupCDTest.getExtendTest().log(Status.INFO, "Not all artifacts are displayed"); + isKeepWaiting = false; + throw new Exception(String.format("Not all artifacts are displayed withing %s seconds", + String.valueOf(maxWaitingPeriodMS / 1000))); + } + + clickRefreshTableButton(rowIndex); + } + } + + SetupCDTest.getExtendTest().log(Status.INFO, "All artifacts were successfully distributed"); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ProductGeneralPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ProductGeneralPage.java new file mode 100644 index 0000000000..3bec4f636c --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ProductGeneralPage.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.ArrayList; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.aventstack.extentreports.Status; + +/** + * @author al714h + * + */ + +public class ProductGeneralPage extends ResourceGeneralPage { + + public ProductGeneralPage() { + super(); + } + + public static ProductLeftMenu getProductLeftMenu() { + return new ProductLeftMenu(); + } + + public static void defineName(String productName) { + WebElement productNameTextbox = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ProductMetadataEnum.PRODUCT_NAME.getValue()); + productNameTextbox.clear(); + productNameTextbox.sendKeys(productName); + } + + public static void defineFullName(String productFullName) { + WebElement productFullNameTextbox = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ProductMetadataEnum.FULL_NAME.getValue()); + productFullNameTextbox.clear(); + productFullNameTextbox.sendKeys(productFullName); + } + + public static void defineProjectCode(String pmat) { + WebElement pmattTextbox = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ProductMetadataEnum.PROJECT_CODE.getValue()); + pmattTextbox.clear(); + pmattTextbox.sendKeys(pmat); + } + + public static String getPmattText(){ + return getPmattField().getAttribute("value"); + } + + public static String[] getTags(){ + return ResourceGeneralPage.getElementsFromTagsTable().stream().map(WebElement::getText).toArray(String[]::new); + } + + private static WebElement getPmattField() { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ProductMetadataEnum.PROJECT_CODE.getValue()); + } + + public static void deleteOldTags(ProductReqDetails product){ + // Delete tag elements + int i = GeneralUIUtils.getWebElementsListByTestID("i-sdc-tag-delete").size(); + while (i > 0){ + GeneralUIUtils.getWebElementByTestID("i-sdc-tag-delete").click(); + i--; + } + + product.setTags(new ArrayList()); + } + + public static void clickAddWorkflow (){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Adding workflow...")); + GeneralUIUtils.clickOnElementByText("Add Workflow"); + } + + public static void fillAndAddNewWorkflow(String name, String description ) throws InterruptedException{ + GeneralUIUtils.ultimateWait(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Filling name field with %s", name)); + insertText(name, "label + input"); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Filling description filed with %s", name)); + insertText(description,"label + textarea"); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking save button ")); + clickSave(); + } + + public static void insertText(String artifactDescriptoin, String element) throws InterruptedException { + GeneralUIUtils.getElementsByCSS("div[class='modal-content']"); + WebElement artifactDescriptionTextbox = GeneralUIUtils.getWebElementBy(By.cssSelector(element)); + artifactDescriptionTextbox.clear(); + artifactDescriptionTextbox.sendKeys(artifactDescriptoin); + GeneralUIUtils.ultimateWait(); + } + + public static void clickSave() { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on Save button")); + GeneralUIUtils.clickOnElementByText("Save"); + GeneralUIUtils.ultimateWait(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ProductLeftMenu.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ProductLeftMenu.java new file mode 100644 index 0000000000..2972e59618 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ProductLeftMenu.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.StepsEnum; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; + +/** + * @author al714h + * + */ + +public class ProductLeftMenu implements ComponentLeftMenu { + + public void moveToGeneralScreen() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.GENERAL); + } + + public void moveToIconScreen() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.ICON); + } + + public void moveToCompositionScreen() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.COMPOSITION); + } + + public void moveToHierarchyScreen() { + GeneralUIUtils.moveToStep(StepsEnum.HIERARCHY); + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/PropertiesPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/PropertiesPage.java new file mode 100644 index 0000000000..4899ab15af --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/PropertiesPage.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.aventstack.extentreports.Status; + +public class PropertiesPage extends GeneralPageElements { + + public PropertiesPage() { + super(); + } + + public static List getElemenetsFromTable() { + return GeneralUIUtils.getInputElements(DataTestIdEnum.PropertiesPageEnum.PROPERTY_ROW.getValue()); + } + + public static void clickAddPropertyArtifact() { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPageEnum.ADD_NEW_PROPERTY.getValue()).click(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPageEnum.POPUP_FORM.getValue()); + } + + public static void clickEditPropertyArtifact(String propertyName) { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPageEnum.EDIT_PROPERTY.getValue() + propertyName).click(); + } + + public static void clickDeletePropertyArtifact(String propertyName) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Delete property %s", propertyName)); + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.PropertiesPageEnum.PROPERTY_NAME.getValue() + propertyName); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.PropertiesPageEnum.DELETE_PROPERTY.getValue() + propertyName); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + GeneralUIUtils.waitForElementInVisibilityBy(By.className("w-sdc-modal-confirmation"), 10); + } + + public static void clickOnProperty(String propertyName) { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPageEnum.PROPERTY_NAME.getValue() + propertyName).click(); + } + + public static PropertyPopup getPropertyPopup() { + return new PropertyPopup(); + } + + public static boolean verifyTotalProperitesField(int count){ + String totalPropertiesCount = GeneralUIUtils.getWebElementBy(By.id("properties-count")).getText(); + return ("Total Properties: " + count).equals(totalPropertiesCount); + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/PropertyPopup.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/PropertyPopup.java new file mode 100644 index 0000000000..5052406d4e --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/PropertyPopup.java @@ -0,0 +1,111 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Select; + +import com.aventstack.extentreports.Status; + +public class PropertyPopup { + + + public PropertyPopup() { + } + + public boolean getPopupForm(){ + return GeneralUIUtils.waitForElementInVisibilityByTestId(DataTestIdEnum.PropertiesPageEnum.POPUP_FORM.getValue(), 60); + } + + public void insertPropertyName(String name) { + WebElement propertyNameField = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPopupEnum.PROPERTY_NAME.getValue()); + propertyNameField.clear(); + propertyNameField.sendKeys(name); + } + + public void insertPropertyDefaultValue(String value) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Inserting to property default value: %s ", value)); + WebElement selectedType = new Select(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPopupEnum.PROPERTY_TYPE.getValue())).getFirstSelectedOption(); + if(selectedType.getText().equals("boolean")) { + GeneralUIUtils.getSelectList(value, DataTestIdEnum.PropertiesPopupEnum.PROPERTY_BOOLEAN_VALUE.getValue()); + } else { + WebElement propertyValue = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPopupEnum.PROPERTY_VALUE.getValue()); + propertyValue.clear(); + propertyValue.sendKeys(value); + } + + GeneralUIUtils.ultimateWait(); + } + + public void insertPropertyDescription(String description) { + WebElement propertyDescription = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPopupEnum.PROPERTY_DESCRIPTION.getValue()); + propertyDescription.clear(); + propertyDescription.sendKeys(description); + } + + public void selectPropertyType(String propertyType) { + boolean isEntrySchemaDisplayed; + try{ + GeneralUIUtils.getSelectList(propertyType, DataTestIdEnum.PropertiesPopupEnum.PROPERTY_TYPE.getValue()); + isEntrySchemaDisplayed = GeneralUIUtils.getDriver().findElement(By.xpath(DataTestIdEnum.PropertiesPopupEnum.ENTRY_SCHEMA.getValue())).isDisplayed(); + if (isEntrySchemaDisplayed){ + PropertiesPage.getPropertyPopup().selectEntrySchema(propertyType); + } + } + catch(NoSuchElementException e){ + + } + } + + public void selectEntrySchema(String propertyType){ + GeneralUIUtils.getSelectList(propertyType, DataTestIdEnum.PropertiesPopupEnum.ENTRY_SCHEMA.getValue()); + } + + public void clickAdd() { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.PropertiesPopupEnum.ADD.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public void clickSave() { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.PropertiesPopupEnum.SAVE.getValue()); + getPopupForm(); + } + + public void clickCancel() { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.PropertiesPopupEnum.CANCEL.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public void clickDone() { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.PropertiesPopupEnum.DONE.getValue()); + GeneralUIUtils.ultimateWait(); + } + + public void selectPropertyRadioButton(String propertyName) { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPopupEnum.PROPERTY_RADIO_BUTTON_CONTAINER.getValue() + propertyName).findElement(By.className(DataTestIdEnum.PropertiesPopupEnum.RADIO_BUTTON_CLASS.getValue())).click(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ResourceGeneralPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ResourceGeneralPage.java new file mode 100644 index 0000000000..1412a4b969 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ResourceGeneralPage.java @@ -0,0 +1,177 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; + + +public class ResourceGeneralPage extends GeneralPageElements { + + public ResourceGeneralPage() { + super(); + } + + public static WebElement getNameField() { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ResourceMetadataEnum.RESOURCE_NAME.getValue()); + } + + public static WebElement getDescriptionField() { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ServiceMetadataEnum.DESCRIPTION.getValue()); + } + + public static String getCategoryDataTestsIdAttribute() { + return DataTestIdEnum.ResourceMetadataEnum.CATEGORY.getValue(); + } + + public static WebElement getVendorNameField() { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ResourceMetadataEnum.VENDOR_NAME.getValue()); + } + + public static WebElement getVendorReleaseField() { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ResourceMetadataEnum.VENDOR_RELEASE.getValue()); + } + + public static WebElement getTagsField() { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ResourceMetadataEnum.TAGS.getValue()); + } + + public static WebElement getContactIdField() { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ResourceMetadataEnum.CONTACT_ID.getValue()); + } + + /***************************************************************/ + + public static String getNameText() { + return getNameField().getAttribute("value"); + } + + public static void defineName(String resourceName) { + WebElement resourceNameTextbox = getNameField(); + resourceNameTextbox.clear(); + resourceNameTextbox.sendKeys(resourceName); + } + + public static void defineNameWithPaste() { + defineTextBoxWithPaste(getNameField()); + } + + public static String getDescriptionText() { + return getDescriptionField().getAttribute("value"); + } + + public static void defineDescription(String description) { + WebElement descriptionTextbox = getDescriptionField(); + descriptionTextbox.clear(); + descriptionTextbox.sendKeys(description); + } + + public static void defineDescriptionWithPaste() { + defineTextBoxWithPaste(getDescriptionField()); + } + + public static String getVendorNameText() { + return getVendorNameField().getAttribute("value"); + } + + public static void defineVendorName(String vendorName) { + WebElement vendorNameTextbox = getVendorNameField(); + vendorNameTextbox.clear(); + vendorNameTextbox.sendKeys(vendorName); + } + + public static void defineVendorNameWithPaste() { + defineTextBoxWithPaste(getVendorNameField()); + } + + public static String getVendorReleaseText() { + return getVendorReleaseField().getAttribute("value"); + } + + public static void defineVendorRelease(String vendorRelease) { + WebElement vendorReleaseTextbox = getVendorReleaseField(); + vendorReleaseTextbox.clear(); + vendorReleaseTextbox.sendKeys(vendorRelease); + } + + public static void defineVendorReleaseWithPaste() { + defineTextBoxWithPaste(getVendorReleaseField()); + } + + public static void defineTag(String resourceTags) { + WebElement tagTextbox = getTagsField(); + tagTextbox.clear(); + tagTextbox.sendKeys(resourceTags); + tagTextbox.sendKeys(Keys.ENTER); + } + + public static void defineTagsList(ComponentReqDetails component, String[] tags) { + List taglist = new ArrayList(); + WebElement resourceTagsTextbox = getTagsField(); + for (String tag : tags) { + resourceTagsTextbox.clear(); + resourceTagsTextbox.sendKeys(tag); + GeneralUIUtils.sleep(500); + resourceTagsTextbox.sendKeys(Keys.ENTER); + taglist.add(tag); + } + component.getTags().addAll(taglist); + } + + public static void defineTagsListWithPaste() { + List taglist = new ArrayList(); + WebElement resourceTagsTextbox = getTagsField(); + defineTextBoxWithPaste(resourceTagsTextbox); + resourceTagsTextbox.sendKeys(Keys.ENTER); + } + + public static void defineCategory(String category) { + GeneralUIUtils.getSelectList(category, getCategoryDataTestsIdAttribute()); + } + + public static String getContactIdText() { + return getContactIdField().getAttribute("value"); + } + + public static void defineContactId(String userId) { + WebElement contactIdTextbox = getContactIdField(); + contactIdTextbox.clear(); + contactIdTextbox.sendKeys(userId); + GeneralUIUtils.waitForLoader(); + } + + public static List getElementsFromTagsTable(){ + return GeneralUIUtils.getWebElementsListByTestID(DataTestIdEnum.ResourceMetadataEnum.TAGS_TABLE.getValue()); + } + + public static void defineTextBoxWithPaste(WebElement textBox) { + textBox.clear(); + textBox.sendKeys(Keys.CONTROL + "v"); + GeneralUIUtils.ultimateWait(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ResourceLeftMenu.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ResourceLeftMenu.java new file mode 100644 index 0000000000..a128aefdc8 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ResourceLeftMenu.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.StepsEnum; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; + +public class ResourceLeftMenu implements ComponentLeftMenu { + + public void moveToGeneralScreen() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.GENERAL); + } + + public void moveToIconScreen() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.ICON); + } + + public void moveToDeploymentArtifactScreen() { + GeneralUIUtils.moveToStep(StepsEnum.DEPLOYMENT_ARTIFACT); + } + + public void moveToInformationalArtifactScreen() { + GeneralUIUtils.moveToStep(StepsEnum.INFORMATION_ARTIFACT); + } + + public void moveToPropertiesScreen() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.PROPERTIES); + } + + public void moveToCompositionScreen() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.COMPOSITION); + } + + public void moveToActivityLogScreen() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.ACTIVITY_LOG); + } + + public void moveToDeploymentViewScreen() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.DEPLOYMENT_VIEW); + } + + public void moveToToscaArtifactsScreen() { + GeneralUIUtils.moveToStep(StepsEnum.TOSCA_ARTIFACTS); + } + + public void moveToInputsScreen() { + GeneralUIUtils.moveToStep(StepsEnum.INPUTS); + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ServiceGeneralPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ServiceGeneralPage.java new file mode 100644 index 0000000000..0394978261 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ServiceGeneralPage.java @@ -0,0 +1,114 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.util.ArrayList; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.aventstack.extentreports.Status; + +public class ServiceGeneralPage extends ResourceGeneralPage { + + public ServiceGeneralPage() { + super(); + } + + public static ServiceLeftMenu getServiceLeftMenu() { + return new ServiceLeftMenu(); + } + + public static void defineName(String serviceName) { + WebElement serviceNameTextbox = GeneralUIUtils + .getWebElementByTestID(DataTestIdEnum.ServiceMetadataEnum.SERVICE_NAME.getValue()); + serviceNameTextbox.clear(); + serviceNameTextbox.sendKeys(serviceName); + } + + public static void defineProjectCode(String pmat) { + WebElement projectCodeTextbox = GeneralUIUtils + .getWebElementByTestID(DataTestIdEnum.ServiceMetadataEnum.PROJECT_CODE.getValue()); + projectCodeTextbox.clear(); + projectCodeTextbox.sendKeys(pmat); + } + + public static String getProjectCodeText(){ + return getProjectCodeField().getAttribute("value"); + } + + public static String[] getTags(){ + return ResourceGeneralPage.getElementsFromTagsTable().stream().map(WebElement::getText).toArray(String[]::new); + } + + private static WebElement getProjectCodeField() { + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ServiceMetadataEnum.PROJECT_CODE.getValue()); + } + + public static void deleteOldTags(ServiceReqDetails service){ + // Delete tag elements + int i = GeneralUIUtils.getWebElementsListByTestID("i-sdc-tag-delete").size(); + while (i > 0){ + GeneralUIUtils.getWebElementByTestID("i-sdc-tag-delete").click(); + i--; + } + + service.setTags(new ArrayList()); + } + + public static String getCategoryText() { + return GeneralUIUtils.getSelectedElementFromDropDown(getCategoryDataTestsIdAttribute()).getText(); + } + + public static void clickAddWorkflow (){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Adding workflow...")); + GeneralUIUtils.clickOnElementByText("Add Workflow"); + } + + public static void fillAndAddNewWorkflow(String name, String description ) throws InterruptedException{ + GeneralUIUtils.ultimateWait(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Filling name field with %s", name)); + insertText(name, "label + input"); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Filling description filed with %s", name)); + insertText(description,"label + textarea"); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking save button ")); + clickSave(); + } + + public static void insertText(String artifactDescriptoin, String element) throws InterruptedException { + GeneralUIUtils.getElementsByCSS("div[class='modal-content']"); + WebElement artifactDescriptionTextbox = GeneralUIUtils.getWebElementBy(By.cssSelector(element)); + artifactDescriptionTextbox.clear(); + artifactDescriptionTextbox.sendKeys(artifactDescriptoin); + GeneralUIUtils.ultimateWait(); + } + + public static void clickSave() { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on Save button")); + GeneralUIUtils.clickOnElementByText("Save"); + GeneralUIUtils.ultimateWait(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ServiceLeftMenu.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ServiceLeftMenu.java new file mode 100644 index 0000000000..127ada2309 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ServiceLeftMenu.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.StepsEnum; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; + +public class ServiceLeftMenu implements ComponentLeftMenu { + + public void moveToManagmentWorkflow() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.MANAGEMENT_WORKFLOW); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/TesterOperationPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/TesterOperationPage.java new file mode 100644 index 0000000000..d9ef375d17 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/TesterOperationPage.java @@ -0,0 +1,101 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; + +import com.aventstack.extentreports.Status; + +public class TesterOperationPage { + + public TesterOperationPage() { + super(); + } + + public static void certifyComponent(String componentName) throws Exception{ + clickStartTestingButton(); + clickAccpetCertificationButton(componentName); + } + + public static void clickAccpetCertificationButton(String componentName) throws Exception { + ExtentTestActions.log(Status.INFO, "Accepting certifiction of " + componentName); + String actionDuration = GeneralUIUtils.getActionDuration(() -> + { + try { + clickAccpetCertificationButtonWithoutDuration(componentName); + } catch (Exception e) { + e.printStackTrace(); + } + }); + ExtentTestActions.log(Status.INFO, componentName + " is certifed", actionDuration); + + } + + public static void clickStartTestingButton() throws Exception{ + ExtentTestActions.log(Status.INFO, "Starting to test"); + String actionDuration = GeneralUIUtils.getActionDuration(() -> { + try { + clickStartTestingButtonWithoutDuration(); + } catch (Exception e) { + e.printStackTrace(); + } + }); + ExtentTestActions.log(Status.INFO, "Ready for certification", actionDuration); + } + + + private static void certifyComponentWithoutDuration(String componentName) throws Exception { + clickStartTestingButtonWithoutDuration(); + clickAccpetCertificationButtonWithoutDuration(componentName); + } + + + private static void clickAccpetCertificationButtonWithoutDuration(String componentName) throws Exception { + try{ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.LifeCyleChangeButtons.ACCEPT.getValue()); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.ACCEP_TESTING_MESSAGE.getValue()).sendKeys(componentName + " tested successfuly"); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ModalItems.OK.getValue()); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.sleep(2000); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtons.SEARCH_BOX.getValue()); + } + catch (Exception e){ + throw new Exception("Accepting certification of " + componentName + " falied"); + } + } + + private static void clickStartTestingButtonWithoutDuration() throws Exception { + try{ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.LifeCyleChangeButtons.START_TESTING.getValue()); +// GeneralUIUtils.ultimateWait(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.LifeCyleChangeButtons.ACCEPT.getValue()); +// GeneralUIUtils.ultimateWait(); +// GeneralUIUtils.sleep(1000); + } + catch (Exception e){ + throw new Exception("Start testing falied"); + } + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ToscaArtifactsPage.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ToscaArtifactsPage.java new file mode 100644 index 0000000000..077ccacde1 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/ToscaArtifactsPage.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.WebElement; + +public class ToscaArtifactsPage extends DeploymentArtifactPage { + + public ToscaArtifactsPage() { + + } + + public static String getArtifactName(int row){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ToscaArtifactsScreenEnum.ARTIFACT_NAME.getValue() + row).getText(); + } + + public static String getArtifactType(int row){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ToscaArtifactsScreenEnum.ARTIFACT_TYPE.getValue() + row).getText(); + } + + public static String getArtifactVersion(int row){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ToscaArtifactsScreenEnum.ARTIFACT_VERSION.getValue() + row).getText(); + } + + public static WebElement getArtifactDetails(int row){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ToscaArtifactsScreenEnum.ARTIFACT_DETAILS.getValue() + row); + } + + public static void downloadCsar() { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ToscaArtifactsScreenEnum.DOWNLOAD_CSAR.getValue()); + GeneralUIUtils.ultimateWait(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/UploadArtifactPopup.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/UploadArtifactPopup.java new file mode 100644 index 0000000000..e97f3feb62 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/pages/UploadArtifactPopup.java @@ -0,0 +1,126 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.pages; + +import java.io.File; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Select; +import org.testng.TestException; + +import com.aventstack.extentreports.Status; + +public class UploadArtifactPopup { + + boolean isCompositionPage; + + public UploadArtifactPopup(boolean isCompositionPage) { + super(); + this.isCompositionPage = isCompositionPage; + } + + public UploadArtifactPopup() { + super(); + } + + public WebElement getArtifactDescriptionWebElement(){ + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPopup.ARTIFACT_DESCRIPTION.getValue()); + } + + public void loadFile(String path, String filename) { + final WebElement browseWebElement = GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPopup.BROWSE.getValue()); +// browseWebElement.sendKeys(path + filename); + browseWebElement.sendKeys(path + File.separator + filename); + GeneralUIUtils.ultimateWait(); + +// if (!browseWebElement.getAttribute("value").equals(filename)) +// { +// throw new TestException("File named " + filename + " does not presented"); +// } + } + + + + public void insertDescription(String artifactDescriptoin) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Changing artifact description to: %s", artifactDescriptoin)); + WebElement artifactDescriptionTextbox = getArtifactDescriptionWebElement(); + artifactDescriptionTextbox.clear(); + artifactDescriptionTextbox.sendKeys(artifactDescriptoin); + + GeneralUIUtils.ultimateWait();; + } + + public Select defineArtifactLabel(String requiredArtifactLabel) { + Select selectList = null; + WebElement artifactLabelWebElement = null; + +// if (isCompositionPage){ + artifactLabelWebElement = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPopup.ARTIFACT_LABEL.getValue()); +// } +// else{ +// selectList = GeneralUIUtils.getSelectList("Create New Artifact", DataTestIdEnum.ArtifactPopup.ARTIFACT_LABEL.getValue()); +// artifactLabelWebElement = GeneralUIUtils.getDriver().findElement(By.name(DataTestIdEnum.ArtifactPopup.ARTIFACT_LABEL.getValue())); +// } + + artifactLabelWebElement.clear(); + artifactLabelWebElement.sendKeys(requiredArtifactLabel); + return selectList; + } + + public Select selectArtifactType(String artifactType) { + return GeneralUIUtils.getSelectList(artifactType, DataTestIdEnum.ArtifactPopup.ARTIFACT_TYPE.getValue()); + } + + public void clickDoneButton() throws Exception { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPopup.DONE_BUTTON.getValue()); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.waitForElementInVisibilityBy(By.className("sdc-add-artifact"), 10); + } + + public void clickCancelButton() throws Exception { + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPopup.CANCEL_BUTTON.getValue()).click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.waitForElementInVisibilityByTestId("sdc-add-artifact"); + } + +// public void clickUpdateButton() throws Exception { +// clickAddButton(); +// GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ArtifactPopup.UPDATE_BUTTON.getValue()).click(); +// GeneralUIUtils.waitForLoader(); +// GeneralUIUtils.waitForElementInVisibilityByTestId(By.className("sdc-add-artifact"), 50); +// } + + public void insertURL(String artifactDescriptoin) throws Exception { + WebElement artifactDescriptionTextbox = getArtifactURLWebElement(); + artifactDescriptionTextbox.clear(); + artifactDescriptionTextbox. sendKeys(artifactDescriptoin); + } + + public WebElement getArtifactURLWebElement(){ + return GeneralUIUtils.getWebElementBy(By.cssSelector((DataTestIdEnum.ArtifactPopup.URL.getValue()))); + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AdditionalConditions.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AdditionalConditions.java new file mode 100644 index 0000000000..aa260ecc80 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AdditionalConditions.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import java.util.concurrent.TimeUnit; + +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.paulhammant.ngwebdriver.NgWebDriver; + +public class AdditionalConditions { + + public static ExpectedCondition jQueryAJAXCallsHaveCompleted() { + return new ExpectedCondition() { + @Override + public Boolean apply(WebDriver driver) { + return (Boolean) ((JavascriptExecutor)driver). + executeScript("return (window.jQuery!= null) && (jQuery.active === 0);"); + } + }; + } + + public static ExpectedCondition angularHasFinishedProcessing() { + return new ExpectedCondition() { + @Override + public Boolean apply(WebDriver driver) { +// String scriptJS = "return (window.angular !==undefined) &&" +// + " (angular.element(document).injector() !==undefined) &&" +// + " (angular.element(document).injector().get('$http').pendingRequests.length === 0)"; +// return Boolean.valueOf(( (JavascriptExecutor) driver).executeScript(scriptJS).toString()); + new NgWebDriver((JavascriptExecutor) driver).waitForAngularRequestsToFinish(); + return true; + } + }; + } + + public static ExpectedCondition pageLoadWait() { + return new ExpectedCondition() { + @Override + public Boolean apply(WebDriver driver) { + String scriptJS = + "try {\r\n" + + " if (document.readyState !== 'complete') {\r\n" + + " return false; // Page not loaded yet\r\n" + + " }\r\n" + + " if (window.jQuery) {\r\n" + + " if (window.jQuery.active) {\r\n" + + " return false;\r\n" + + " } else if (window.jQuery.ajax && window.jQuery.ajax.active) {\r\n" + + " return false;\r\n" + + " }\r\n" + + " }\r\n" + + " if (window.angular) {\r\n" + + " if (!window.qa) {\r\n" + + " // Used to track the render cycle finish after loading is complete\r\n" + + " window.qa = {\r\n" + + " doneRendering: false\r\n" + + " };\r\n" + + " }\r\n" + + " // Get the angular injector for this app (change element if necessary)\r\n" + + " var injector = window.angular.element('body').injector();\r\n" + + " // Store providers to use for these checks\r\n" + + " var $rootScope = injector.get('$rootScope');\r\n" + + " var $http = injector.get('$http');\r\n" + + " var $timeout = injector.get('$timeout');\r\n" + + " // Check if digest\r\n" + + " if ($rootScope.$$phase === '$apply' || $rootScope.$$phase === '$digest' || $http.pendingRequests.length !== 0) {\r\n" + + " window.qa.doneRendering = false;\r\n" + + " return false; // Angular digesting or loading data\r\n" + + " }\r\n" + + " if (!window.qa.doneRendering) {\r\n" + + " // Set timeout to mark angular rendering as finished\r\n" + + " $timeout(function() {\r\n" + + " window.qa.doneRendering = true;\r\n" + + " }, 0);\r\n" + + " return false;\r\n" + + " }\r\n" + + " }\r\n" + + " return true;\r\n" + + "} catch (ex) {\r\n" + + " return false;\r\n" + + "}"; + return Boolean.valueOf(( (JavascriptExecutor) driver).executeScript(scriptJS).toString()); + } + }; + } + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AdminWorkspaceUIUtilies.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AdminWorkspaceUIUtilies.java new file mode 100644 index 0000000000..db621f3355 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AdminWorkspaceUIUtilies.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.pages.AdminGeneralPage; + +public class AdminWorkspaceUIUtilies { + + + public static void createNewUser(String userId, UserRoleEnum userRole){ + AdminGeneralPage.getUserManagementTab().setNewUserBox(userId); + AdminGeneralPage.getUserManagementTab().selectUserRole(userRole); + AdminGeneralPage.getUserManagementTab().clickCreateButton(); +// AdminWorkspaceUIUtilies.highlightNewRow(); + } + + private static void highlightNewRow(){ + GeneralUIUtils.HighlightMyElement(AdminGeneralPage.getUserManagementTab().getRow(0)); + } + + public static void updateUserRole(int rowIndx, UserRoleEnum userRole) { + AdminGeneralPage.getUserManagementTab().updateUser(rowIndx); + AdminGeneralPage.getUserManagementTab().updateUserRole(userRole, rowIndx); + AdminGeneralPage.getUserManagementTab().saveAfterUpdateUser(rowIndx); + } + + public static void deleteFirstRow(){ + AdminGeneralPage.getUserManagementTab().deleteUser(0); + } + + public static void searchForUser(String searchString){ + AdminGeneralPage.getUserManagementTab().searchUser(searchString); + } + + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ArtifactUIUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ArtifactUIUtils.java new file mode 100644 index 0000000000..d55ace4374 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ArtifactUIUtils.java @@ -0,0 +1,638 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.awt.AWTException; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.datatransfer.StringSelection; +import java.awt.event.KeyEvent; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.datatypes.elements.HeatParameterDataDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactInfo; +import org.openecomp.sdc.ci.tests.datatypes.ArtifactReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.InformationalArtifactsPlaceholders; +import org.openecomp.sdc.ci.tests.datatypes.HeatWithParametersDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ArtifactTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.InformationalArtifactPage; +import org.openecomp.sdc.ci.tests.pages.UploadArtifactPopup; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.Assert; + +import com.aventstack.extentreports.Status; + +public final class ArtifactUIUtils { + + private static final String PARAMETERS = "parameters"; + + private ArtifactUIUtils() { + } + + public static void fillAndAddNewArtifactParameters(ArtifactInfo artifactInfo) throws Exception { + UploadArtifactPopup artifactPopup = new UploadArtifactPopup(); + fillAndAddNewArtifactParameters(artifactInfo, artifactPopup); +// artifactPopup.defineArtifactLabel(artifactInfo.getArtifactLabel()); +// artifactPopup.selectArtifactType(artifactInfo.getArtifactType()); +// artifactPopup.insertDescription(artifactInfo.getDescription()); +// artifactPopup.loadFile(artifactInfo.getFilepath(), artifactInfo.getFilename()); +// artifactPopup.clickAddButton(); + } + + public static void fillAndAddNewArtifactParameters(ArtifactInfo artifactInfo, UploadArtifactPopup artifactPopup) throws Exception { + artifactPopup.defineArtifactLabel(artifactInfo.getArtifactLabel()); + artifactPopup.selectArtifactType(artifactInfo.getArtifactType()); + artifactPopup.insertDescription(artifactInfo.getDescription()); + artifactPopup.loadFile(artifactInfo.getFilepath(), artifactInfo.getFilename()); + artifactPopup.clickDoneButton(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("A new artifact of type %s was added", artifactInfo.getArtifactType())); + } + + public static void fillAndAddNewEnvArtifactParameters(ArtifactInfo artifactInfo, UploadArtifactPopup artifactPopup) throws Exception { + artifactPopup.insertDescription(artifactInfo.getDescription()); + artifactPopup.loadFile(artifactInfo.getFilepath(), artifactInfo.getFilename()); + artifactPopup.clickDoneButton(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("ENV parameters %s artifact updated ", artifactInfo.getArtifactType())); + } + + public static void fillPlaceHolderInformationalArtifact(DataTestIdEnum.InformationalArtifactsPlaceholders artifactLabel,String filepath, String filename, String description) throws Exception { + GeneralUIUtils.clickOnElementByTestId(artifactLabel.getValue()); + InformationalArtifactPage.artifactPopup().loadFile(filepath, filename); + InformationalArtifactPage.artifactPopup().insertDescription(description); + InformationalArtifactPage.artifactPopup().clickDoneButton(); + } + + public static void fillPlaceHolderInformationalArtifact(DataTestIdEnum.InformationalArtifactsService artifactLabel, + String filepath, String filename, String description) throws Exception { + GeneralUIUtils.clickOnElementByTestId(artifactLabel.getValue()); + UploadArtifactPopup artifactPopup = new UploadArtifactPopup(true); + artifactPopup.loadFile(filepath, filename); + artifactPopup.insertDescription(description); + artifactPopup.clickDoneButton(); + } + + public static void fillPlaceHolderAPIArtifact(DataTestIdEnum.APIArtifactsService artifactLabel, + String filepath, String filename, String description, String url) throws Exception { + GeneralUIUtils.clickOnElementByTestId(artifactLabel.getValue()); + UploadArtifactPopup artifactPopup = new UploadArtifactPopup(true); + artifactPopup.loadFile(filepath, filename); + artifactPopup.insertURL(url); + artifactPopup.insertDescription(description); + artifactPopup.clickDoneButton(); + } + + public static RestResponse deploymentArtifactResourceInUI(ResourceReqDetails resource, User user, + ArtifactReqDetails artifact, String file) throws Exception { + Thread.sleep(1000); + + List listFormInput = GeneralUIUtils.getDriver() + .findElements(By.className("i-sdc-designer-sidebar-tab")); + WebElement addArtifactElement = listFormInput.get(2); + addArtifactElement.click(); + + WebElement addArtifact = GeneralUIUtils.getDriver() + .findElement(By.className("i-sdc-designer-sidebar-section-content-item-artifact-details-name")); + addArtifact.click(); + + Thread.sleep(1000); + WebElement descriptionProperty = GeneralUIUtils.getDriver().findElement(By.className("i-sdc-form-textarea")); + descriptionProperty.clear(); + descriptionProperty.sendKeys(artifact.getDescription()); + + WebElement uploadFile = GeneralUIUtils.getDriver().findElement(By.className("i-sdc-form-label-upload")); + uploadFile.click(); + + StringSelection sel = new StringSelection(file); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, null); + // System.out.println("selection" + sel); + Thread.sleep(1000); + + Robot robot = new Robot(); + Thread.sleep(1000); + + Thread.sleep(2000); + + robot.keyPress(KeyEvent.VK_ENTER); + + // Release Enter + robot.keyRelease(KeyEvent.VK_ENTER); + + // Press CTRL+V + robot.keyPress(KeyEvent.VK_CONTROL); + robot.keyPress(KeyEvent.VK_V); + + // Release CTRL+V + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.keyRelease(KeyEvent.VK_V); + Thread.sleep(1000); + + // Press Enter + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + Thread.sleep(3000); + + WebElement clickDone = GeneralUIUtils.getDriver().findElement(By.className("w-sdc-form-action")); + clickDone.click(); + + Thread.sleep(3500); + + GeneralUIUtils.getDriver().findElement(By.cssSelector("button[data-ng-click^=save]")).click(); + + RestResponse getResource = RestCDUtils.getResource(resource, user); + assertEquals("Did not succeed to get resource after create", 200, getResource.getErrorCode().intValue()); + return getResource; + } + + public static void addInformationArtifact(ArtifactReqDetails artifact, String filePath, + final InformationalArtifactsPlaceholders dataTestEnum) throws Exception { + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.sleep(2000); + GeneralUIUtils.getWebElementByTestID(dataTestEnum.getValue()).click(); + +// final WebElement browseWebElement = GeneralUIUtils.retryMethodOnException( +// () -> GeneralUIUtils.getWebElementByDataTestId(DataTestIdEnum.ModalItems.BROWSE_BUTTON.getValue())); + + WebElement browseWebElement = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.BROWSE_BUTTON.getValue()); + browseWebElement.sendKeys(filePath); + + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.DESCRIPTION.getValue()) + .sendKeys(artifact.getDescription()); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.ADD.getValue()).click(); + + } + + private static void addFileToWindowBrowse(String file) throws InterruptedException, AWTException { + StringSelection sel = new StringSelection(file); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, null); + // System.out.println("selection" + sel); + Thread.sleep(1000); + + Robot robot = new Robot(); + + robot.keyPress(KeyEvent.VK_ENTER); + + // Release Enter + robot.keyRelease(KeyEvent.VK_ENTER); + + // Press CTRL+V + robot.keyPress(KeyEvent.VK_CONTROL); + robot.keyPress(KeyEvent.VK_V); + + // Release CTRL+V + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.keyRelease(KeyEvent.VK_V); + Thread.sleep(1000); + + // Press Enter + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + Thread.sleep(3000); + } + + static WebElement ArtifactLabel; + + public static Map addInformationalArtifact(String artifactLabel) throws Exception { + String type = GeneralUIUtils.getSelectList(null, "artifacttype").getFirstSelectedOption().getText(); + Map artifactValues = new HashMap(); + String labelName = GeneralUIUtils.getSelectList(artifactLabel, "selectArtifact").getFirstSelectedOption() + .getText(); + ArtifactLabel = GeneralUIUtils.getDriver().findElement(By.name("artifactLabel")); + if (ArtifactLabel.getAttribute("value").equals("")) { + labelName = "New-Test-Artifact"; + ArtifactLabel.sendKeys(labelName); + type = GeneralUIUtils.getSelectList("HEAT", "artifacttype").getFirstSelectedOption().getText(); + } + String description = "This is Description"; + String fileName = "Heat-File.yaml"; + GeneralUIUtils.setWebElementByTestId("description", "description"); + ResourceUIUtils.importFileWithSendKeyBrowse(ImportAssetUIUtils.FILE_PATH, fileName); + GeneralUIUtils.getWebElementByTestID("Add").click(); + GeneralUIUtils.getWebElementByTestID(labelName); + + artifactValues.put("type", type); + artifactValues.put("description", description); + artifactValues.put("name", labelName); + artifactValues.put("fileName", fileName); + return artifactValues; + } + + public static Map addDeploymentArtifact(String artifactLabel, String artifactType, String fileName) + throws Exception { + String type = null; + String labelName; + Map artifactValues = new HashMap(); + try { + labelName = GeneralUIUtils.getSelectList(artifactLabel, "selectArtifact").getOptions().get(1).getText(); + GeneralUIUtils.getSelectList(artifactLabel, "selectArtifact").selectByVisibleText(labelName); + } catch (Exception e) { + labelName = GeneralUIUtils.getWebElementByClassName(artifactLabel).getText(); + } + ArtifactLabel = GeneralUIUtils.getDriver().findElement(By.name("artifactLabel")); + if (ArtifactLabel.getText().equals("")) { + labelName = "New-Test-Artifact"; + ArtifactLabel.sendKeys(labelName); + type = GeneralUIUtils.getSelectList(artifactType, "artifacttype").getFirstSelectedOption().getText(); + } + String description = "This is Description"; + GeneralUIUtils.setWebElementByTestId("description", "description" ); + ResourceUIUtils.importFileWithSendKeyBrowse(ImportAssetUIUtils.FILE_PATH, fileName); + try { + GeneralUIUtils.getWebElementByTestID("Add").click(); + } catch (Exception e) { + GeneralUIUtils.getWebElementByClassName("w-sdc-form-action add-property").click(); + } + + artifactValues.put("type", artifactType); + artifactValues.put("description", description); + artifactValues.put("name", labelName); + artifactValues.put("fileName", fileName); + return artifactValues; + } + + + public static Map addDeploymentArtifactFromCanvas(String artifactLabel) throws Exception { + String type = null; + Map artifactValues = new HashMap(); + String labelName = GeneralUIUtils.getSelectList(artifactLabel, "selectArtifact").getFirstSelectedOption() + .getText(); + ArtifactLabel = GeneralUIUtils.getDriver().findElement(By.name("artifactLabel")); + if (ArtifactLabel.getText().equals("")) { + labelName = "New-Test-Artifact"; + ArtifactLabel.sendKeys(labelName); + type = GeneralUIUtils.getSelectList("OTHER", "artifacttype").getFirstSelectedOption().getText(); + } + String description = "This is Description"; + String filePath = "C:\\Git_work\\ASDC\\d2-sdnc\\ui-ci\\src\\main\\resources\\Files\\"; + String fileName = "Heat-File.yaml"; + GeneralUIUtils.setWebElementByTestId("description", "description"); + ResourceUIUtils.importFileWithSendKeyBrowse(filePath, fileName); + GeneralUIUtils.getWebElementByTestID("Add").click(); + artifactValues.put("type", type); + artifactValues.put("description", description); + artifactValues.put("name", labelName); + artifactValues.put("fileName", fileName); + return artifactValues; + } + + public static Map valideArtifact(Map artifactValues, Boolean condition) + throws Exception { + if (condition) { + GeneralUIUtils.getWebElementByClassName("table-edit-btn").click(); + } else { + System.out.println(artifactValues.get("name")); + GeneralUIUtils.getWebElementByTestID("edit_" + artifactValues.get("name")).click(); + } + Thread.sleep(1000); + String labelname = GeneralUIUtils.getWebElementByClassName("artifactLabel").getAttribute("value"); + String filename = GeneralUIUtils.getWebElementByTestID("filename").getText(); + String description = GeneralUIUtils.getWebElementByTestID("description").getAttribute("value"); + String type = GeneralUIUtils.getSelectList(null, "artifacttype").getFirstSelectedOption().getText(); + labelname.compareToIgnoreCase(artifactValues.get("name").replaceAll("-", "")); + assertEquals(filename, artifactValues.get("fileName").replaceAll(" ", "-")); + assertEquals(type, artifactValues.get("type")); + assertEquals(description, artifactValues.get("description")); + GeneralUIUtils.getWebElementByTestID("Update").click(); + return artifactValues; + } + + public static void valideArtifactFromCanvas(Map artifactValues) throws Exception { + GeneralUIUtils.getWebElementByTestID("artifactDisplayName-" + artifactValues.get("name")).click(); + Thread.sleep(1000); + String labelname = GeneralUIUtils.getWebElementByClassName("artifactLabel").getAttribute("value"); + String filename = GeneralUIUtils.getWebElementByTestID("filename").getText(); + String description = GeneralUIUtils.getWebElementByTestID("description").getAttribute("value"); + String type = GeneralUIUtils.getSelectList(null, "artifacttype").getFirstSelectedOption().getText(); + labelname.compareToIgnoreCase(artifactValues.get("name").replaceAll("-", "")); + assertEquals(filename, artifactValues.get("fileName")); + assertEquals(type, artifactValues.get("type")); + assertEquals(description, artifactValues.get("description")); + } + + public static Map> getArtifactsListFromResponse(String jsonResponse, + String fieldOfArtifactList) { + JSONObject object = (JSONObject) JSONValue.parse(jsonResponse); + Map> map = (Map>) object.get(fieldOfArtifactList); + return map; + } + + public static void validateArtifactNameVersionType(String artifactLabel, String artifactVersion, String artifactType) { +// Assert.assertEquals(GeneralUIUtils.getDriver().findElement(By.xpath("//*[@data-tests-id='" + DataTestIdEnum.ArtifactPageEnum.ARTIFACT_NAME.getValue() + artifactLabel + "']")).getAttribute("textContent").trim(), artifactLabel); + if(!GeneralUIUtils.getDriver().findElement(By.xpath("//*[@data-tests-id='" + DataTestIdEnum.ArtifactPageEnum.ARTIFACT_NAME.getValue() + artifactLabel + "']")).getAttribute("textContent").trim().equals(artifactLabel)) { + SetupCDTest.getExtendTest().log(Status.WARNING, "Artifact label not equal - this warnning represent defect."); + } + if(artifactVersion != null) { +// Assert.assertEquals(GeneralUIUtils.getDriver().findElement(By.xpath("//*[@data-tests-id='" + DataTestIdEnum.ArtifactPageEnum.VERSION.getValue() + artifactLabel + "']")).getAttribute("textContent").trim(), artifactVersion, "Artifact version not equal."); + if(!GeneralUIUtils.getDriver().findElement(By.xpath("//*[@data-tests-id='" + DataTestIdEnum.ArtifactPageEnum.VERSION.getValue() + artifactLabel + "']")).getAttribute("textContent").trim().equals(artifactVersion)) { + SetupCDTest.getExtendTest().log(Status.WARNING, "Artifact version not equal - this warnning represent defect."); + } + } + if(artifactType != null) { +// Assert.assertEquals(GeneralUIUtils.getDriver().findElement(By.xpath("//*[@data-tests-id='" + DataTestIdEnum.ArtifactPageEnum.TYPE.getValue() + artifactLabel + "']")).getAttribute("textContent").trim(), artifactType, "Artifact type not equal."); + if(!GeneralUIUtils.getDriver().findElement(By.xpath("//*[@data-tests-id='" + DataTestIdEnum.ArtifactPageEnum.TYPE.getValue() + artifactLabel + "']")).getAttribute("textContent").trim().equals(artifactType)) { + SetupCDTest.getExtendTest().log(Status.WARNING, "Artifact type not equal - this warnning represent defect."); + } + } + } + + public static void validateArtifactVersionByTypeAndLabel(String artifactLabel, String expectedArtifactVersion, ArtifactTypeEnum artifactType) { + if(expectedArtifactVersion != null) { + String xPath; + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Going to validate artifact version ...")); + if(artifactType.getType().equals(ArtifactTypeEnum.HEAT_ENV.getType())){ + xPath = "//*[@data-tests-id='" + DataTestIdEnum.ArtifactPageEnum.VERSION_ENV.getValue() + artifactLabel + "']"; + }else{ + xPath = "//*[@data-tests-id='" + DataTestIdEnum.ArtifactPageEnum.VERSION.getValue() + artifactLabel + "']"; + } + String actualartifactVersion = GeneralUIUtils.getDriver().findElement(By.xpath(xPath)).getAttribute("textContent").trim(); + Assert.assertEquals(actualartifactVersion, expectedArtifactVersion, "Artifact type " + artifactType.getType() + " expected version is " + expectedArtifactVersion + " not equal to " + actualartifactVersion); + } + } + + public static void validateExistArtifactOnDeploymentInformationPage(String expectedArtifactLabel, String artifactUUID, String artifactVersion, String artifactType, boolean isDownloadable, boolean isEditable, boolean isDeletable, boolean isArtifactParametersEditable) { + + String dataTestId = DataTestIdEnum.ArtifactPageEnum.ARTIFACT_NAME.getValue() + expectedArtifactLabel; + + List artifactElements = GeneralUIUtils.getWebElementsListByContainTestID(dataTestId); + Assert.assertEquals(artifactElements.size(), 1, "There are more then one artifact named " + expectedArtifactLabel); + + WebElement artifact = artifactElements.get(0); + String actualArtifactLabel = GeneralUIUtils.getTextContentAttributeValue(artifact).trim(); + Assert.assertEquals(actualArtifactLabel, expectedArtifactLabel); + + if(artifactUUID != null) { + WebElement uuid = GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.UUID.getValue() + expectedArtifactLabel); + Assert.assertEquals(GeneralUIUtils.getTextContentAttributeValue(uuid).trim(), artifactUUID, "Artifact uuid not equal."); + } + if(artifactVersion != null) { + WebElement version = GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.VERSION.getValue() + expectedArtifactLabel); + Assert.assertEquals(GeneralUIUtils.getTextContentAttributeValue(version).trim(), artifactVersion, "Artifact version not equal."); + } + if(artifactType != null) { + WebElement type = GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.TYPE.getValue() + expectedArtifactLabel); + Assert.assertEquals(GeneralUIUtils.getTextContentAttributeValue(type).trim(), artifactType, "Artifact type not equal."); + } + if(isArtifactParametersEditable) { + Assert.assertNotNull(GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.EDIT_PARAMETERS_OF_ARTIFACT.getValue() + expectedArtifactLabel), "Expect that parameters edit button enabled."); + } else if(isArtifactParametersEditable==false) { + Assert.assertNull(GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.EDIT_PARAMETERS_OF_ARTIFACT.getValue() + expectedArtifactLabel), "Expect that parameters edit button disabled."); + } + if(isDownloadable) { + Assert.assertNotNull(GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT.getValue() + expectedArtifactLabel), "Expect that download button enabled."); + } else if(isDownloadable==false) { + Assert.assertNull(GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT.getValue() + expectedArtifactLabel), "Expect that download button disabled."); + } + if(isEditable) { + Assert.assertNotNull(GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.EDIT_ARTIFACT.getValue() + expectedArtifactLabel), "Expect that edit button enabled."); + } else if(isEditable==false) { + Assert.assertNull(GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.EDIT_ARTIFACT.getValue() + expectedArtifactLabel), "Expect that edit button disabled."); + } + if(isDeletable) { + Assert.assertNotNull(GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.DELETE_ARTIFACT.getValue() + expectedArtifactLabel), "Expect that delete button enabled."); + } else if(isDeletable==false) { + Assert.assertNull(GeneralUIUtils.getInputElement(DataTestIdEnum.ArtifactPageEnum.DELETE_ARTIFACT.getValue() + expectedArtifactLabel), "Expect that delete button disabled."); + } + } + + public static void validateNotExistArtifactOnDeploymentInformationPage(String artifactLabel) { + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.ArtifactPageEnum.ARTIFACT_NAME.getValue() + artifactLabel), false); + } + + public static void validateExistArtifactOnCompositionRightMenuDeploymentInformationPage(String fileName, String artifactDisplayedName, + boolean isUpdateable, boolean isParametersEditable, boolean isDownloadable, boolean isDeleteable) { + Assert.assertEquals(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_NAME.getValue() + artifactDisplayedName).getText(), fileName); + Assert.assertEquals(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_DISPLAY_NAME.getValue() + artifactDisplayedName).getText(), artifactDisplayedName); + + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_DISPLAY_NAME.getValue() + artifactDisplayedName); + + if(isParametersEditable) { + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.EDIT_PARAMETERS_OF_ARTIFACT.getValue() + artifactDisplayedName), true, "Expect that parameters edit button enabled."); + } else { + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.EDIT_PARAMETERS_OF_ARTIFACT.getValue() + artifactDisplayedName), false, "Expect that parameters edit button disabled."); + } + if(isDownloadable) { + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DOWNLOAD.getValue() + artifactDisplayedName), true, "Expect that download button enabled."); + } else { + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DOWNLOAD.getValue() + artifactDisplayedName), false, "Expect that download button disabled."); + } + if(isDeleteable) { + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DELETE.getValue() + artifactDisplayedName), true, "Expect that delete button enabled."); + } else { + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.DELETE.getValue() + artifactDisplayedName), false, "Expect that delete button disabled."); + } + if(isUpdateable) { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_DISPLAY_NAME.getValue() + artifactDisplayedName); + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.ArtifactPopup.MODAL_WINDOW.getValue()), true, "Expect that edit button enabled."); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPopup.DONE_BUTTON.getValue()); + GeneralUIUtils.waitForElementInVisibilityByTestId(DataTestIdEnum.ArtifactPopup.DONE_BUTTON.getValue()); + } else { + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_DISPLAY_NAME.getValue() + artifactDisplayedName); + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.ArtifactPopup.MODAL_WINDOW.getValue()), false, "Expect that edit button disabled."); + } + + } + + public static void validateNotExistArtifactOnCompositionRightMenuDeploymentInformationPage(String artifactDisplayedName) { + Assert.assertEquals(GeneralUIUtils.isWebElementExistByTestId(DataTestIdEnum.DeploymentArtifactCompositionRightMenu.ARTIFACT_NAME.getValue() + artifactDisplayedName), false); + } + + public static File verifyUpdatedEnvParameters(HeatWithParametersDefinition pairToUpdate, File updateEnvFile, String dataTestId) throws Exception { + GeneralUIUtils.hoverOnAreaByTestId(dataTestId); + return verifyUpdatedEnvParameters(pairToUpdate, updateEnvFile); + } + + public static File verifyUpdatedEnvParameters(HeatWithParametersDefinition pairToUpdate, File updateEnvFile) throws Exception { + + String heatDisplayName = pairToUpdate.getHeatArtifactDisplayName(); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ArtifactPageEnum.DOWNLOAD_ARTIFACT_ENV.getValue()+heatDisplayName); + File latestFilefromDir = FileHandling.getLastModifiedFileFromDir(); + + String pattern = PARAMETERS; + Map mapUpdetedEnvFile = FileHandling.parseYamlFileToMapByPattern(updateEnvFile, pattern); + Map mapDownloadedEnvFile = FileHandling.parseYamlFileToMapByPattern(latestFilefromDir, pattern); + + SetupCDTest.getExtendTest().log(Status.INFO, "Going to check, that ENV file was updated ..."); + assertTrue("File" + latestFilefromDir.getName() + " contains different parameters number from expected file", mapDownloadedEnvFile.size() == mapUpdetedEnvFile.size()); + assertTrue("Updated file contains not updated parameters value", mapDownloadedEnvFile.entrySet().containsAll(mapUpdetedEnvFile.entrySet())); + return latestFilefromDir; + } + + /** + * compare heat env files by pattern ("parameters") + * @param expectedFile + * @param actualFile + * @param pattern + * @throws Exception + */ + public static void compareYamlFilesByPattern(File expectedFile, File actualFile, String pattern) throws Exception { + + Map mapExpectedFile = FileHandling.parseYamlFileToMapByPattern(expectedFile, pattern); + Map mapActualFile = FileHandling.parseYamlFileToMapByPattern(actualFile, pattern); + SetupCDTest.getExtendTest().log(Status.INFO, "Going to compare files ..."); + assertTrue("File" + actualFile.getName() + " contains different parameters number from expected file", mapActualFile.size() == mapExpectedFile.size()); + assertTrue("File " + actualFile.getName() + " does not contains all expected parametrs", mapActualFile.entrySet().containsAll(mapExpectedFile.entrySet())); + } + + public static void compareYamlParametersByPattern(Map mapExpectedproperties, File actualFileproperties, String pattern) throws Exception { + + Map mapActualFileProerties = FileHandling.parseYamlFileToMapByPattern(actualFileproperties, pattern); + SetupCDTest.getExtendTest().log(Status.INFO, "Going to compare files ..."); + assertTrue("Actual file contains different parameters number from expected file", mapActualFileProerties.size() == mapExpectedproperties.size()); + Map newMap = new HashMap<>(mapActualFileProerties); + assertTrue("Actual file does not contains all expected parametrs", newMap.entrySet().containsAll(mapExpectedproperties.entrySet())); + } + + + public static File uploadCreatedUpdateParametersEnvFile(HeatWithParametersDefinition heatEnvDetails, String directoryPath) throws Exception { +// created env file to upload + File pathToEnvParametersFile = prepareEnvParametersFile(heatEnvDetails, directoryPath); + ArtifactInfo heatEnvArtifactInfo = new ArtifactInfo(directoryPath, heatEnvDetails.getHeatEnvLabel()+".env", "heatEnvDesc", heatEnvDetails.getHeatEnvLabel(),heatEnvDetails.getHeatEnvArtifactType()); + ArtifactUIUtils.fillAndAddNewEnvArtifactParameters(heatEnvArtifactInfo, CompositionPage.artifactPopup()); + return pathToEnvParametersFile; + } + + public static File prepareEnvParametersFile(HeatWithParametersDefinition heatEnvDetails, String directoryPath) throws IOException { + File pathToEnvParametersFile = FileHandling.createEmptyFile(directoryPath+heatEnvDetails.getHeatEnvLabel()+".env"); +// fill file + FileHandling.writeToFile(pathToEnvParametersFile, "parameters:", 0); + for(HeatParameterDataDefinition paramDefinition : heatEnvDetails.getHeatParameterDefinition()){ + Object data = getDataToWrite(paramDefinition); + FileHandling.writeToFile(pathToEnvParametersFile, data, 2); + } + + return pathToEnvParametersFile; + } + + public static Object getDataToWrite(HeatParameterDataDefinition paramDefinition) { + Object data = ""; + switch (paramDefinition.getType()) { + case "string": + String text = "\"string\""; + data = getFormatedData(paramDefinition.getName(), text); + break; + case "number": + data = getFormatedData(paramDefinition.getName(), 666); + break; + case "json": + String jsonText = "{\"param1\":\"param1\", \"param2\":2}"; + data = getFormatedData(paramDefinition.getName(), jsonText); + break; + case "boolean": + if(paramDefinition.getCurrentValue().equals("true")){ + data = getFormatedData(paramDefinition.getName(), false); + }else{ + data = getFormatedData(paramDefinition.getName(), true); + } + break; + case "comma_delimited_list": + String commaDelimitedListText = "127.0.0.10, 127.0.0.15, 127.0.0.20"; + data = getFormatedData(paramDefinition.getName(), commaDelimitedListText); + break; + default: + break; + } + return data; + } + + + public static Map getDataToWriteInUI(List paramDefinitionFromGetResourceResponse) { + MapnewValuesToUpdateInUI=new HashMap<>(); + for (HeatParameterDataDefinition param : paramDefinitionFromGetResourceResponse) { + System.out.println(param.getCurrentValue()); + switch (param.getType()) { + + case "string": + String text = "string"; + newValuesToUpdateInUI.put(param.getName(),text); + break; + case "number": + newValuesToUpdateInUI.put(param.getName(),666); + break; + case "json": + String jsonText = "{\"param1\":\"param1\", \"param2\":2}"; + newValuesToUpdateInUI.put(param.getName(),jsonText); + break; + case "boolean": + if (param.getCurrentValue().equals(true)) { + newValuesToUpdateInUI.put(param.getName(),false); + } else { + newValuesToUpdateInUI.put(param.getName(),true); + } + break; + case "comma_delimited_list": + String commaDelimitedListText = "127.0.0.10, 127.0.0.15, 127.0.0.20"; + newValuesToUpdateInUI.put(param.getName(),commaDelimitedListText); + break; + default: + break; + + } + + } + return newValuesToUpdateInUI; + } + + public static Object getValue(HeatParameterDataDefinition param) { + String type = param.getType(); + Object result = null; + switch(type){ + case "string": + result = param.getCurrentValue(); + break; + case "number": + result = new Integer(param.getCurrentValue()); + break; + case "json": + result = param.getCurrentValue(); + break; + case "boolean": + result = new Boolean(param.getCurrentValue()); + break; + case "comma_delimited_list": + result = param.getCurrentValue(); + break; + default: + break; + } + return result; + } + + public static Object getFormatedData(String name, Object text) { + return name + ": " + text; +} + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AuditCDUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AuditCDUtils.java new file mode 100644 index 0000000000..c53fef596a --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/AuditCDUtils.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import org.codehaus.jettison.json.JSONObject; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.expected.ExpectedResourceAuditJavaObject; +import org.openecomp.sdc.ci.tests.utils.general.Convertor; +import org.openecomp.sdc.ci.tests.utils.validation.AuditValidationUtils; + +public class AuditCDUtils { + + public static void validateResourceSuccessAudit(ResourceReqDetails resource, User user, String action) + throws Exception { + JSONObject auditBody = AuditValidationUtils.filterAuditByUuid(action, resource.getUUID()); + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = Convertor + .constructFieldsForAuditValidation(resource, resource.getVersion(), user); + String auditAction = "Create"; + expectedResourceAuditJavaObject.setAction(auditAction); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, auditAction, auditBody.toString(), false); + } + + public static void validateServiceSuccessAudit(ServiceReqDetails service, User user, String action) + throws Exception { + validateServiceSuccessAudit(service, user, action, LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + } + + public static void validateServiceSuccessAudit(ServiceReqDetails service, User user, String action, + LifecycleStateEnum lifecycleStatus) throws Exception { + ExpectedResourceAuditJavaObject expectedResourceAuditJavaObject = AuditValidationUtils + .constructFieldsForAuditValidation(service, service.getVersion(), user); + String body = AuditValidationUtils.filterAuditByUuid(action, service.getUUID()).toString(); + expectedResourceAuditJavaObject.setAction(action); + expectedResourceAuditJavaObject.setPrevState(""); + expectedResourceAuditJavaObject.setPrevVersion(""); + expectedResourceAuditJavaObject.setCurrState(lifecycleStatus.toString()); + expectedResourceAuditJavaObject.setStatus("201"); + expectedResourceAuditJavaObject.setDesc("OK"); + AuditValidationUtils.validateAudit(expectedResourceAuditJavaObject, action, body, false); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CanvasElement.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CanvasElement.java new file mode 100644 index 0000000000..fbe8c04036 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CanvasElement.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.LeftPanelCanvasItems; +import org.openqa.selenium.WebElement; + +public final class CanvasElement { + private final String uniqueId; + private ImmutablePair location; + private WebElement elementType; + + CanvasElement(String name, ImmutablePair location, WebElement canvasItem) { + super(); + this.uniqueId = name; + this.location = location; + elementType = canvasItem; + } + + public String getUniqueId() { + return uniqueId; + } + + public ImmutablePair getLocation() { + return location; + } + + public void setLocation(ImmutablePair location) { + this.location = location; + } + + public WebElement getElementType() { + return elementType; + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CanvasManager.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CanvasManager.java new file mode 100644 index 0000000000..18cb338891 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CanvasManager.java @@ -0,0 +1,179 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +public final class CanvasManager { + private Map canvasElements; + private Actions actions; + private WebElement canvas; + private int reduceCanvasWidthFactor; + // Offsets Are used to find upper right corner of canvas element in order to + // connect links + private static final int CANVAS_ELEMENT_Y_OFFSET = 40; + private static final int CANVAS_ELEMENT_X_OFFSET = 21; // 14 - 27 + + private CanvasManager() { + canvasElements = new HashMap<>(); + actions = new Actions(GeneralUIUtils.getDriver()); + canvas = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralCanvasItems.CANVAS.getValue()); + try { + WebElement webElement = GeneralUIUtils + .getWebElementByTestID(DataTestIdEnum.GeneralCanvasItems.CANVAS_RIGHT_PANEL.getValue()); + reduceCanvasWidthFactor = webElement.getSize().width; + } catch (Exception e) { + reduceCanvasWidthFactor = 0; + } + } + + public static CanvasManager getCanvasManager() { + return new CanvasManager(); + } + + public List getCanvasElements() { + return canvasElements.values().stream().collect(Collectors.toList()); + } + + private void addCanvasElement(CanvasElement element) { + canvasElements.put(element.getUniqueId(), element); + } + + private void moveElementOnCanvas(CanvasElement canvasElement, ImmutablePair newLocation) + throws Exception { + GeneralUIUtils.waitForLoader(); + Thread.sleep(500); + actions.moveToElement(canvas, canvasElement.getLocation().left, canvasElement.getLocation().right); + actions.clickAndHold(); + actions.moveToElement(canvas, newLocation.left, newLocation.right); + actions.release(); + actions.perform(); + canvasElement.setLocation(newLocation); + GeneralUIUtils.waitForLoader(); + + } + + public void moveElementOnCanvas(CanvasElement canvasElement) throws Exception { + moveElementOnCanvas(canvasElement, getFreePosition()); + } + + public void deleteElementFromCanvas(CanvasElement canvasElement) throws Exception { + GeneralUIUtils.waitForLoader(); + actions.moveToElement(canvas, canvasElement.getLocation().left, canvasElement.getLocation().right); + actions.click(); + actions.perform(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralCanvasItems.DELETE_INSTANCE_BUTTON.getValue()) + .click(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ModalItems.OK.getValue()).click(); + canvasElements.remove(canvasElement.getUniqueId()); + GeneralUIUtils.waitForLoader(); + } + + private String getItemName(WebElement canvasItem) { + String canvasItemName = canvasItem.getAttribute("data-tests-id"); + + return canvasItemName.substring(canvasItemName.lastIndexOf("-")); + } + + public CanvasElement createElementOnCanvas(WebElement canvasItem) throws Exception { + GeneralUIUtils.waitForLoader(); + ImmutablePair freePosition = getFreePosition(); + actions.moveToElement(canvasItem, 0, 0); + actions.clickAndHold(); + actions.moveToElement(canvas, freePosition.left, freePosition.right); + actions.release(); + actions.perform(); + + String uniqueId = getItemName(canvasItem) + "_" + UUID.randomUUID().toString(); + CanvasElement canvasElement = new CanvasElement(uniqueId, freePosition, canvasItem); + addCanvasElement(canvasElement); + GeneralUIUtils.waitForLoader(); + return canvasElement; + } + + private ImmutablePair getFreePosition() { + // TODO mshitrit use better method + ImmutablePair randomPosition = null; + boolean freePosition = false; + int minSpace = 150; + while (!freePosition) { + ImmutablePair tempRandomPosition = getRandomPosition(); + freePosition = !canvasElements.values().stream().map(e -> e.getLocation()) + .filter(e -> Math.abs(e.left - tempRandomPosition.left) < minSpace + && Math.abs(e.right - tempRandomPosition.right) < minSpace) + .findAny().isPresent(); + randomPosition = tempRandomPosition; + } + return randomPosition; + } + + private ImmutablePair getRandomPosition() { + int edgeBuffer = 50; + Random random = new Random(); + int xElement = random.nextInt(canvas.getSize().width - 2 * edgeBuffer - reduceCanvasWidthFactor) + edgeBuffer; + int yElement = random.nextInt(canvas.getSize().height - 2 * edgeBuffer) + edgeBuffer; + return new ImmutablePair(xElement, yElement); + } + + public void linkElements(CanvasElement firstElement, CanvasElement secondElement) throws Exception { + GeneralUIUtils.waitForLoader(); + drawSimpleLink(firstElement, secondElement); + + selectReqAndCapAndConnect(); + + GeneralUIUtils.waitForLoader(); + + } + + private void selectReqAndCapAndConnect() { + // Select First Cap + GeneralUIUtils.getWebElementsListByTestID(DataTestIdEnum.LinkMenuItems.LINK_ITEM_CAP.getValue()).get(0).click(); + // Select First Req + GeneralUIUtils.getWebElementsListByTestID(DataTestIdEnum.LinkMenuItems.LINK_ITEM_REQ.getValue()).get(0).click(); + // Connect + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.LinkMenuItems.CONNECT_BUTTON.getValue()).click(); + } + + private void drawSimpleLink(CanvasElement firstElement, CanvasElement secondElement) { + + int yOffset = CANVAS_ELEMENT_Y_OFFSET; + int xOffset = CANVAS_ELEMENT_X_OFFSET; + + actions.moveToElement(canvas, firstElement.getLocation().left + xOffset, + firstElement.getLocation().right - yOffset); + + actions.clickAndHold(); + actions.moveToElement(canvas, secondElement.getLocation().left + xOffset, + secondElement.getLocation().right - yOffset); + actions.release(); + actions.perform(); + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CatalogUIUtilitis.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CatalogUIUtilitis.java new file mode 100644 index 0000000000..e9ba11f0f4 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/CatalogUIUtilitis.java @@ -0,0 +1,232 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.openecomp.sdc.ci.tests.datatypes.TopMenuButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.CheckBoxStatusEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.CatalogPageLeftPanelFilterTitle; +import org.openecomp.sdc.ci.tests.datatypes.TypesEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utils.rest.CatalogRestUtils; +import org.openqa.selenium.WebElement; +import org.testng.annotations.Test; + +import com.aventstack.extentreports.Status; + +public class CatalogUIUtilitis { + + + + + + // Get all Categories , Subcategories and Icons. + public void getAllCategoriesAndSubcategories() throws IOException, JSONException { + RestResponse allcategoriesJson = CatalogRestUtils.getAllCategoriesTowardsCatalogBe(); + JSONArray categories = new JSONArray(allcategoriesJson.getResponse()); + for (int i = 0; i < categories.length(); i++) { + String categoryname = (String) categories.getJSONObject(i).get("name"); + JSONArray subcategories = (JSONArray) categories.getJSONObject(i).get("subcategories"); + for (int j = 0; j < subcategories.length(); j++) { + String subcategoryname = (String) subcategories.getJSONObject(j).get("name"); + System.out.println(subcategoryname); + } + for (int j = 0; j < subcategories.length(); j++) { + JSONArray icons = (JSONArray) subcategories.getJSONObject(j).get("icons"); + for (int k = 0; k < icons.length(); k++) { + System.out.println(icons.get(k)); + } + } + System.out.println("-------------------------------"); + } + } + + @Test + // FOr testing---delete. + public static List abcd() throws IOException, JSONException { + RestResponse allcategoriesJson = CatalogRestUtils.getAllCategoriesTowardsCatalogBe(); + JSONArray categories = new JSONArray(allcategoriesJson.getResponse()); + List allcat = new ArrayList<>(); + String uniqueId = null; + for (int i = 0; i < categories.length(); i++) { + String categoryname = (String) categories.getJSONObject(i).get("name"); + uniqueId = (String) categories.getJSONObject(i).get("uniqueId"); + allcat.add(uniqueId); + JSONArray subcategories = (JSONArray) categories.getJSONObject(i).get("subcategories"); + for (int j = 0; j < subcategories.length(); j++) { + String subcategoryname = (String) subcategories.getJSONObject(j).get("name"); + uniqueId = (String) subcategories.getJSONObject(j).get("uniqueId"); + allcat.add(uniqueId); + } + } + return allcat; + + } + + public static void clickTopMenuButton(TopMenuButtonsEnum button) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s button ...", button.name())); + switch (button) { + case CATALOG: + GeneralUIUtils.getWebElementByTestID(button.getButton()).click(); + break; + case HOME: + GeneralUIUtils.getWebElementByTestID(button.getButton()).click(); + break; + case ON_BOARDING: + GeneralUIUtils.getWebElementByTestID(button.getButton()).click(); + break; + default: + break; + } + GeneralUIUtils.ultimateWait(); + } + + public static String catalogFilterTypeChecBox(TypesEnum enumtype) throws Exception { + String Type = enumtype.toString().toLowerCase(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s ...", Type)); + GeneralUIUtils.getWebElementByTestID(enumtype.getValue()).click(); + return Type; + } + + public static List catalogFilterStatusChecBox(CheckBoxStatusEnum statusEnum) throws Exception { + List status = null; + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s status", statusEnum.name())); + switch (statusEnum) { + case IN_DESIGN: + status = Arrays.asList("NOT_CERTIFIED_CHECKIN", "NOT_CERTIFIED_CHECKOUT"); + GeneralUIUtils.getWebElementByTestID(statusEnum.getCatalogValue()).click(); + break; + case READY_FOR_TESTING: + status = Arrays.asList("READY_FOR_CERTIFICATION"); + GeneralUIUtils.getWebElementByTestID(statusEnum.getCatalogValue()).click(); + break; + case IN_TESTING: + status = Arrays.asList("CERTIFICATION_IN_PROGRESS"); + GeneralUIUtils.getWebElementByTestID(statusEnum.getCatalogValue()).click(); + break; + case CERTIFIED: + status = Arrays.asList("CERTIFIED"); + GeneralUIUtils.getWebElementByTestID(statusEnum.getCatalogValue()).click(); + break; + case DISTRIBUTED: + status = Arrays.asList("CERTIFIED"); + GeneralUIUtils.getWebElementByTestID(statusEnum.getCatalogValue()).click(); + break; + } + return status; + } + + // Get all Categories uniqueID .//The parent categories. + public static List getCategories() throws IOException, JSONException { + List allCategoriesList = new ArrayList<>(); + RestResponse allcategoriesJson = CatalogRestUtils.getAllCategoriesTowardsCatalogBe(); + JSONArray categories = new JSONArray(allcategoriesJson.getResponse()); + for (int i = 0; i < categories.length(); i++) { + String categoryname = (String) categories.getJSONObject(i).get("name"); + System.out.println(categoryname); + allCategoriesList.add(categoryname); + } + return allCategoriesList; + } + + @Test + // Get Subcategories by Category name + public static List getAllSubcategoriesByUniqueId(String uniqueId) throws IOException, JSONException { + + RestResponse allcategoriesJson = CatalogRestUtils.getAllCategoriesTowardsCatalogBe(); + JSONArray categories = new JSONArray(allcategoriesJson.getResponse()); + List subCategories = new ArrayList<>();// subCategories to + // return. + JSONArray subcategories = null; + + for (int i = 0; i < categories.length(); i++) { + + String categoryuniqueId = (String) categories.getJSONObject(i).get("uniqueId"); + + if (categoryuniqueId.contentEquals(uniqueId)) { + subcategories = (JSONArray) categories.getJSONObject(i).get("subcategories"); + + for (int j = 0; j < subcategories.length(); j++) { + + subCategories.add((String) subcategories.getJSONObject(j).get("uniqueId")); + } + + break; + } + } + if (subcategories == null) { + subCategories.add(uniqueId); + } + return subCategories; + } + + @Test + // Get icons by category name + public void getSubCategoryIcons() throws IOException, JSONException { + RestResponse allcategoriesJson = CatalogRestUtils.getAllCategoriesTowardsCatalogBe(); + + JSONArray categories = new JSONArray(allcategoriesJson.getResponse()); + for (int i = 0; i < categories.length(); i++) { + String subcategoryname = (String) categories.getJSONObject(i).get("name"); + if (subcategoryname.contentEquals("Generic")) { + JSONArray subcategories = (JSONArray) categories.getJSONObject(i).get("subcategories"); + for (int j = 0; j < subcategories.length(); j++) { + JSONArray icons = (JSONArray) subcategories.getJSONObject(j).get("icons"); + for (int k = 0; k < icons.length(); k++) { + System.out.println(icons.get(k)); + } + } + break; + } + } + } + + + public static WebElement clickOnUpperCategoryCheckbox() throws InterruptedException { + List categorieCheckboxes = GeneralUIUtils.getElementsByCSS("span[data-tests-id*='category']"); // get all categories and subcategories + WebElement categorieCheckbox = categorieCheckboxes.get(0); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s category ...", categorieCheckbox.getText())); + categorieCheckbox.click(); + GeneralUIUtils.ultimateWait(); + return categorieCheckbox; + } + + public static void clickOnLeftPanelElement(DataTestIdEnum.CatalogPageLeftPanelFilterTitle leftPanelElement) throws InterruptedException { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s", leftPanelElement.name())); + GeneralUIUtils.getElementsByCSS(leftPanelElement.getValue()).forEach(WebElement::click); + } + + public static WebElement catalogSearchBox(String searchText) { + WebElement searchBox = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtons.SEARCH_BOX.getValue()); + searchBox.clear(); + searchBox.sendKeys(searchText); + return searchBox; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/DownloadManager.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/DownloadManager.java new file mode 100644 index 0000000000..08b392fcd6 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/DownloadManager.java @@ -0,0 +1,115 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import java.io.File; +import java.util.List; + +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.execute.setup.AttFtpClient; +import org.openecomp.sdc.ci.tests.execute.setup.DriverFactory; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +import com.aventstack.extentreports.Status; + +public class DownloadManager { + + + public File fetchDownloadedFile(){ + + File retrieveLastModifiedFileFromFTP = null; + + if (DriverFactory.getConfig().isRemoteTesting()){ + + + try { + + AttFtpClient instance = AttFtpClient.getInstance(); + AttFtpClient.getInstance().retrieveListOfFile(); + retrieveLastModifiedFileFromFTP = instance.retrieveLastModifiedFileFromFTP(); + + } catch (Exception e) { + System.out.println("could not retriev file"); + } + + return retrieveLastModifiedFileFromFTP; + + } + + + return retrieveLastModifiedFileFromFTP; + + } + + + /** + * this method download csar file from VSP repository to default browser download directory + * @param vspName + * @throws Exception + */ + public static void downloadCsarByNameFromVSPRepository(String vspName, String vspId) throws Exception{ + FileHandling.cleanCurrentDownloadDir(); + HomePage.showVspRepository(); + boolean vspFound = HomePage.searchForVSP(vspName); + if (vspFound){ + ExtentTestActions.log(Status.INFO, String.format("Going to downloading VSP %s", vspName)); + List elemenetsFromTable = HomePage.getElemenetsFromTable(); +// GeneralUIUtils.ultimateWait(); +// WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), 5); +// WebElement findElement = wait.until(ExpectedConditions.visibilityOf(elemenetsFromTable.get(1))); + elemenetsFromTable.get(1).click(); +// findElement.click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ImportVfRepository.DOWNLOAD_CSAR.getValue()); + ExtentTestActions.log(Status.INFO, "Succeeded to downloaded CSAR file named " + vspId + " into folder " + SetupCDTest.getWindowTest().getDownloadDirectory()); + GeneralUIUtils.getElementsByCSS("div[class^='w-sdc-modal-close']").forEach(e -> e.click()); + GeneralUIUtils.ultimateWait(); + } + } + +// AttFtpClient instance = AttFtpClient.getInstance(); +// +// String server = "135.177.130.113"; +// int port = 2121; +// String user = "admin"; +// String pass = "admin"; +// AttFtpClient.getInstance().init(server, port, user, pass); +// +// try { +// AttFtpClient.getInstance().retrieveListOfFile(); +// +// File retrieveLastModifiedFileFromFTP = instance.retrieveLastModifiedFileFromFTP(); +// String content = new String(Files.readAllBytes(Paths.get(retrieveLastModifiedFileFromFTP.getPath())), StandardCharsets.UTF_8); +//// instance.deleteFilesFromFTPserver(); +// System.out.println(content); +// readFile(retrieveLastModifiedFileFromFTP); +// +// } finally { +// instance.terminateClient(); +// } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/FileHandling.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/FileHandling.java new file mode 100644 index 0000000000..6008f200d2 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/FileHandling.java @@ -0,0 +1,505 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; + +import org.apache.commons.io.FileUtils; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.yaml.snakeyaml.Yaml; + +import com.aventstack.extentreports.Status; +import com.clearspring.analytics.util.Pair; + +public class FileHandling { + +// ------------------yaml parser methods---------------------------- + public static Map parseYamlFile(String filePath) throws Exception { + Yaml yaml = new Yaml(); + File file = new File(filePath); + InputStream inputStream = new FileInputStream(file); + Map map = (Map) yaml.load(inputStream); + return map; + } + + /** + * The method return map fetched objects by pattern from yaml file + * @param yamlFile + * @param pattern + * @return + * @throws Exception + */ + public static Map parseYamlFileToMapByPattern(File yamlFile, String pattern) throws Exception { + Map yamlFileToMap = FileHandling.parseYamlFile(yamlFile.toString()); + Map objectMap = getObjectMapByPattern(yamlFileToMap, pattern); + return objectMap; + } + + @SuppressWarnings("unchecked") + public static Map getObjectMapByPattern(Map parseUpdetedEnvFile, String pattern) { + Map objectMap = null; + + Object objectUpdetedEnvFile = parseUpdetedEnvFile.get(pattern); + if(objectUpdetedEnvFile instanceof HashMap){ + objectMap = (Map) objectUpdetedEnvFile; + } + return objectMap; + } + +// ------------------------------------------------------------------------------------------------- + + public static String getFilePath(String folder) { + String filepath = System.getProperty("filepath"); + if (filepath == null && System.getProperty("os.name").contains("Windows")) { + filepath = FileHandling.getResourcesFilesPath() + folder + File.separator; + } + + else if(filepath.isEmpty() && !System.getProperty("os.name").contains("Windows")){ + filepath = FileHandling.getBasePath() + "Files" + File.separator + folder + File.separator; + } + + System.out.println(filepath); + + return filepath; + } + + public static String getBasePath() { + return System.getProperty("user.dir") + File.separator; + } + + public static String getDriversPath() { + return getBasePath() + "src" + File.separator + "main" + File.separator + "resources" + + File.separator + "ci" + File.separator + "drivers" + File.separator; + } + + public static String getResourcesFilesPath() { + return getBasePath() + "src" + File.separator + "main" + File.separator + "resources" + + File.separator + "Files" + File.separator; + } + + public static String getResourcesEnvFilesPath() { + return getBasePath() + File.separator + "src" + File.separator + "main" + File.separator + "resources" + + File.separator + "Files" + File.separator + "ResourcesEnvFiles" +File.separator; + } + + public static String getCiFilesPath() { + return getBasePath() + "src" + File.separator + "main" + File.separator + "resources" + + File.separator + "ci"; + } + + public static String getConfFilesPath() { + return getCiFilesPath() + File.separator + "conf" + File.separator; + } + + public static String getTestSuitesFilesPath() { + return getCiFilesPath() + File.separator + "testSuites" + File.separator; + } + + public static String getVnfRepositoryPath() { + return getFilePath("VNFs"); + } + + public static File getConfigFile(String configFileName) throws Exception { + File configFile = new File(FileHandling.getBasePath() + File.separator + "conf" + File.separator + configFileName); + if (!configFile.exists()) { + configFile = new File(FileHandling.getConfFilesPath() + configFileName); + } + return configFile; + } + + public static Object[] filterFileNamesFromFolder(String filepath, String extension) { + try { + File dir = new File(filepath); + List filenames = new ArrayList(); + + FilenameFilter extensionFilter = new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.endsWith(extension); + } + }; + + if (dir.isDirectory()) { + for (File file : dir.listFiles(extensionFilter)) { + filenames.add(file.getName()); + } + return filenames.toArray(); + } + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static String[] getArtifactsFromZip(String filepath, String zipFilename){ + try{ + ZipFile zipFile = new ZipFile(filepath + File.separator + zipFilename); + Enumeration entries = zipFile.entries(); + + String[] artifactNames = new String[zipFile.size() - 1]; + + int i = 0; + while(entries.hasMoreElements()){ + ZipEntry nextElement = entries.nextElement(); + if (!nextElement.isDirectory()){ + if (!nextElement.getName().equals("MANIFEST.json")){ + String name = nextElement.getName(); + artifactNames[i++] = name; + } + } + } + zipFile.close(); + return artifactNames; + } + catch(ZipException zipEx){ + System.err.println("Error in zip file named : " + zipFilename); + zipEx.printStackTrace(); + } catch (IOException e) { + System.err.println("Unhandled exception : "); + e.printStackTrace(); + } + + return null; + + } + + public static Object[] getZipFileNamesFromFolder(String filepath) { + return filterFileNamesFromFolder(filepath, ".zip"); + } + + public static int countFilesInZipFile(String[] artifactsArr, String reqExtension){ + int fileCounter = 0; + for (String artifact : artifactsArr){ + String extensionFile = artifact.substring(artifact.lastIndexOf(".") + 1 , artifact.length()); + if (extensionFile.equals(reqExtension)){ + fileCounter++; + } + } + return fileCounter; + } + + + public static synchronized File getLastModifiedFileFromDir() throws Exception{ + return getLastModifiedFileFromDir(SetupCDTest.getWindowTest().getDownloadDirectory()); + } + + public static synchronized File getLastModifiedFileFromDir(String dirPath){ + File dir = new File(dirPath); + File[] files = dir.listFiles(); + if (files == null) { + assertTrue("File not found under directory " + dirPath, false); + return null; + } + + File lastModifiedFile = files[0]; + for (int i = 1; i < files.length; i++) { + if(files[i].isDirectory()) { + continue; + } + if (lastModifiedFile.lastModified() < files[i].lastModified()) { + lastModifiedFile = files[i]; + } + } + return lastModifiedFile; + } + + public static void deleteDirectory(String directoryPath) { + File dir = new File(directoryPath); + try { + FileUtils.deleteDirectory(dir); + } catch (IOException e) { + System.out.println("Failed to delete " + dir); + SetupCDTest.getExtendTest().log(Status.INFO, "Failed to delete " + dir); + } + } + + public static void createDirectory(String directoryPath) { + File directory = new File(String.valueOf(directoryPath)); + if (! directory.exists()){ + directory.mkdir(); + } + } + + + /** + * The method append data to existing file, if file not exists - create it + * @param pathToFile + * @param text + * @param leftSpaceCount + * @throws IOException + */ + public static synchronized void writeToFile(File pathToFile, Object text, Integer leftSpaceCount) throws IOException{ + + BufferedWriter bw = null; + FileWriter fw = null; + if(!pathToFile.exists()){ + createEmptyFile(pathToFile); + } + try { + fw = new FileWriter(pathToFile, true); + bw = new BufferedWriter(fw); + StringBuilder sb = new StringBuilder(); + if(leftSpaceCount > 0 ){ + for(int i = 0; i < leftSpaceCount; i++){ + sb.append(" "); + } + } + bw.write(sb.toString() + text); + bw.newLine(); + bw.close(); + fw.close(); + } catch (Exception e) { + SetupCDTest.getExtendTest().log(Status.INFO, "Unable to write to flie " + pathToFile); + } + } + + public static synchronized void writeToFile(File pathToFile, Map> dataMap, Integer leftSpaceCount) throws IOException{ + + BufferedWriter bw = null; + FileWriter fw = null; + try { + if(!pathToFile.exists()){ + createEmptyFile(pathToFile); + } + fw = new FileWriter(pathToFile, true); + bw = new BufferedWriter(fw); + StringBuilder sb = new StringBuilder(); + if(leftSpaceCount > 0 ){ + for(int i = 0; i < leftSpaceCount; i++){ + sb.append(" "); + } + } + for(Map.Entry> entry : dataMap.entrySet()){ + Object record = ArtifactUIUtils.getFormatedData(entry.getKey(), entry.getValue().right); + bw.write(sb.toString() + record); + bw.newLine(); + } + bw.close(); + fw.close(); + } catch (Exception e) { + SetupCDTest.getExtendTest().log(Status.INFO, "Unable to write to flie " + pathToFile); + } + } + + public static void deleteLastDowloadedFiles(List files) throws IOException { + for (File file : files) { + File fileToDelete =new File(Config.instance().getWindowsDownloadDirectory()+file.getName()); + fileToDelete.delete(); + } + } + + public static void cleanCurrentDownloadDir() throws IOException { + try{ + ExtentTestActions.log(Status.INFO, "Cleaning directory " + SetupCDTest.getWindowTest().getDownloadDirectory()); + System.gc(); + FileUtils.cleanDirectory(new File(SetupCDTest.getWindowTest().getDownloadDirectory())); + } + catch(Exception e){ + + } + } + + public static boolean isFileDownloaded(String downloadPath, String fileName) { + boolean flag = false; + File dir = new File(downloadPath); + File[] dir_contents = dir.listFiles(); + for (int i = 0; i < dir_contents.length; i++) { + if (dir_contents[i].getName().equals(fileName)) + return flag = true; + } + return flag; + } + + public static String getMD5OfFile(File file) throws IOException { + String content = FileUtils.readFileToString(file); + String md5 = GeneralUtility.calculateMD5ByString(content); + return md5; + } + + public static File createEmptyFile(String fileToCreate) { + File file= new File(fileToCreate); + try { + if(file.exists()){ + deleteFile(file); + } + file.createNewFile(); + SetupCDTest.getExtendTest().log(Status.INFO, "Create file " + fileToCreate); + } catch (IOException e) { + SetupCDTest.getExtendTest().log(Status.INFO, "Failed to create file " + fileToCreate); + e.printStackTrace(); + } + return file; + } + + public static File createEmptyFile(File fileToCreate) { + try { + if(fileToCreate.exists()){ + deleteFile(fileToCreate); + } + fileToCreate.createNewFile(); + SetupCDTest.getExtendTest().log(Status.INFO, "Create file " + fileToCreate); + } catch (IOException e) { + SetupCDTest.getExtendTest().log(Status.INFO, "Failed to create file " + fileToCreate); + e.printStackTrace(); + } + return fileToCreate; + } + + public static void deleteFile(File file){ + + try{ + if(file.exists()){ + file.deleteOnExit(); + SetupCDTest.getExtendTest().log(Status.INFO, "File " + file.getName() + "has been deleted"); + }else{ + SetupCDTest.getExtendTest().log(Status.INFO, "Failed to delete file " + file.getName()); + } + }catch(Exception e){ + e.printStackTrace(); + } + + } + + + /** + * get file list from directory by extension array + * @param directory + * @param okFileExtensions + * @return + */ + public static List getHeatAndHeatEnvArtifactsFromZip(File directory, String[] okFileExtensions){ + + List fileList = new ArrayList<>(); + File[] files = directory.listFiles(); + + for (String extension : okFileExtensions){ + for(File file : files){ + if (file.getName().toLowerCase().endsWith(extension)){ + fileList.add(file); + } + } + } + return fileList; + } + + private static final int BUFFER_SIZE = 4096; + public static void unzip(String zipFilePath, String destDirectory) throws IOException { + File destDir = new File(destDirectory); + if (!destDir.exists()) { + destDir.mkdir(); + } + ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath)); + ZipEntry entry = zipIn.getNextEntry(); +// iterates over entries in the zip file + while (entry != null) { + String entryName; + if(System.getProperty("os.name").contains("Windows")){ + entryName = entry.getName().replaceAll("/", "\\"+File.separator); + }else{ + entryName = entry.getName(); + } + String filePath = destDirectory + entryName; + String currPath = destDirectory; + String[] dirs = entryName.split("\\"+File.separator); + String currToken; + for(int i = 0; i0) { +// timeOut=time; +// } +// else { +// timeOut=timeOut; +// } +// } + + /**************** DRIVER ****************/ + + public static WebDriver getDriver() { + try{ + return DriverFactory.getDriver(); + } + catch(Exception e){ + e.printStackTrace(); + } + return null; + } + /****************************************/ + + public static List getElemenetsFromTable(By by) { + return getDriver().findElements(by); + } + + public static File takeScreenshot(String screenshotFilename, String dir, String testName) throws IOException { + if (screenshotFilename == null) { + if (testName != null){ + screenshotFilename = testName; + } + else + { + screenshotFilename = UUID.randomUUID().toString(); + } + } + try { + File scrFile = ((TakesScreenshot) getDriver()).getScreenshotAs(OutputType.FILE); + File filePath = new File(String.format("%s/%s.png", dir, screenshotFilename)); + new File(dir).mkdirs(); + FileUtils.copyFile(scrFile, filePath); + return filePath; + } catch (IOException e1) { + e1.printStackTrace(); + } + return null; + } + + public static File takeScreenshot(String screenshotFilename, String dir) throws IOException{ + return takeScreenshot(screenshotFilename, dir, null); + } + + + public static void scrollDown() { + try{ + Robot robot = new Robot(); + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + GeneralUIUtils.waitForLoader(); + } + catch(Exception e){ + e.printStackTrace(); + } + } + + public static void minimizeCatalogFilterByTitle(CatalogFilterTitlesEnum titlesEnum) { + + switch (titlesEnum) { + case CATEGORIES: + GeneralUIUtils.getWebElementByTestID(titlesEnum.getValue()).click(); + break; + case STATUS: + GeneralUIUtils.getWebElementByTestID(titlesEnum.getValue()).click(); + break; + case TYPE: + GeneralUIUtils.getWebElementByTestID(titlesEnum.getValue()).click(); + break; + default: + break; + } + + } + + public static WebElement getWebElementByTestID(String dataTestId) { + return getWebElementByTestID(dataTestId, timeOut); + } + + public static WebElement getWebElementByTestID(String dataTestId, int timeout) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeout); + return wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@data-tests-id='" + dataTestId + "']"))); + } + + public static boolean isWebElementExistByTestId(String dataTestId) { + if(getDriver().findElements(By.xpath("//*[@data-tests-id='" + dataTestId + "']")).size() == 0) { + return false; + } + return true; + } + + public static WebElement getInputElement(String dataTestId) { + try{ + ultimateWait(); + return getDriver().findElement(By.xpath("//*[@data-tests-id='" + dataTestId + "']")); + } + catch(Exception e){ + return null; + } + } + + public static List getInputElements(String dataTestId) { + ultimateWait(); + return getDriver().findElements(By.xpath("//*[@data-tests-id='" + dataTestId + "']")); + + } + + public static WebElement getWebElementBy(By by) { + return getWebElementBy(by, timeOut); + } + + public static WebElement getWebElementBy(By by, int timeOut) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + return wait.until(ExpectedConditions.visibilityOfElementLocated(by)); + } + + public static List getWebElementListText(Listelements) { + ListText=new ArrayList<>(); + for (WebElement webElement : elements) { + Text.add(webElement.getText()); + } + return Text; + } + + + public static List getWebElementsListBy(By by) { + return getWebElementsListBy(by, timeOut); + } + + public static List getWebElementsListBy(By by, int timeOut) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + return wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(by)); + } + + public static List getWebElementsListByContainTestID(String dataTestId) { + try{ + WebDriverWait wait = new WebDriverWait(getDriver(), 10); + return wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath("//*[contains(@data-tests-id, '"+dataTestId+"')]"))); + } + catch(Exception e){ + return new ArrayList(); + } + } + + public static List getWebElementsListByContainsClassName(String containedText) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + return wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath("//*[contains(@class, '"+containedText+"')]"))); + } + + public static WebElement getWebElementByContainsClassName(String containedText) { + return getWebElementBy(By.xpath("//*[contains(@class, '"+containedText+"')]")); + } + + public static WebElement getWebElementByClassName(String className) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + return wait.until(ExpectedConditions.visibilityOfElementLocated(By.className(className))); + } + + public static WebElement getWebElementByLinkText(String linkText) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + return wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@text='" + linkText + "']"))); + } + + + public static List getWebElementsListByTestID(String dataTestId) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + return wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.xpath("//*[@data-tests-id='" + dataTestId + "']"))); + } + + public static List getWebElementsListByClassName(String className) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + return wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.className(className))); + } + + + + + public static Boolean isElementInvisibleByTestId(String dataTestId) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + return wait.until( + ExpectedConditions.invisibilityOfElementLocated(By.xpath("//*[@data-tests-id='" + dataTestId + "']"))); + } + + public static Boolean isElementVisibleByTestId(String dataTestId) { + try{ + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + if(wait.until(ExpectedConditions.visibilityOfElementLocated((By.xpath("//*[@data-tests-id='" + dataTestId + "']")))).isDisplayed()){ + return true; + }else { + return false; + } + } + catch(Exception e){ + return false; + } + } + + public static void clickOnElementByTestId(String dataTestId) { + clickOnElementByTestIdWithoutWait(dataTestId); + ultimateWait(); + } + + public static void clickOnElementByTestIdWithoutWait(String dataTestId) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@data-tests-id='" + dataTestId + "']"))).click(); + } + + public static void clickOnElementByTestId(String dataTestId, int customTimeout) { + WebDriverWait wait = new WebDriverWait(getDriver(), customTimeout); + wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@data-tests-id='" + dataTestId + "']"))).click(); + } + + public static WebElement waitForElementVisibilityByTestId(String dataTestId) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + return wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@data-tests-id='" + dataTestId + "']"))); + } + + public static Boolean waitForElementInVisibilityByTestId(String dataTestId) { + return waitForElementInVisibilityByTestId(dataTestId, timeOut); + } + + public static Boolean waitForElementInVisibilityByTestId(String dataTestId, int timeOut) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + boolean displayed = getDriver().findElements(By.xpath("//*[@data-tests-id='" + dataTestId + "']")).isEmpty(); + if (!displayed){ + Boolean until = wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//*[@data-tests-id='" + dataTestId + "'])"))); + ultimateWait(); + return until; + } + return false; + } + + public static Boolean waitForElementInVisibilityByTestId(By by) { + return waitForElementInVisibilityBy(by, timeOut); + } + + + public static Boolean waitForElementInVisibilityBy(By by, int timeOut) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + boolean displayed = getDriver().findElements(by).isEmpty(); + if (!displayed){ + Boolean until = wait.until(ExpectedConditions.invisibilityOfElementLocated(by)); + sleep(1000); + return until; + } + return false; + } + + + public static void setWebElementByTestId(String elemetID, String value) { + WebElement resourceDescriptionTextbox = GeneralUIUtils.getWebElementByTestID(elemetID); + resourceDescriptionTextbox.clear(); + resourceDescriptionTextbox.sendKeys(value); + + } + + public static WebElement hoverOnAreaByTestId(String areaId) { + Actions actions = new Actions(getDriver()); + WebElement area = getWebElementByTestID(areaId); + actions.moveToElement(area).perform(); + ultimateWait(); + return area; + } + + public static WebElement hoverOnAreaByClassName(String className) { + Actions actions = new Actions(getDriver()); + WebElement area = getWebElementByClassName(className); + actions.moveToElement(area).perform(); + GeneralUIUtils.ultimateWait(); + return area; + } + + public static void clickElementUsingActions(WebElement element){ + Actions actions = new Actions(getDriver()); + + actions.moveToElement(element); + actions.perform(); + + actions.click(); + actions.perform(); + + ultimateWait(); + } + + public static void waitForLoader() { + waitForLoader(timeOut); + } + + public static void waitForLoader(int timeOut) { + sleep(500); + waitForElementInVisibilityBy(By.className("tlv-loader"), timeOut); + } + + public static void findComponentAndClick(String resourceName) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, "Searching for " + resourceName + " in homepage"); + WebElement searchTextbox = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtons.SEARCH_BOX.getValue()); + try{ + searchTextbox.clear(); + searchTextbox.sendKeys(resourceName); + ultimateWait(); + } + catch(Exception e){ + SetupCDTest.getExtendTest().log(Status.INFO, "Can't interact with search bar"); + e.printStackTrace(); + } + + + try{ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on the %s component from home screen", resourceName)); + clickOnElementByTestId(resourceName); + GeneralUIUtils.ultimateWait(); + getWebElementByTestID(DataTestIdEnum.GeneralElementsEnum.LIFECYCLE_STATE.getValue()); + } + catch(Exception e){ + SetupCDTest.getExtendTest().log(Status.INFO, "Can't click on component named " + resourceName); + e.printStackTrace(); + } + } + + + public static String getComponentVersion(String componentName) { + return GeneralUIUtils.getWebElementByTestID(componentName + "Version").getText(); + } + + public static void windowZoomOut() { + final int zoomOutFactor = 3; + for (int i = 0; i < zoomOutFactor; i++) { + if(getDriver() instanceof FirefoxDriver) { + getDriver().findElement(By.tagName("html")).sendKeys(Keys.chord(Keys.CONTROL, Keys.SUBTRACT)); + } + } + } + + public static void resetZoom(){ + getDriver().findElement(By.tagName("html")).sendKeys(Keys.chord(Keys.CONTROL, "0")); + } + + public static void windowZoomOutUltimate(){ + resetZoom(); + windowZoomOut(); +// JavascriptExecutor js = (JavascriptExecutor) driver; +// js.executeScript("document.body.style.zoom='90%'"); + } + + public static void clickASDCLogo() { + WebDriverWait wait = new WebDriverWait(getDriver(), 15); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.linkText("ASDC"))); + WebElement ClickASDCLogo = getDriver().findElement(By.linkText("ASDC")); + ClickASDCLogo.click(); + GeneralUIUtils.waitForLoader(); + } + + public static void sleep(int duration) { + try { + Thread.sleep(duration); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + public static void moveToStep(DataTestIdEnum.StepsEnum Stepname) { + moveToStep(Stepname.getValue()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Going to %s page ", Stepname.toString())); + } + + public static void moveToStep(String dataTestId) { + clickOnElementByTestId(dataTestId); + ultimateWait(); + } + + + public static Select getSelectList(String item, String datatestsid) { + Select selectlist = new Select(getWebElementByTestID(datatestsid)); + if (item != null) { + selectlist.selectByVisibleText(item); + } + return selectlist; + } + + public static List waitForElementsListVisibilityTestMethod(DashboardCardEnum dataTestId) { + GeneralUIUtils.waitForLoader(); + return getDriver().findElements(By.xpath("//*[@data-tests-id='" + dataTestId.getValue() + "']")); + } + + public static List getElementsByCSS(String cssString) throws InterruptedException { + GeneralUIUtils.waitForLoader(); + List assets = getDriver().findElements(By.cssSelector(cssString)); + return assets; + } + + public static WebElement getElementfromElementByCSS(WebElement parentElement, String cssString){ + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + GeneralUIUtils.waitForLoader(); + return parentElement.findElement(By.cssSelector(cssString)); + } + + public static WebElement getElementfromElementByXPATH(WebElement parentElement, DashboardCardEnum dataTestId){ + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + GeneralUIUtils.waitForLoader(); + return HighlightMyElement( parentElement.findElement(By.xpath("//*[@data-tests-id='" + dataTestId.getValue() + "']"))); + } + + public static WebElement HighlightMyElement(WebElement element) { + JavascriptExecutor javascript = (JavascriptExecutor) getDriver(); + javascript.executeScript("arguments[0].setAttribute('style', arguments[1]);", element, "color: yellow; border: 4px solid yellow;"); + return element; + } + + public static WebElement getSelectedElementFromDropDown(String dataTestId){ + GeneralUIUtils.ultimateWait();; + WebElement selectedElement = new Select (getDriver().findElement(By.xpath("//*[@data-tests-id='" + dataTestId + "']"))).getFirstSelectedOption(); + return selectedElement; + } + + + public static void waitForPageLoadByReadyState() { + new WebDriverWait(getDriver(), 30).until((ExpectedCondition) wd -> + ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete")); + } + + + public static boolean checkElementsCountInTable(int expectedElementsCount, Supplier> func) { + int maxWaitingPeriodMS = 10 * 1000; + int napPeriodMS = 100; + int sumOfWaiting = 0; + List elements = null; + boolean isKeepWaiting = false; + while (!isKeepWaiting) { + elements = func.get(); + isKeepWaiting = (expectedElementsCount == elements.size()); + sleep(napPeriodMS); + sumOfWaiting += napPeriodMS; + if (sumOfWaiting > maxWaitingPeriodMS) + return false; + } + return true; + } + + public static String getActionDuration(Runnable func) throws Exception{ + long startTime = System.nanoTime(); + func.run(); + long estimateTime = System.nanoTime(); + long duration = TimeUnit.NANOSECONDS.toSeconds(estimateTime - startTime); + String durationString = String.format("%02d:%02d", duration / 60, duration % 60); + return durationString; + } + + public static WebElement clickOnAreaJS(String areaId) { + return clickOnAreaJS(areaId, timeOut); + } + + + public static WebElement clickOnAreaJS(String areaId, int timeout) { + try{ + ultimateWait(); + WebElement area = getWebElementByTestID(areaId); + JavascriptExecutor javascript = (JavascriptExecutor) getDriver(); + //HighlightMyElement(area); + Object executeScript = javascript.executeScript("arguments[0].click();", area, "color: yellow; border: 4px solid yellow;"); + waitForLoader(timeout); + return area; + } + catch (Exception e){ + e.printStackTrace(); + } + return null; + } + + + + public static WebElement clickOnAreaJS(WebElement areaId) throws InterruptedException { + JavascriptExecutor javascript = (JavascriptExecutor) getDriver(); + //HighlightMyElement(area); + javascript.executeScript("arguments[0].click();", areaId, "color: yellow; border: 4px solid yellow;"); + return areaId; + } + + + + public static void clickSomewhereOnPage() { + getDriver().findElement(By.cssSelector(".asdc-app-title")).click(); + } + + public static void findComponentAndClickInCatalog(String resourceName) throws Exception { + // This method will find element by element name, don't use data-tests-id argument + WebElement searchTextbox = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtons.SEARCH_BOX.getValue()); + searchTextbox.clear(); + searchTextbox.sendKeys(resourceName); + ultimateWait(); + clickOnElementByText(resourceName); + ultimateWait(); + } + + public static void clickOnElementByText(String textInElement) { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + HighlightMyElement(wait.until( + ExpectedConditions.elementToBeClickable(findByText(textInElement)))).click(); + } + + public static void clickOnElementByText(String textInElement, int customTimeout) { + WebDriverWait wait = new WebDriverWait(getDriver(), customTimeout); + HighlightMyElement(wait.until( + ExpectedConditions.elementToBeClickable(findByText(textInElement)))).click(); + } + + public static void clickJSOnElementByText(String textInElement) throws Exception { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + clickOnAreaJS(wait.until( + ExpectedConditions.elementToBeClickable(findByText(textInElement)))); + } + + public static void fluentWaitTestID(String dataTestId, String text) { + FluentWait fluentWait = new FluentWait(getDriver()) + .withTimeout(30, TimeUnit.SECONDS) + .pollingEvery(50, TimeUnit.MILLISECONDS) + .ignoring(NoSuchElementException.class); + + fluentWait.until(ExpectedConditions.refreshed( + ExpectedConditions.textToBePresentInElementValue(By.xpath("//*[@data-tests-id='" + dataTestId + "']"), text))); + } + + public static void regularWait(WebElement element, String text){ + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + + wait.until(ExpectedConditions.textToBePresentInElementValue(element, text)); + } + + public static void waitForAngular(){ + WebDriverWait wait = new WebDriverWait(getDriver(), 90, 100); + wait.until(AdditionalConditions.pageLoadWait()); + wait.until(AdditionalConditions.angularHasFinishedProcessing()); + } + + public static Object getAllElementAttributes(WebElement element) { + return ((JavascriptExecutor)getDriver()).executeScript("var s = []; var attrs = arguments[0].attributes; for (var l = 0; l < attrs.length; ++l) { var a = attrs[l]; s.push(a.name + ':' + a.value); } ; return s;", element); + } + + public static boolean isElementReadOnly(WebElement element){ + try { + HighlightMyElement(element).clear(); + return false; + } catch (Exception e) { + return true; + } + } + + public static boolean isElementReadOnly(String dataTestId){ + return isElementReadOnly( + waitForElementVisibilityByTestId(dataTestId)); + } + + public static boolean isElementDisabled(WebElement element){ + return HighlightMyElement(element).getAttribute("class").contains("view-mode") || + element.getAttribute("class").contains("disabled"); + } + + public static boolean isElementDisabled(String dataTestId){ + return isElementDisabled( + waitForElementVisibilityByTestId(dataTestId)); + } + + public static void ultimateWait(){ + long startTime = System.nanoTime(); + + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.waitForBackLoader(); + GeneralUIUtils.waitForAngular(); + + long estimateTime = System.nanoTime(); + long duration = TimeUnit.NANOSECONDS.toSeconds(estimateTime - startTime); +// System.out.println("UltimateWait took: "+ duration); + if(duration > timeOut){ + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Delays on page, %d seconds", duration)); + } +// waitForUINotification(); + } + + public static WebElement makeElementVisibleWithJS(WebElement element){ + String js = "arguments[0].style.height='auto'; arguments[0].style.visibility='visible';"; + ((JavascriptExecutor) getDriver()).executeScript(js, element); + return element; + } + + public static WebElement unhideElement(WebElement element, String attributeValue){ + String js = "arguments[0].setAttribute('class','" + attributeValue + "');"; + ((JavascriptExecutor) getDriver()).executeScript(js, element); + return element; + } + + public static WebElement findByText(String textInElement){ + return getDriver().findElement(searchByTextContaining(textInElement)); + } + public static By searchByTextContaining(String textInElement) { + return By.xpath("//*[contains(text(),'" + textInElement + "')]"); + } + + + public static boolean findAndWaitByText(String textInElement, int timeout){ + try{ + WebDriverWait wait = new WebDriverWait(getDriver(), timeout); + wait.until(ExpectedConditions.presenceOfElementLocated(searchByTextContaining(textInElement))); + return true; + } + catch(Exception e){ + return false; + } + } + + public static WebElement getClickableButtonBy(By by, int timout){ + try{ + WebDriverWait wait = new WebDriverWait(getDriver(), timout); + WebElement element = wait.until(ExpectedConditions.elementToBeClickable(by)); + return element; + } + catch(Exception e){ + return null; + } + } + + + + public static WebElement getButtonWithText(String textInButton){ + try{ + return getDriver().findElement(By.xpath("//button[contains(text(),'" + textInButton + "')]")); + } + catch(Exception e) + { + return null; + } + } + + + public static List getElementsByDataTestsIdStartWith(String startWithString){ + ultimateWait(); + return getDriver().findElements(By.xpath("//*[starts-with(@data-tests-id,'" + startWithString + "')]")); + } + + public static void closeErrorMessage() { + WebElement okWebElement = getButtonWithText("OK"); + if (okWebElement != null){ + okWebElement.click(); + ultimateWait(); + } + } + + public static WebElement getElementByCSS(String cssString) throws InterruptedException { + ultimateWait(); + return getDriver().findElement(By.cssSelector(cssString)); + } + + public static String getDataTestIdAttributeValue(WebElement element) { + return element.getAttribute("data-tests-id"); + } + + public static String getTextContentAttributeValue(WebElement element) { + return element.getAttribute("textContent"); + } + + public static WebElement getElementInsideElementByDataTestsId(WebElement element, String dataTestId) { + try{ + return element.findElement(By.xpath("//*[@data-tests-id='" + dataTestId + "']")); + } + catch(Exception e){ + return null; + } + } + + public static void clickOnElementByCSS(String cssString) throws Exception { + WebDriverWait wait = new WebDriverWait(getDriver(), timeOut); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(cssString))).click(); + ultimateWait(); + } + public static String getRandomComponentName(String prefix) { + return prefix + GeneralUIUtils.randomNumber(); + } + public static int randomNumber() { + Random r = new Random(); + return r.nextInt(10000); + } + + public static void waitForUINotification() { + List notificationElements = getDriver().findElements(By.className("ui-notification")); + if (!notificationElements.isEmpty()){ + notificationElements.forEach(WebElement::click); + } + } + + public static boolean checkForDisabledAttribute(String dataTestId){ + Object elementAttributes = getAllElementAttributes(waitForElementVisibilityByTestId(dataTestId)); + return elementAttributes.toString().contains("disabled"); + } + + public static void dragAndDropElementByY(WebElement area, int yOffset) { + Actions actions = new Actions(getDriver()); + actions.dragAndDropBy(area, 10, yOffset).perform(); + ultimateWait(); + } + + public static void waitForBackLoader() { + waitForBackLoader(timeOut); + } + + public static void waitForBackLoader(int timeOut) { + sleep(100); + waitForElementInVisibilityBy(By.className("tlv-loader-back"), timeOut); + } + + public static void addStringtoClipboard(String text){ + StringSelection selection = new StringSelection(text); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(selection, selection); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/HomeUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/HomeUtils.java new file mode 100644 index 0000000000..1bef2ad32c --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/HomeUtils.java @@ -0,0 +1,117 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import org.openecomp.sdc.ci.tests.datatypes.TopMenuButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.CheckBoxStatusEnum; +import org.openecomp.sdc.ci.tests.datatypes.CreateAndImportButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.testng.Assert; + +import com.aventstack.extentreports.Status; + +public final class HomeUtils { + + public static WebElement createAndImportButtons(CreateAndImportButtonsEnum type, WebDriver driver) + throws InterruptedException { + switch (type) { + case IMPORT_CP: + case IMPORT_VFC: + case IMPORT_VL: + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.Dashboard.IMPORT_AREA.getValue()); + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.IMPORT_VFC.getValue()); + + case IMPORT_VF: + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.Dashboard.IMPORT_AREA.getValue()); + return GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.IMPORT_VFC.getValue()); + case CREATE_SERVICE: + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.Dashboard.ADD_AREA.getValue()); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_SERVICE.getValue()).click(); + ; + break; + + case CREATE_PRODUCT: + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_SERVICE.getValue()).click(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_SERVICE.getValue()).click(); + break; + + default: + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.Dashboard.ADD_AREA.getValue()); + driver.findElement(By.xpath("//*[@data-tests-id='createResourceButton']")).click(); + break; + } + return null; + + } + + public static String checkBoxLifeCyclestate(CheckBoxStatusEnum lifeCycle) { + String Status = "IN DESIGN CHECK OUT"; + switch (lifeCycle) { + case CHECKIN: + Status = "IN DESIGN CHECK IN"; + if (GeneralUIUtils.getWebElementByTestID(lifeCycle.getValue()).isDisplayed()) { + GeneralUIUtils.getWebElementByTestID(lifeCycle.getValue()).click(); + } + break; + case CHECKOUT: + GeneralUIUtils.getWebElementByTestID(lifeCycle.getValue()).click(); + Status = "IN DESIGN CHECK OUT"; + break; + case IN_TESTING: + GeneralUIUtils.getWebElementByTestID(lifeCycle.getValue()).click(); + Status = "IN TESTING"; + break; + case READY_FOR_TESTING: + GeneralUIUtils.getWebElementByTestID(lifeCycle.getValue()).click(); + Status = "READY FOR TESTING"; + break; + case CERTIFIED: + GeneralUIUtils.getWebElementByTestID(lifeCycle.getValue()).click(); + Status = "CERTIFIED"; + break; + } + return Status; + } + + public static void findComponentAndClick(String componentName) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, "finding component " + componentName); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.MainMenuButtons.SEARCH_BOX.getValue()).sendKeys(componentName); + WebElement foundComp = null; + try { + foundComp = GeneralUIUtils.getWebElementByTestID(componentName); + foundComp.click(); + GeneralUIUtils.waitForLoader(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralElementsEnum.LIFECYCLE_STATE.getValue()); + } catch (Exception e) { + String msg = String.format("DID NOT FIND A COMPONENT NAMED %s", componentName); + SetupCDTest.getExtendTest().log(Status.FAIL, msg); + System.out.println(msg); + Assert.fail(msg); + } + } + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ImportAssetUIUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ImportAssetUIUtils.java new file mode 100644 index 0000000000..d1045eab76 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ImportAssetUIUtils.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.CreateAndImportButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +public class ImportAssetUIUtils { + + public static final String FILE_PATH = System.getProperty("user.dir") + "\\src\\main\\resources\\Files\\"; + public static String fileName = "JDM_vfc.yml"; + public static final String toscaErrorMessage = "Invalid TOSCA template."; + public static final String yamlError = "Invalid YAML file."; + public static final String allReadyExistErro = "Imported resource already exists in ASDC Catalog."; + + public static void importAsssetAndFillGeneralInfo(String FILE_PATH, String fileName, + ResourceReqDetails resourceDetails, User user, CreateAndImportButtonsEnum type) throws Exception { + ResourceUIUtils.importFileWithSendKey(FILE_PATH, fileName, type); + ResourceUIUtils.fillResourceGeneralInformationPage(resourceDetails, user,true); + } + + public static void importAsssetFillGeneralInfoAndSelectIcon(String FILE_PATH, String fileName, + ResourceReqDetails resourceDetails, User user, CreateAndImportButtonsEnum type) throws Exception { + importAsssetAndFillGeneralInfo(FILE_PATH, fileName, resourceDetails, user, type); + GeneralPageElements.clickCreateButton(); + ResourceUIUtils.selectRandomResourceIcon(); + } + + // checking or unchecking the checkbox on right palette at designer + // workspace + public static void checkbox(String checkBoxname, WebDriver driver) { + driver.findElement(By.xpath("//label[@for='" + checkBoxname + "']")).click(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/OnboardingUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/OnboardingUtils.java new file mode 100644 index 0000000000..dfb4b74fac --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/OnboardingUtils.java @@ -0,0 +1,801 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import static org.testng.AssertJUnit.assertEquals; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.nio.file.FileSystems; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.entity.mime.content.FileBody; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.simple.JSONArray; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.LifeCycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpHeaderEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.HttpRequest; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.devCI.ArtifactFromCsar; +import org.openecomp.sdc.ci.tests.execute.setup.ArtifactsCorrelationManager; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.DeploymentArtifactPage; +import org.openecomp.sdc.ci.tests.pages.HomePage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.utils.Utils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.verificator.VfVerificator; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.testng.Assert; + +import com.aventstack.extentreports.Status; +import com.clearspring.analytics.util.Pair; + +public class OnboardingUtils { + + public OnboardingUtils() { + } + + private static String vendorId; + private static String vendorLicenseName; + private static String vendorLicenseAgreementId; + private static String featureGroupId; + + public static Pair> createVendorSoftwareProduct(String HeatFileName, String filepath, User user) + throws Exception { + Pair> pair = createVSP(HeatFileName, filepath, user); + + String vspid = pair.right.get("vspId"); + + prepareVspForUse(user, vspid); + + return pair; + } + + public static void prepareVspForUse(User user, String vspid) throws Exception { + RestResponse checkin = checkinVendorSoftwareProduct(vspid, user); + assertEquals("did not succeed to checking new VSP", 200, checkin.getErrorCode().intValue()); + + RestResponse submit = submitVendorSoftwareProduct(vspid, user); + assertEquals("did not succeed to submit new VSP", 200, submit.getErrorCode().intValue()); + + RestResponse createPackage = createPackageOfVendorSoftwareProduct(vspid, user); + assertEquals("did not succeed to create package of new VSP ", 200, createPackage.getErrorCode().intValue()); + + SetupCDTest.getExtendTest().log(Status.INFO, "Succeeded in creating the vendor software product"); + } + + public static Pair> createVSP(String HeatFileName, String filepath, User user) throws Exception { + String vspName = handleFilename(HeatFileName); + + SetupCDTest.getExtendTest().log(Status.INFO, "Starting to create the vendor software product"); + + Pair> createNewVspPair = createNewVendorSoftwareProduct(vspName, vendorLicenseName, vendorId, vendorLicenseAgreementId, featureGroupId, user); + RestResponse createNewVendorSoftwareProduct = createNewVspPair.left; + assertEquals("did not succeed to create new VSP", 200,createNewVendorSoftwareProduct.getErrorCode().intValue()); + String vspid = ResponseParser.getValueFromJsonResponse(createNewVendorSoftwareProduct.getResponse(), "vspId"); + String componentId = ResponseParser.getValueFromJsonResponse(createNewVendorSoftwareProduct.getResponse(), "componentId"); + + Map vspMeta = createNewVspPair.right; + Map vspObject = new HashMap(); + Iterator iterator = vspMeta.keySet().iterator(); + while(iterator.hasNext()){ + Object key = iterator.next(); + Object value = vspMeta.get(key); + vspObject.put(key.toString(), value.toString()); + } + vspObject.put("vspId", vspid); + vspObject.put("componentId", componentId); + vspObject.put("vendorName", vendorLicenseName); + vspObject.put("attContact", user.getUserId()); + + RestResponse uploadHeatPackage = uploadHeatPackage(filepath, HeatFileName, vspid, user); + assertEquals("did not succeed to upload HEAT package", 200, uploadHeatPackage.getErrorCode().intValue()); + + RestResponse validateUpload = validateUpload(vspid, user); + assertEquals("did not succeed to validate upload process", 200, validateUpload.getErrorCode().intValue()); + + Pair> pair = new Pair>(vspName, vspObject); + + return pair; + } + + public static void updateVspWithVfcArtifacts(String filepath, String vspId, String updatedSnmpPoll, String updatedSnmpTrap, String componentId, User user) throws Exception{ + RestResponse checkout = checkoutVendorSoftwareProduct(vspId, user); + assertEquals("did not succeed to checkout new VSP", 200, checkout.getErrorCode().intValue()); + ExtentTestActions.log(Status.INFO, "Deleting SNMP POLL"); + deleteSnmpArtifact(componentId, vspId, user, SnmpTypeEnum.SNMP_POLL); + ExtentTestActions.log(Status.INFO, "Deleting SNMP TRAP"); + deleteSnmpArtifact(componentId, vspId, user, SnmpTypeEnum.SNMP_TRAP); + addVFCArtifacts(filepath, updatedSnmpPoll, updatedSnmpTrap, vspId, user, componentId); + prepareVspForUse(user, vspId); + } + + public static String updateVendorSoftwareProduct(String vspId, String HeatFileName, String filepath, User user) + throws Exception, Throwable { + String vspName = handleFilename(HeatFileName); + SetupCDTest.getExtendTest().log(Status.INFO, "Starting to update the vendor software product"); + + RestResponse checkout = checkoutVendorSoftwareProduct(vspId, user); + assertEquals("did not succeed to checkout new VSP", 200, checkout.getErrorCode().intValue()); + + RestResponse uploadHeatPackage = uploadHeatPackage(filepath, HeatFileName, vspId, user); + assertEquals("did not succeed to upload HEAT package", 200, uploadHeatPackage.getErrorCode().intValue()); + + RestResponse validateUpload = validateUpload(vspId, user); + assertEquals("did not succeed to validate upload process", 200, validateUpload.getErrorCode().intValue()); + + RestResponse checkin = checkinVendorSoftwareProduct(vspId, user); + assertEquals("did not succeed to checking VSP", 200, checkin.getErrorCode().intValue()); + + + RestResponse submit = submitVendorSoftwareProduct(vspId, user); + assertEquals("did not succeed to submit VSP", 200, submit.getErrorCode().intValue()); + + RestResponse createPackage = createPackageOfVendorSoftwareProduct(vspId, user); + assertEquals("did not succeed to update package of VSP ", 200, createPackage.getErrorCode().intValue()); + + SetupCDTest.getExtendTest().log(Status.INFO, "Succeeded in updating the vendor software product"); + + return vspName; + } + + public static String handleFilename(String heatFileName) { + final String namePrefix = "ciVFOnboarded-"; + final String nameSuffix = "-" + getShortUUID(); + + String subHeatFileName = heatFileName.substring(0, heatFileName.lastIndexOf(".")); + + if ((namePrefix + subHeatFileName + nameSuffix).length() >= 50) { + subHeatFileName = subHeatFileName.substring(0, 50 - namePrefix.length() - nameSuffix.length()); + } + + if (subHeatFileName.contains("(") || subHeatFileName.contains(")")) { + subHeatFileName = subHeatFileName.replace("(", "-"); + subHeatFileName = subHeatFileName.replace(")", "-"); + } + + String vnfName = namePrefix + subHeatFileName + nameSuffix; + return vnfName; + } + + public static String addVFCArtifacts(String filepath, String snmpPoll, String snmpTrap, String vspid, User user, String vspComponentId) throws Exception{ + vspComponentId = (vspComponentId == null) ? getVSPComponentId(vspid, user) : vspComponentId; + if (vspComponentId != null){ + if (snmpPoll != null){ + ExtentTestActions.log(Status.INFO, "Adding VFC artifact of type SNMP POLL with the file " + snmpPoll); + RestResponse uploadSnmpPollArtifact = uploadSnmpPollArtifact(filepath, snmpPoll, vspid, user, vspComponentId); + assertEquals("Did not succeed to add SNMP POLL", 200, uploadSnmpPollArtifact.getErrorCode().intValue()); + } + if (snmpTrap != null){ + ExtentTestActions.log(Status.INFO, "Adding VFC artifact of type SNMP TRAP with the file " + snmpTrap); + RestResponse uploadSnmpTrapArtifact = uploadSnmpTrapArtifact(filepath, snmpTrap, vspid, user, vspComponentId); + assertEquals("Did not succeed to add SNMP TRAP", 200, uploadSnmpTrapArtifact.getErrorCode().intValue()); + } + } + + return vspComponentId; + } + + public static String addVFCArtifacts(String filepath, String snmpPoll, String snmpTrap, String vspid, User user) throws Exception{ + return addVFCArtifacts(filepath, snmpPoll, snmpTrap, vspid, user, null); + } + + private static RestResponse uploadSnmpPollArtifact(String filepath, String zipArtifact, String vspid, User user, + String vspComponentId) throws FileNotFoundException, IOException, ClientProtocolException { + Config config = Utils.getConfig(); + String snmpPollUrl = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products/%s/versions/0.1/components/%s/monitors/snmp/upload", + config.getCatalogBeHost(),config.getCatalogBePort(), vspid, vspComponentId); + return uploadFile(filepath, zipArtifact, snmpPollUrl, user); + } + + private static RestResponse uploadSnmpTrapArtifact(String filepath, String zipArtifact, String vspid, User user, + String vspComponentId) throws FileNotFoundException, IOException, ClientProtocolException { + Config config = Utils.getConfig(); + String snmpTrapUrl = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products/%s/versions/0.1/components/%s/monitors/snmp-trap/upload", + config.getCatalogBeHost(),config.getCatalogBePort(), vspid, vspComponentId); + return uploadFile(filepath, zipArtifact, snmpTrapUrl, user); + } + + private static RestResponse deleteSnmpArtifact(String componentId, String vspId, User user, SnmpTypeEnum snmpType) throws Exception + { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products/%s/versions/0.1/components/%s/monitors/%s", + config.getCatalogBeHost(),config.getCatalogBePort(), vspId, componentId, snmpType.getValue()); + String userId = user.getUserId(); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendDelete(url, headersMap); + return response; + } + + + + private static String getVSPComponentId(String vspid, User user) throws Exception, JSONException { + RestResponse components = getVSPComponents(vspid, user); + String response = components.getResponse(); + Map responseMap = (Map) JSONValue.parse(response); + JSONArray results = (JSONArray)responseMap.get("results"); + for (Object res : results){ + Map compMap= (Map) JSONValue.parse(res.toString()); + String componentId = compMap.get("id").toString(); + return componentId; + } + return null; + } + + private static RestResponse getVSPComponents(String vspid, User user) throws Exception{ + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products/%s/versions/0.1/components", config.getCatalogBeHost(),config.getCatalogBePort(), vspid); + String userId = user.getUserId(); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendGet(url, headersMap); + return response; + } + + public static void createVendorLicense(User user) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, "Starting to create the vendor license"); + vendorLicenseName = "ciLicense" + getShortUUID(); + RestResponse vendorLicenseResponse = createVendorLicenseModels_1(vendorLicenseName, user); + assertEquals("did not succeed to create vendor license model", 200, + vendorLicenseResponse.getErrorCode().intValue()); + vendorId = ResponseParser.getValueFromJsonResponse(vendorLicenseResponse.getResponse(), "value"); + + RestResponse vendorKeyGroupsResponse = createVendorKeyGroups_2(vendorId, user); + assertEquals("did not succeed to create vendor key groups", 200, + vendorKeyGroupsResponse.getErrorCode().intValue()); + String keyGroupId = ResponseParser.getValueFromJsonResponse(vendorKeyGroupsResponse.getResponse(), "value"); + + RestResponse vendorEntitlementPool = createVendorEntitlementPool_3(vendorId, user); + assertEquals("did not succeed to create vendor entitlement pool", 200, + vendorEntitlementPool.getErrorCode().intValue()); + String entitlementPoolId = ResponseParser.getValueFromJsonResponse(vendorEntitlementPool.getResponse(), + "value"); + + RestResponse vendorLicenseFeatureGroups = createVendorLicenseFeatureGroups_4(vendorId, keyGroupId, + entitlementPoolId, user); + assertEquals("did not succeed to create vendor license feature groups", 200, + vendorLicenseFeatureGroups.getErrorCode().intValue()); + featureGroupId = ResponseParser.getValueFromJsonResponse(vendorLicenseFeatureGroups.getResponse(), "value"); + + RestResponse vendorLicenseAgreement = createVendorLicenseAgreement_5(vendorId, featureGroupId, user); + assertEquals("did not succeed to create vendor license agreement", 200, + vendorLicenseAgreement.getErrorCode().intValue()); + vendorLicenseAgreementId = ResponseParser.getValueFromJsonResponse(vendorLicenseAgreement.getResponse(), + "value"); + + RestResponse checkinVendorLicense = checkinVendorLicense(vendorId, user); + assertEquals("did not succeed to checkin vendor license", 200, checkinVendorLicense.getErrorCode().intValue()); + + RestResponse submitVendorLicense = submitVendorLicense(vendorId, user); + assertEquals("did not succeed to submit vendor license", 200, submitVendorLicense.getErrorCode().intValue()); + + SetupCDTest.getExtendTest().log(Status.INFO, "Succeeded in creating the vendor license"); + } + + private static String getShortUUID() { + return UUID.randomUUID().toString().split("-")[0]; + } + + private static RestResponse actionOnComponent(String vspid, String action, String onboardComponent, User user) + throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/" + onboardComponent + "/%s/versions/0.1/actions", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + String userId = user.getUserId(); + + JSONObject jObject = new JSONObject(); + jObject.put("action", action); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPut(url, jObject.toString(), headersMap); + return response; + } + + public static RestResponse checkinVendorLicense(String vspid, User user) throws Exception { + return actionOnComponent(vspid, "Checkin", "vendor-license-models", user); + } + + public static RestResponse submitVendorLicense(String vspid, User user) throws Exception { + return actionOnComponent(vspid, "Submit", "vendor-license-models", user); + } + + public static RestResponse createVendorLicenseModels_1(String name, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models", config.getCatalogBeHost(), + config.getCatalogBePort()); + String userId = user.getUserId(); + + JSONObject jObject = new JSONObject(); + jObject.put("vendorName", name); + jObject.put("description", "new vendor license model"); + jObject.put("iconRef", "icon"); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObject.toString(), headersMap); + return response; + + } + + public static RestResponse createVendorLicenseAgreement_5(String vspid, String featureGroupId, User user) + throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models/%s/versions/0.1/license-agreements", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + String userId = user.getUserId(); + + JSONObject licenseTermpObject = new JSONObject(); + licenseTermpObject.put("choice", "Fixed_Term"); + licenseTermpObject.put("other", ""); + + JSONObject jObjectBody = new JSONObject(); + jObjectBody.put("name", "abc"); + jObjectBody.put("description", "new vendor license agreement"); + jObjectBody.put("requirementsAndConstrains", "abc"); + jObjectBody.put("licenseTerm", licenseTermpObject); + jObjectBody.put("addedFeatureGroupsIds", Arrays.asList(featureGroupId).toArray()); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObjectBody.toString(), headersMap); + return response; + } + + public static RestResponse createVendorLicenseFeatureGroups_4(String vspid, String licenseKeyGroupId, + String entitlementPoolId, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models/%s/versions/0.1/feature-groups", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + String userId = user.getUserId(); + + JSONObject jObject = new JSONObject(); + jObject.put("name", "xyz"); + jObject.put("description", "new vendor license feature groups"); + jObject.put("partNumber", "123abc456"); + jObject.put("addedLicenseKeyGroupsIds", Arrays.asList(licenseKeyGroupId).toArray()); + jObject.put("addedEntitlementPoolsIds", Arrays.asList(entitlementPoolId).toArray()); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObject.toString(), headersMap); + return response; + + } + + public static RestResponse createVendorEntitlementPool_3(String vspid, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models/%s/versions/0.1/entitlement-pools", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + String userId = user.getUserId(); + + JSONObject jEntitlementMetricObject = new JSONObject(); + jEntitlementMetricObject.put("choice", "CPU"); + jEntitlementMetricObject.put("other", ""); + + JSONObject jAggregationFunctionObject = new JSONObject(); + jAggregationFunctionObject.put("choice", "Peak"); + jAggregationFunctionObject.put("other", ""); + + JSONObject jOperationalScope = new JSONObject(); + jOperationalScope.put("choices", Arrays.asList("Availability_Zone").toArray()); + jOperationalScope.put("other", ""); + + JSONObject jTimeObject = new JSONObject(); + jTimeObject.put("choice", "Hour"); + jTimeObject.put("other", ""); + + JSONObject jObjectBody = new JSONObject(); + jObjectBody.put("name", "def"); + jObjectBody.put("description", "new vendor license entitlement pool"); + jObjectBody.put("thresholdValue", "23"); + jObjectBody.put("thresholdUnits", "Absolute"); + jObjectBody.put("entitlementMetric", jEntitlementMetricObject); + jObjectBody.put("increments", "abcd"); + jObjectBody.put("aggregationFunction", jAggregationFunctionObject); + jObjectBody.put("operationalScope", jOperationalScope); + jObjectBody.put("time", jTimeObject); + jObjectBody.put("manufacturerReferenceNumber", "123aaa"); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObjectBody.toString(), headersMap); + return response; + } + + public static RestResponse createVendorKeyGroups_2(String vspid, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-license-models/%s/versions/0.1/license-key-groups", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + String userId = user.getUserId(); + + JSONObject jOperationalScope = new JSONObject(); + jOperationalScope.put("choices", Arrays.asList("Tenant").toArray()); + jOperationalScope.put("other", ""); + + JSONObject jObjectBody = new JSONObject(); + jObjectBody.put("name", "keyGroup"); + jObjectBody.put("description", "new vendor license key group"); + jObjectBody.put("operationalScope", jOperationalScope); + jObjectBody.put("type", "Universal"); + + Map headersMap = prepareHeadersMap(userId); + + HttpRequest http = new HttpRequest(); + RestResponse response = http.httpSendPost(url, jObjectBody.toString(), headersMap); + return response; + } + + public static Pair> createNewVendorSoftwareProduct(String name, String vendorName, String vendorId, + String licenseAgreementId, String featureGroupsId, User user) throws Exception { + + Map vspMetadta = new HashMap(); + + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products", + config.getCatalogBeHost(), config.getCatalogBePort()); + + String userId = user.getUserId(); + + JSONObject jlicensingDataObj = new JSONObject(); + jlicensingDataObj.put("licenseAgreement", licenseAgreementId); + jlicensingDataObj.put("featureGroups", Arrays.asList(featureGroupsId).toArray()); + + JSONObject jlicensingVersionObj = new JSONObject(); + jlicensingVersionObj.put("id", "1.0"); + jlicensingVersionObj.put("label", "1.0"); + + JSONObject jObject = new JSONObject(); + jObject.put("name", name); + jObject.put("description", "new VSP description"); + jObject.put("category", "resourceNewCategory.generic"); + jObject.put("subCategory", "resourceNewCategory.generic.database"); + jObject.put("licensingVersion", jlicensingVersionObj); + jObject.put("vendorName", vendorName); + jObject.put("vendorId", vendorId); + jObject.put("icon", "icon"); + jObject.put("licensingData", jlicensingDataObj); + + vspMetadta.put("description", jObject.getString("description")); + vspMetadta.put("category", jObject.getString("category")); + vspMetadta.put("subCategory", jObject.getString("subCategory").split("\\.")[2]); + + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + + RestResponse response = http.httpSendPost(url, jObject.toString(), headersMap); + + return new Pair>(response, vspMetadta); + } + + public static RestResponse getVendorSoftwareProduct(Map vspObject, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products/" + vspObject.get("vspId"), + config.getCatalogBeHost(), config.getCatalogBePort()); + + String userId = user.getUserId(); + + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + + RestResponse response = http.httpsSendGet(url, headersMap); + + return response; + } + + public static RestResponse validateUpload(String vspid, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products/%s/versions/0.1/orchestration-template-candidate/process", + config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + + String userId = user.getUserId(); + + Map headersMap = prepareHeadersMap(userId); + HttpRequest http = new HttpRequest(); + + String body =null; + + RestResponse response = http.httpSendPut(url, body, headersMap); + + return response; + } + + public static RestResponse uploadHeatPackage(String filepath, String filename, String vspid, User user) throws Exception { + Config config = Utils.getConfig(); + String url = String.format("http://%s:%s/onboarding-api/v1.0/vendor-software-products/%s/versions/0.1/orchestration-template-candidate", config.getCatalogBeHost(), config.getCatalogBePort(), vspid); + return uploadFile(filepath, filename, url, user); + } + + private static RestResponse uploadFile(String filepath, String filename, String url, User user) + throws FileNotFoundException, IOException, ClientProtocolException { + CloseableHttpResponse response = null; + + MultipartEntityBuilder mpBuilder = MultipartEntityBuilder.create(); + mpBuilder.addPart("upload", new FileBody(getTestZipFile(filepath, filename))); + + Map headersMap = prepareHeadersMap(user.getUserId()); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "multipart/form-data"); + + CloseableHttpClient client = HttpClients.createDefault(); + try { + HttpPost httpPost = new HttpPost(url); + RestResponse restResponse = new RestResponse(); + + Iterator iterator = headersMap.keySet().iterator(); + while (iterator.hasNext()) { + String key = iterator.next(); + String value = headersMap.get(key); + httpPost.addHeader(key, value); + } + httpPost.setEntity(mpBuilder.build()); + response = client.execute(httpPost); + HttpEntity entity = response.getEntity(); + String responseBody = null; + if (entity != null) { + InputStream instream = entity.getContent(); + StringWriter writer = new StringWriter(); + IOUtils.copy(instream, writer); + responseBody = writer.toString(); + try { + + } finally { + instream.close(); + } + } + + restResponse.setErrorCode(response.getStatusLine().getStatusCode()); + restResponse.setResponse(responseBody); + + return restResponse; + + } finally { + closeResponse(response); + closeHttpClient(client); + + } + } + + private static void closeResponse(CloseableHttpResponse response) { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + System.out.println(String.format("failed to close client or response: %s", e.getMessage())); + } + } + + private static void closeHttpClient(CloseableHttpClient client) { + try { + if (client != null) { + client.close(); + } + } catch (IOException e) { + System.out.println(String.format("failed to close client or response: %s", e.getMessage())); + } + } + + private static File getTestZipFile(String filepath, String filename) throws IOException { + Config config = Utils.getConfig(); + String sourceDir = config.getImportResourceTestsConfigDir(); + java.nio.file.Path filePath = FileSystems.getDefault().getPath(filepath + File.separator + filename); + return filePath.toFile(); + } + + public static RestResponse checkinVendorSoftwareProduct(String vspid, User user) throws Exception { + return actionOnComponent(vspid, "Checkin", "vendor-software-products", user); + } + + private static RestResponse checkoutVendorSoftwareProduct(String vspid, User user) throws Exception { + return actionOnComponent(vspid, "Checkout", "vendor-software-products", user); + } + + public static RestResponse submitVendorSoftwareProduct(String vspid, User user) throws Exception { + return actionOnComponent(vspid, "Submit", "vendor-software-products", user); + } + + public static RestResponse createPackageOfVendorSoftwareProduct(String vspid, User user) throws Exception { + return actionOnComponent(vspid, "Create_Package", "vendor-software-products", user); + } + + protected static Map prepareHeadersMap(String userId) { + Map headersMap = new HashMap(); + headersMap.put(HttpHeaderEnum.CONTENT_TYPE.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.ACCEPT.getValue(), "application/json"); + headersMap.put(HttpHeaderEnum.USER_ID.getValue(), userId); + return headersMap; + } + + + private static void importUpdateVSP(Pair> vsp, boolean isUpdate) throws Exception{ + String vspName = vsp.left; + Map vspMetadata = vsp.right; + boolean vspFound = HomePage.searchForVSP(vspName); + + if (vspFound){ + + List elemenetsFromTable = HomePage.getElemenetsFromTable(); +// WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), 30); +// WebElement findElement = wait.until(ExpectedConditions.visibilityOf(elemenetsFromTable.get(1))); +// findElement.click(); + elemenetsFromTable.get(1).click(); + GeneralUIUtils.waitForLoader(); + + if (isUpdate){ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ImportVfRepository.UPDATE_VSP.getValue()); + + } + else{ + GeneralUIUtils.clickOnElementByTestId(DataTestIdEnum.ImportVfRepository.IMPORT_VSP.getValue()); + } + + String lifeCycleState = ResourceGeneralPage.getLifeCycleState(); + boolean needCheckout = lifeCycleState.equals(LifeCycleStateEnum.CHECKIN.getValue()) || lifeCycleState.equals(LifeCycleStateEnum.CERTIFIED.getValue()); + if (needCheckout) + { + try { + ResourceGeneralPage.clickCheckoutButton(); + Assert.assertTrue(ResourceGeneralPage.getLifeCycleState().equals(LifeCycleStateEnum.CHECKOUT.getValue()), "Did not succeed to checkout"); + + } catch (Exception e) { + ExtentTestActions.log(Status.ERROR, "Did not succeed to checkout"); + e.printStackTrace(); + } + GeneralUIUtils.waitForLoader(); + } + + //Metadata verification + VfVerificator.verifyOnboardedVnfMetadata(vspName, vspMetadata); + + ExtentTestActions.log(Status.INFO, "Clicking create/update VNF"); + String duration = GeneralUIUtils.getActionDuration(() -> waitUntilVnfCreated()); + ExtentTestActions.log(Status.INFO, "Succeeded in importing/updating " + vspName, duration); + } + else{ + Assert.fail("Did not find VSP named " + vspName); + } + } + + private static void waitUntilVnfCreated() { + GeneralUIUtils.clickOnElementByTestIdWithoutWait(DataTestIdEnum.GeneralElementsEnum.CREATE_BUTTON.getValue()); + GeneralUIUtils.waitForLoader(60*10); + GeneralUIUtils.waitForAngular(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.GeneralElementsEnum.CHECKIN_BUTTON.getValue()); + } + + public static void updateVSP(Pair> vsp) throws Exception{ + ExtentTestActions.log(Status.INFO, "Updating VSP " + vsp.left); + importUpdateVSP(vsp, true); + } + + public static void importVSP(Pair> vsp) throws Exception{ + ExtentTestActions.log(Status.INFO, "Importing VSP " + vsp.left); + importUpdateVSP(vsp, false); + } + + public static void updateVnfAndValidate(String filepath, Pair> vsp, String updatedVnfFile, User user) throws Exception, Throwable { + ExtentTestActions.log(Status.INFO, String.format("Going to update the VNF with %s......", updatedVnfFile)); + System.out.println(String.format("Going to update the VNF with %s......", updatedVnfFile)); + + Map vspMap = vsp.right; + String vspId = vspMap.get("vspId"); + + updateVendorSoftwareProduct(vspId, updatedVnfFile, filepath, user); + HomePage.showVspRepository(); + updateVSP(vsp); + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + DeploymentArtifactPage.verifyArtifactsExistInTable(filepath, updatedVnfFile); + } + + public static Pair> onboardAndValidate(String filepath, String vnfFile, User user) throws Exception { + ExtentTestActions.log(Status.INFO, String.format("Going to onboard the VNF %s", vnfFile)); + System.out.println(String.format("Going to onboard the VNF %s", vnfFile)); + + createVendorLicense(user); + Pair> createVendorSoftwareProduct = createVendorSoftwareProduct(vnfFile, filepath, user); + String vspName = createVendorSoftwareProduct.left; + + DownloadManager.downloadCsarByNameFromVSPRepository(vspName, createVendorSoftwareProduct.right.get("vspId")); + File latestFilefromDir = FileHandling.getLastModifiedFileFromDir(); + + ExtentTestActions.log(Status.INFO, String.format("Searching for onboarded %s", vnfFile)); + HomePage.showVspRepository(); + ExtentTestActions.log(Status.INFO,String.format("Going to import %s", vnfFile.substring(0, vnfFile.indexOf(".")))); + importVSP(createVendorSoftwareProduct); + + ResourceGeneralPage.getLeftMenu().moveToDeploymentArtifactScreen(); + + // Verify deployment artifacts + Map combinedMap = ArtifactFromCsar.combineHeatArtifacstWithFolderArtifacsToMap(latestFilefromDir.getAbsolutePath()); + + LinkedList deploymentArtifacts = ((LinkedList) combinedMap.get("Deployment")); + ArtifactsCorrelationManager.addVNFartifactDetails(vspName, deploymentArtifacts); + + for(HeatMetaFirstLevelDefinition deploymentArtifact: deploymentArtifacts) { + if(deploymentArtifact.getType().equals("HEAT_ENV")) { + continue; + } else if(deploymentArtifact.getFileName().contains(".")) { + ArtifactUIUtils.validateArtifactNameVersionType(deploymentArtifact.getFileName().trim().substring(0, deploymentArtifact.getFileName().lastIndexOf(".")), "1", deploymentArtifact.getType()); + } else { + ArtifactUIUtils.validateArtifactNameVersionType(deploymentArtifact.getFileName().trim(), "1", deploymentArtifact.getType()); + } + + } + + DeploymentArtifactPage.verifyArtifactsExistInTable(filepath, vnfFile); + return createVendorSoftwareProduct; + } + +} + +enum SnmpTypeEnum{ + SNMP_POLL ("snmp"), + SNMP_TRAP ("snmp-trap"); + + private String value; + + public String getValue() { + return value; + } + + private SnmpTypeEnum(String value) { + this.value = value; + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ProductUIUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ProductUIUtils.java new file mode 100644 index 0000000000..9e478c8523 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ProductUIUtils.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import java.awt.AWTException; +import java.util.List; + +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openecomp.sdc.ci.tests.pages.ProductGeneralPage; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +import com.aventstack.extentreports.Status; + +/** + * @author al714h + * + */ + +public class ProductUIUtils { + + protected static WebDriver driver; + + public ProductUIUtils(TestName name, String className) { + super(); + } + + public static void fillProductGeneralPage(ProductReqDetails product, User user) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Fill in metadata values in general page.. ")); + ProductGeneralPage.defineName(product.getName()); + ProductGeneralPage.defineFullName(product.getFullName()); + ProductGeneralPage.defineDescription(product.getDescription()); + ProductGeneralPage.defineProjectCode(product.getProjectCode()); + defineTagsList2(product.getTags()); + ProductGeneralPage.defineContactId(product.getContactId()); + GeneralUIUtils.clickSomewhereOnPage(); + } + + public static void createProduct(ProductReqDetails product, User user) throws Exception, AWTException { + clikAddProduct(); + fillProductGeneralPage(product, user); + GeneralPageElements.clickCreateButton(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Product %s created", product.getName())); + } + + public static void defineTagsList2(List productTags){ + WebElement productTagsTextbox = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.ProductMetadataEnum.TAGS.getValue()); + for (String tag : productTags) { + productTagsTextbox.clear(); + productTagsTextbox.sendKeys(tag); + GeneralUIUtils.waitForAngular(); + productTagsTextbox.sendKeys(Keys.ENTER); + } + } + + public static void clikAddProduct(){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking Add Product button")); + try { + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.Dashboard.ADD_AREA.getValue()); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_PRODUCT.getValue()).click(); + GeneralUIUtils.ultimateWait(); + } catch (Exception e){ + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Exception on catched on Add Product button, retrying ...")); + GeneralUIUtils.hoverOnAreaByClassName("w-sdc-dashboard-card-new"); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_PRODUCT.getValue()).click(); + GeneralUIUtils.ultimateWait(); + } + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/PropertiesUIUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/PropertiesUIUtils.java new file mode 100644 index 0000000000..62b2f832bd --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/PropertiesUIUtils.java @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import java.util.HashMap; +import java.util.Map; + +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.PropertiesPage; +import org.openqa.selenium.WebElement; + +import com.aventstack.extentreports.Status; + +public class PropertiesUIUtils { + + // public static void addPropertByType(String type,String name,String + // defaultValue,String description) throws Exception{ + // + // ResourceUIUtils.defineNewSelectList(type); + // ResourceUIUtils.definePropertyName(name); + // ResourceUIUtils.defineDefaultValueByType(defaultValue); + // ResourceUIUtils.defineDescription(description); + // Thread.sleep(2000); + // ResourceUIUtils.clickButton("Add"); + // } + public static Map addProperties(String name, String itemType, String defaultValue, + String description, String schemaType) throws Exception { + Map propertyvalues = new HashMap(); + GeneralUIUtils.getSelectList(itemType, "propertyType"); + ResourceUIUtils.definePropertyName(name); + if (itemType == "boolean") { + ResourceUIUtils.defineBoolenDefaultValue(defaultValue); + GeneralUIUtils.setWebElementByTestId("description","description"); + Thread.sleep(2000); + GeneralUIUtils.getWebElementByTestID("Add").click(); + ; + } else if (itemType == "list" || itemType == "map") { + GeneralUIUtils.getSelectList(schemaType, "schemaType"); + } + if (!(itemType == "boolean")) { + ResourceUIUtils.defineDefaultValueByType(defaultValue); + GeneralUIUtils.setWebElementByTestId("description", "des"); + GeneralUIUtils.getWebElementByTestID("Add").click(); + ; + Thread.sleep(2000); + } + propertyvalues.put("type", itemType); + propertyvalues.put("defaultValue", defaultValue); + propertyvalues.put("description", description); + propertyvalues.put("name", name); + + return propertyvalues; + } + + public static void vlidateProperties(Map propertyValues) throws InterruptedException { + WebElement name = GeneralUIUtils.getWebElementByTestID(propertyValues.get("name")); + name.getText().equalsIgnoreCase(propertyValues.get("name")); + WebElement defaultValue = GeneralUIUtils.getWebElementByTestID(propertyValues.get("name")); + defaultValue.getText().equalsIgnoreCase(propertyValues.get("defaultValue")); + WebElement type = GeneralUIUtils.getWebElementByTestID(propertyValues.get("type")); + type.getText().equalsIgnoreCase(propertyValues.get("type")); + } + + public static void addNewProperty(PropertyTypeEnum property) { + GeneralUIUtils.ultimateWait(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Adding new %s property", property.name())); + PropertiesPage.clickAddPropertyArtifact(); + PropertiesPage.getPropertyPopup().insertPropertyName(property.getName()); + PropertiesPage.getPropertyPopup().selectPropertyType(property.getType()); + PropertiesPage.getPropertyPopup().insertPropertyDescription(property.getDescription()); + PropertiesPage.getPropertyPopup().insertPropertyDefaultValue(property.getValue()); + PropertiesPage.getPropertyPopup().clickSave(); + } + + public static void updateProperty(PropertyTypeEnum property) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating property: %s", property.name())); + PropertiesPage.clickOnProperty(property.getName()); + PropertiesPage.getPropertyPopup().insertPropertyDescription(property.getDescription()); + PropertiesPage.getPropertyPopup().insertPropertyDefaultValue(property.getValue()); + PropertiesPage.getPropertyPopup().clickSave(); + } + + public static void changePropertyDefaultValueInComposition(String propertyName, String defaultValue) { + GeneralUIUtils.clickOnElementByTestId(propertyName); + PropertiesPage.getPropertyPopup().insertPropertyDefaultValue(defaultValue); + PropertiesPage.getPropertyPopup().clickSave(); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ResourceUIUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ResourceUIUtils.java new file mode 100644 index 0000000000..c76bf4b74a --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ResourceUIUtils.java @@ -0,0 +1,1143 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.awt.AWTException; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.awt.event.KeyEvent; +import java.io.File; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.http.HttpStatus; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.CheckBoxStatusEnum; +import org.openecomp.sdc.ci.tests.datatypes.CreateAndImportButtonsEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.Dashboard; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.StepsEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceCategoriesNameEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openqa.selenium.By; +import org.openqa.selenium.ElementNotVisibleException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.Select; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.testng.AssertJUnit; + +import com.aventstack.extentreports.Status; + +public final class ResourceUIUtils { + public static final String RESOURCE_NAME_PREFIX = "ResourceCDTest-"; + protected static final boolean IS_BEFORE_TEST = true; + public static final String INITIAL_VERSION = "0.1"; + public static final String ICON_RESOURCE_NAME = "call_controll"; + protected static final String UPDATED_RESOURCE_ICON_NAME = "objectStorage"; + + private ResourceUIUtils() { + } + + static WebDriver driver = GeneralUIUtils.getDriver(); + + public static void defineResourceName(String resourceName) { + + WebElement resourceNameTextbox = GeneralUIUtils.getDriver().findElement(By.name("componentName")); + resourceNameTextbox.clear(); + resourceNameTextbox.sendKeys(resourceName); + } + + public static void defineResourceCategory(String category, String datatestsid) { + + GeneralUIUtils.getSelectList(category, datatestsid); + } + + // public static void uploadFileWithJavaRobot(String FilePath,String + // FileName) throws Exception{ + // + // StringSelection Path= new StringSelection(FilePath+FileName); + // Thread.sleep(1000); + // java.awt.Toolkit.getDefaultToolkit().getSystemClipboard().setContents(Path, + // null); + // Robot robot = new Robot(); + // robot.delay(1000); + // robot.keyPress(KeyEvent.VK_CONTROL); + // robot.keyPress(KeyEvent.VK_V); + // robot.keyRelease(KeyEvent.VK_V); + // robot.keyRelease(KeyEvent.VK_CONTROL); + // robot.delay(1000); + // robot.keyPress(KeyEvent.VK_ENTER); + // robot.keyRelease(KeyEvent.VK_ENTER); + // robot.delay(1000); + // } + // click and upload tosca file //**to be changed. + public static void importFileWithSendKey(String FilePath, String FileName, CreateAndImportButtonsEnum type) + throws Exception { + WebElement importButton = HomeUtils.createAndImportButtons(type, driver).findElement(By.tagName("input")); + importButton.sendKeys(FilePath + FileName); + } + + public static void importFileWithSendKeyBrowse(String FilePath, String FileName) throws Exception { + WebElement browsebutton = GeneralUIUtils.getWebElementByTestID("browseButton"); + browsebutton.sendKeys(FilePath + FileName); + } + + // public static void defineVendorName(String resourceVendorName) { + // + // WebElement resourceVendorNameTextbox = + // GeneralUIUtils.getWebElementByTestID("vendorName"); + // resourceVendorNameTextbox.clear(); + // resourceVendorNameTextbox.sendKeys(resourceVendorName); + // } + + // public static void defineTagsList(ResourceReqDetails resource,String + // []resourceTags) { + // Listtaglist = new ArrayList();; + // WebElement resourceTagsTextbox = + // GeneralUIUtils.getWebElementByTestID("i-sdc-tag-input"); + // for (String tag : resourceTags) { + // resourceTagsTextbox.clear(); + // resourceTagsTextbox.sendKeys(tag); + // resourceTagsTextbox.sendKeys(Keys.ENTER); + // taglist.add(tag); + // } + // resource.setTags(taglist); + // } + + public static String defineUserId(String userId) { + // + WebElement resourceUserIdTextbox = ResourceGeneralPage.getContactIdField(); + resourceUserIdTextbox.clear(); + resourceUserIdTextbox.sendKeys(userId); + return userId; + } + + public static void defineVendorRelease(String resourceVendorRelease) { + + WebElement resourceVendorReleaseTextbox = GeneralUIUtils.getWebElementByTestID("vendorRelease"); + resourceVendorReleaseTextbox.clear(); + resourceVendorReleaseTextbox.sendKeys(resourceVendorRelease); + } + + public static void selectResourceIcon(String resourceIcon) throws Exception { + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), 10); + wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[@data-tests-id='" + resourceIcon + "']"))) + .click(); + } + + public static String definePropertyName(String name) { + + WebElement nameProperty = GeneralUIUtils.getDriver().findElement(By.name("propertyName")); + nameProperty.sendKeys(name); + return name; + } + + public static void selectRandomResourceIcon() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.ICON); + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), 4); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(@data-tests-id, 'iconBox')]"))); + List iconElement = GeneralUIUtils.getDriver() + .findElements(By.xpath("//*[contains(@data-tests-id, 'iconBox')]")); + iconElement.get(0).click(); + } + + public static List getAllObjectsOnWorkspace(WebDriver driver, ResourceReqDetails resource) + throws Exception { + + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), 10); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@*='" + resource.getName() + "']"))); + return GeneralUIUtils.getDriver() + .findElements(By.xpath("//div[@class='" + "w-sdc-dashboard-card-info-name" + "']")); + + } + + public static String getErrorMessageText(String text) throws Exception { + + return GeneralUIUtils.getWebElementByClassName(text).getText(); + + } + + public static WebElement scrollElement(WebDriver driver) throws Exception { + + return GeneralUIUtils.getDriver().findElement(By.className("ps-scrollbar-y")); + } + + public static void scrollDownPage() throws AWTException, InterruptedException { + Robot robot = new Robot(); + robot.keyPress(KeyEvent.VK_PAGE_DOWN); + robot.keyRelease(KeyEvent.VK_PAGE_DOWN); + robot.keyPress(KeyEvent.VK_PAGE_DOWN); + robot.keyRelease(KeyEvent.VK_PAGE_DOWN); + robot.keyPress(KeyEvent.VK_PAGE_DOWN); + robot.keyRelease(KeyEvent.VK_PAGE_DOWN); + robot.keyPress(KeyEvent.VK_PAGE_DOWN); + robot.keyRelease(KeyEvent.VK_PAGE_DOWN); + robot.keyPress(KeyEvent.VK_PAGE_DOWN); + robot.keyRelease(KeyEvent.VK_PAGE_DOWN); + robot.keyPress(KeyEvent.VK_PAGE_DOWN); + robot.keyRelease(KeyEvent.VK_PAGE_DOWN); + robot.keyPress(KeyEvent.VK_PAGE_DOWN); + robot.keyRelease(KeyEvent.VK_PAGE_DOWN); + } + + public static void defineNewSelectList(String Text) { + WebElement mySelectElm = GeneralUIUtils.getDriver().findElement(By.className("i-sdc-form-select")); + Select mySelectString = new Select(mySelectElm); + mySelectString.selectByVisibleText(Text); + } + + public static void defineDefaultValueByType(String Value) { + + WebElement valueString = GeneralUIUtils.getDriver().findElement(By.name("value")); + valueString.clear(); + valueString.sendKeys(Value); + } + + public static void defineBoolenDefaultValue(String Value) { + + WebElement elementBoolean = GeneralUIUtils.getDriver().findElement(By.name("value")); + Select se = new Select(elementBoolean); + se.selectByValue(Value); + } + + public static void clickButtonBlue() { + WebElement clickButtonBlue = GeneralUIUtils.getDriver().findElement(By.className("w-sdc-btn-blue")); + clickButtonBlue.click(); + } + + public static void clickButton(String selectButton) { + + WebElement clickButton = GeneralUIUtils.getDriver() + .findElement(By.xpath("//*[@data-tests-id='" + selectButton + "']")); + clickButton.click(); + } + + public static WebElement Waitfunctionforbuttons(String element, int timeout) { + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), timeout); + return wait.until(ExpectedConditions.elementToBeClickable(By.xpath(element))); + } + + public static WebElement waitToButtonSubmitForTesting() { + return Waitfunctionforbuttons("//*[@data-tests-id='submitForTesting']", 10); + } + + public static WebElement waitToFinishButtonEnabled() { + return Waitfunctionforbuttons("//button[@data-tests-id='Finish']", 10); + } + + public static WebElement waitToNextButtonEnabled() { + return Waitfunctionforbuttons("//button[@data-tests-id='Next']", 10); + } + + public static WebElement waitToHomeMenu() { + return Waitfunctionforbuttons("//*[@data-tests-id='main-menu-button-home']", 10); + } + + public static WebElement waitToCatalogMenu() { + return Waitfunctionforbuttons("//*[@data-tests-id='main-menu-button-catalog']", 10); + } + + public static WebElement waitSearch() { + return Waitfunctionforbuttons("//*[@data-tests-id='main-menu-input-search']", 10); + } + + public static WebElement waitSubmitforTestingCard() { + return Waitfunctionforbuttons("//*[@data-tests-id='i-sdc-dashboard-card-menu-item-SubmitforTesting']", 10); + } + + public static WebElement waitViewCard() { + return Waitfunctionforbuttons("//*[@data-tests-id='i-sdc-dashboard-card-menu-item-View']", 5); + } + +// public static void waitOpenCard(String requiredElementUniqueId) throws Exception { +// WebElement menu = GeneralUIUtils.getDriver() +// .findElement(By.xpath("//*[@data-tests-id='" + requiredElementUniqueId + "']")); +// GeneralUIUtils.hoverOnAreaByTestId(menu); +// } + + public static void fillResourceGeneralInformationPage(ResourceReqDetails resource, User user, boolean isNewResource) { + try { + ResourceGeneralPage.defineName(resource.getName()); + ResourceGeneralPage.defineDescription(resource.getDescription()); + ResourceGeneralPage.defineCategory(resource.getCategories().get(0).getSubcategories().get(0).getName()); + ResourceGeneralPage.defineVendorName(resource.getVendorName()); + ResourceGeneralPage.defineVendorRelease(resource.getVendorRelease()); + if (isNewResource){ + ResourceGeneralPage.defineTagsList(resource, new String[] { "This-is-tag", "another-tag", "Test-automation-tag" }); + } + else{ + ResourceGeneralPage.defineTagsList(resource, new String[] { "one-more-tag" }); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void fillMaxValueResourceGeneralInformationPage(ResourceReqDetails resource) { + String stringPattern = "ABCDabcd123456"; + GeneralUIUtils.addStringtoClipboard(buildStringFromPattern(stringPattern, 5000)); + ResourceGeneralPage.defineNameWithPaste(); + ResourceGeneralPage.defineDescriptionWithPaste(); + ResourceGeneralPage.defineVendorNameWithPaste(); + ResourceGeneralPage.defineVendorReleaseWithPaste(); +// ResourceGeneralPage.defineName(buildStringFromPattern(stringPattern, 5000)); +// ResourceGeneralPage.defineDescription(buildStringFromPattern(stringPattern, 5000)); +// ResourceGeneralPage.defineVendorName(buildStringFromPattern(stringPattern, 5000)); +// ResourceGeneralPage.defineVendorRelease(buildStringFromPattern(stringPattern, 5000)); +// ResourceGeneralPage.defineTagsList(resource, new String[] { buildStringFromPattern(stringPattern, 5000) }); + ResourceGeneralPage.defineTagsListWithPaste(); + GeneralUIUtils.waitForAngular(); + } + + public static String buildStringFromPattern(String stringPattern, int stringLength){ + char[] chars = stringPattern.toCharArray(); + StringBuilder sb = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < stringLength; i++) { + char c = chars[random.nextInt(chars.length)]; + sb.append(c); + } + return sb.toString(); + } + + public static void fillNewResourceValues(ResourceReqDetails resource, User user) throws Exception { + fillResourceGeneralInformationPage(resource, user, true); + GeneralPageElements.clickCreateButton(); + // selectIcon(); + } + + // coded by teddy. + + public static WebElement waitfunctionforallelements(String element) { + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), 5); + return wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@*='" + element + "']"))); + } + + public static WebElement waitFunctionForaGetElements(String element, int timeout) { + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), timeout); + return wait.until( + ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@data-tests-id='" + element + "']"))); + } + + public static void getVFCGeneralInfo(ResourceReqDetails resource, User user) throws InterruptedException { + Thread.sleep(2000); + String version = GeneralUIUtils.getWebElementsListByTestID("versionvalue").get(0).getText().substring(1); + String name = GeneralUIUtils.getWebElementByTestID("name").getAttribute("value"); + String description = GeneralUIUtils.getWebElementByTestID("description").getAttribute("value"); + String category = GeneralUIUtils.getSelectList(null, "selectGeneralCategory").getFirstSelectedOption() + .getText(); + String vendorName = GeneralUIUtils.getWebElementByTestID("vendorName").getAttribute("value"); + String vendorRelease = GeneralUIUtils.getWebElementByTestID("vendorRelease").getAttribute("value"); + List tags = GeneralUIUtils.getWebElementsListByTestID("i-sdc-tag-text"); + String type = GeneralUIUtils.getWebElementsListByTestID("type").get(1).getText(); + int index = type.lastIndexOf(":"); + System.out.println(type.substring(0, index)); + String AttContact = GeneralUIUtils.getWebElementByTestID("attContact").getAttribute("value"); + System.out.println(resource.getVersion()); + assertTrue(resource.getVersion().equals(version)); + assertTrue(resource.getName().equals(name)); + assertTrue(resource.getDescription().equals(description)); + System.out.println(resource.getVendorName()); + System.out.println(resource.getVendorRelease()); + assertTrue(resource.getCategories().get(0).getSubcategories().get(0).getName().equals(category)); + assertTrue(resource.getVendorName().equals(vendorName)); + assertTrue(resource.getVendorRelease().equals(vendorRelease)); + assertTrue(resource.getCreatorUserId().equals(AttContact)); + assertEquals(type.substring(0, index), resource.getResourceType()); + + for (int i = 0; i < tags.size(); i++) { + assertEquals(resource.getTags().get(i), tags.get(i).getText()); + } + } + + public static void getGeneralInfo(ResourceReqDetails resource, User user) { + + // clickMore(); + // String + // componentType=waitFunctionForaGetElements("componentType",3).getText(); + // String version=waitFunctionForaGetElements("version",3).getText(); + // String + // category=waitFunctionForaGetElements("category",3).getText();//get + // right panel Category. + // String + // resourceType=waitFunctionForaGetElements("resourceType",3).getText();//get + // right panel SubCategory. + // String date=waitfunctionforelements("creationDate",3).getText(); + // String aouthor=waitfunctionforallelements("author'",3).getText(); + // String + // vendorName=waitFunctionForaGetElements("vendorName",3).getText(); + // String + // vendorRelease=waitFunctionForaGetElements("vendorRelease",3).getText(); + // String + // AttContact=waitFunctionForaGetElements("attContact",3).getText(); + // String + // Description=waitFunctionForaGetElements("description",3).getText(); + List tags = GeneralUIUtils.getWebElementsListByTestID("tag"); + // // String TagVF=waitFunctionForaGetElements("tag",3).getText(); + // assertTrue(componentType.equals("RESOURCE")); + // assertTrue(version.equals(resource.getVersion())); + // assertTrue(category.equals(resource.getCategories().get(0).getName())); + // assertEquals(resourceType,resource.getResourceType()); + // // assertEquals(Date,resource.getCreationDate()); + // // assertEquals(Aouthor,resource.getCreatorFullName()); + // assertTrue(vendorName.equals(resource.getVendorName())); + // assertTrue(vendorRelease.equals(resource.getVendorRelease())); + // assertTrue(AttContact.equals(resource.getAttContact())); + // assertTrue(Description.equals(resource.getDescription()+"\nLess")); + for (WebElement tag : tags) { + System.out.println(resource.getTags().get(0)); + } + } + + public static void getGeneralInfoForTags(ResourceReqDetails resource, User user) { + + clickMore(); + String componentType = waitFunctionForaGetElements("componentType", 3).getText(); + String version = waitFunctionForaGetElements("version", 3).getText(); + String category = waitFunctionForaGetElements("category", 3).getText();// get + // right + // panel + // Category. + String resourceType = waitFunctionForaGetElements("resourceType", 3).getText();// get + // right + // panel + // SubCategory. + String date = GeneralUIUtils.getWebElementByClassName("creationDate").getText(); + String aouthor = waitfunctionforallelements("author'").getText(); + String vendorName = waitFunctionForaGetElements("vendorName", 3).getText(); + String vendorRelease = waitFunctionForaGetElements("vendorRelease", 3).getText(); + String attContact = waitFunctionForaGetElements("attContact", 3).getText(); + String description = waitFunctionForaGetElements("description", 3).getText(); + List tags = GeneralUIUtils.getWebElementsListByTestID("tag"); + assertTrue(componentType.equals("RESOURCE")); + assertTrue(version.equals(resource.getVersion())); + assertTrue(category.equals(resource.getCategories().get(0).getName())); + assertEquals(resourceType, resource.getResourceType()); + // assertEquals(Date,resource.getCreationDate()); + // assertEquals(Aouthor,resource.getCreatorFullName()); + assertTrue(vendorName.equals(resource.getVendorName())); + assertTrue(vendorRelease.equals(resource.getVendorRelease())); + assertTrue(attContact.equals(resource.getContactId())); + assertTrue(description.equals(resource.getDescription() + "\nLess")); + assertTrue(tags.equals("Tag-150")); + } + + public static WebElement searchVFNameInWorkspace(ResourceReqDetails resource, User user) throws Exception { + + List findElements = GeneralUIUtils.getDriver() + .findElements(By.xpath("//div[@data-tests-id='" + resource.getUniqueId() + "']")); + assertNotNull("did not find any elements", findElements); + for (WebElement webElement : findElements) { + if (webElement.getText().contains(resource.getUniqueId())) { + System.out.println("I find it"); + return webElement; + } + } + return null; + } + + public static Boolean searchCheckOutWorkspace(ResourceReqDetails resource, User user, + CheckBoxStatusEnum checkBoxStatusEnum) throws Exception { + + List findElements = GeneralUIUtils.getDriver() + .findElements(By.xpath("//div[@data-tests-id='component.lifecycleState']")); + assertNotNull("did not find any elements", findElements); + for (WebElement webElement : findElements) { + if (!webElement.getAttribute("class").contains(checkBoxStatusEnum.name())) { + return false; + } + } + return true; + } + + // coded by tedy. + public static void validateWithRightPalett(ResourceReqDetails resource, User user) { + // String + // Type=Waitfunctionforallelements("sharingService.selectedEntity.getTypeForView()",3).getText(); + String ResourceType = waitfunctionforallelements("selectedComponent.resourceType").getText(); + System.out.println(ResourceType); + String Version = waitfunctionforallelements("selectedComponent.version").getText(); + String Category = waitfunctionforallelements("selectedComponent.categories[0].name").getText();// get + // right + // panel + // Category. + String CanvasSubCategory = waitfunctionforallelements("selectedComponent.categories[0].subcategories[0].name") + .getText();// get right panel SubCategory. + // String Date=Waitfunctionforelements("selectedComponent.creationDate | + // date: 'MM/dd/yyyy'").getText(); + // String + // Aouthor=waitfunctionforallelements("selectedComponent.creatorFullName'").getText(); + String VendorName = waitfunctionforallelements("selectedComponent.vendorName").getText(); + String VendorRelease = waitfunctionforallelements("selectedComponent.vendorRelease").getText(); + String AttContact = waitfunctionforallelements("selectedComponent.attContact").getText(); + String Description = waitfunctionforallelements("selectedComponent.description").getText(); + String TagVF = waitfunctionforallelements("tag").getText(); + AssertJUnit.assertEquals(ResourceType, resource.getResourceType()); + AssertJUnit.assertEquals(Version, resource.getVersion()); + AssertJUnit.assertEquals(Category, resource.getCategories().get(0).getName()); + AssertJUnit.assertEquals(CanvasSubCategory, + resource.getCategories().get(0).getSubcategories().get(0).getName()); + // assertEquals(Date,resource.getCreationDate()); + // assertEquals(Aouthor,resource.getCreatorFullName()); + AssertJUnit.assertEquals(VendorName, resource.getVendorName()); + AssertJUnit.assertEquals(VendorRelease, resource.getVendorRelease()); + AssertJUnit.assertEquals(AttContact, resource.getContactId()); + AssertJUnit.assertEquals(Description, resource.getDescription() + "\nLess"); + AssertJUnit.assertEquals(TagVF, "qa123"); + } + + public static void clickMore() { + WebElement clickButtonSubmit = GeneralUIUtils.getDriver() + .findElement(By.className("ellipsis-directive-more-less")); + clickButtonSubmit.click(); + } + + public static RestResponse createResourceInUI(ResourceReqDetails resource, User user) + throws Exception, AWTException { + System.out.println("creating resource..."); + fillNewResourceValues(resource, user); + RestResponse getCreatedResource = RestCDUtils.getResource(resource, user); + AssertJUnit.assertEquals("Did not succeed to get any resource", HttpStatus.SC_OK, + getCreatedResource.getErrorCode().intValue()); + + return getCreatedResource; + } + + public static void createResource(ResourceReqDetails resource, User user) throws Exception { + ExtentTestActions.log(Status.INFO, "Going to create a new VF."); + WebElement addVFButton = null; + try { + GeneralUIUtils.ultimateWait(); + try{ + GeneralUIUtils.hoverOnAreaByClassName("w-sdc-dashboard-card-new"); + addVFButton = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_VF.getValue()); + } + catch (Exception e){ + File imageFilePath = GeneralUIUtils.takeScreenshot(null, SetupCDTest.getScreenshotFolder(), "Warning_" + resource.getName()); + final String absolutePath = new File(SetupCDTest.getReportFolder()).toURI().relativize(imageFilePath.toURI()).getPath(); + SetupCDTest.getExtendTest().log(Status.WARNING, "Add VF button is not visible after hover on import area of Home page, moving on ..." + SetupCDTest.getExtendTest().addScreenCaptureFromPath(absolutePath)); + showButtonsADD(); + addVFButton = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_VF.getValue()); + } + addVFButton.click(); + GeneralUIUtils.ultimateWait(); + } + catch (Exception e ) { + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Exeption catched on ADD VF button, retrying ... ")); + GeneralUIUtils.hoverOnAreaByClassName("w-sdc-dashboard-card-new"); + GeneralUIUtils.ultimateWait(); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_VF.getValue()).click(); + GeneralUIUtils.ultimateWait(); + } + fillResourceGeneralInformationPage(resource, user, true); + resource.setVersion("0.1"); + GeneralPageElements.clickCreateButton(); + } + + public static void updateResource(ResourceReqDetails resource, User user){ + ResourceGeneralPage.defineContactId(resource.getContactId()); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Updating General screen fields ...")); + fillResourceGeneralInformationPage(resource, user, false); + ResourceGeneralPage.clickUpdateButton(); + } + + + + public static RestResponse updateResourceInformationPage(ResourceReqDetails resource, User user) + throws Exception, AWTException { + + fillResourceGeneralInformationPage(resource, user, true); + GeneralPageElements.clickCreateButton(); + return null; + + } + + public static RestResponse checkInResourceInUI(ResourceReqDetails resource, User user) throws Exception { + + WebElement ASDCLink = GeneralUIUtils.getDriver().findElement(By.className("w-sdc-header-logo-link")); + ASDCLink.click(); + Thread.sleep(2000); + + List listFormInput = GeneralUIUtils.getDriver() + .findElements(By.className("i-sdc-left-sidebar-nav-item")); + WebElement addPropertyElement = listFormInput.get(0); + addPropertyElement.click(); + Thread.sleep(2000); + + WebElement searchResource = GeneralUIUtils.getDriver() + .findElement(By.className("w-sdc-header-catalog-search-input")); + searchResource.sendKeys("newresource4test"); + + Thread.sleep(1000); + + WebElement buttonClickMenu = GeneralUIUtils.getDriver() + .findElement(By.className("w-sdc-dashboard-card-menu-button")); + buttonClickMenu.click(); + + WebElement clickMenu = GeneralUIUtils.getDriver().findElement(By.className("w-sdc-dashboard-card-menu")); + clickMenu.click(); + + List clickCheckIn = GeneralUIUtils.getDriver() + .findElements(By.className("i-sdc-dashboard-card-menu-item")); + WebElement clickCheckInMenu = clickCheckIn.get(1); + clickCheckInMenu.click(); + + WebElement descriptionForSubmit = GeneralUIUtils.getDriver() + .findElement(By.className("w-sdc-modal-body-comment")); + descriptionForSubmit.sendKeys("checkin resource"); + Thread.sleep(2000); + WebElement clickButtonSubmitTwo = GeneralUIUtils.getDriver().findElement(By.className("w-sdc-btn-blue")); + clickButtonSubmitTwo.click(); + Thread.sleep(2000); + + WebElement buttonClickMenu1 = GeneralUIUtils.getDriver() + .findElement(By.className("w-sdc-dashboard-card-menu-button")); + buttonClickMenu1.click(); + + WebElement clickMenu1 = GeneralUIUtils.getDriver().findElement(By.className("w-sdc-dashboard-card-menu")); + clickMenu1.click(); + + List clickCheckOut = GeneralUIUtils.getDriver() + .findElements(By.className("i-sdc-dashboard-card-menu-item")); + WebElement clickCheckOutMenu = clickCheckOut.get(0); + clickCheckOutMenu.click(); + + Thread.sleep(3000); + RestResponse getResource = RestCDUtils.getResource(resource, user); + AssertJUnit.assertEquals("Did not succeed to get resource after create", 200, + getResource.getErrorCode().intValue()); + return getResource; + + } + + public static String lifeCycleStateUI() throws InterruptedException { + return GeneralUIUtils.getWebElementByTestID("formlifecyclestate").getText(); + } + + public static List catalogFilterResourceCategoriesChecBox(ResourceCategoriesNameEnum enumName) + throws Exception { + List categories = Arrays.asList(); + switch (enumName) { + case APPLICATIONL4: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("applicationServer", "defaulticon", "vl", "cp", "call_controll", "borderElement", + "network", "firewall", "database", "loadBalancer"); + break; + case APPLICATION_SERVER: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("applicationServer", "vl", "cp", "defaulticon"); + break; + case BORDER_ELEMENT: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("borderElement", "vl", "cp", "defaulticon"); + break; + case CALL_CONTROL: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("call_controll", "vl", "cp", "defaulticon"); + break; + case COMMON_NETWORK_RESOURCES: + GeneralUIUtils.getWebElementByLinkText("Common Network Resources").click(); + categories = Arrays.asList("network", "vl", "cp", "defaulticon"); + break; + case CONNECTION_POINTS: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("cp", "defaulticon"); + break; + case DATABASE: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("database", "vl", "cp", "defaulticon"); + break; + case DATABASE_GENERIC: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("database", "vl", "cp", "defaulticon"); + break; + case FIREWALL: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("firewall", "vl", "cp", "defaulticon"); + break; + case GATEWAY: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("gateway", "vl", "cp", "defaulticon"); + break; + case INFRASTRUCTURE: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("connector", "vl", "cp", "defaulticon"); + break; + case INFRASTRUCTUREL23: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("ucpe", "vl", "cp", "defaulticon"); + break; + case LAN_CONNECTORS: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("network", "port", "connector", "vl", "cp", "defaulticon"); + break; + case LOAD_BALANCER: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("loadBalancer", "vl", "cp", "defaulticon"); + break; + case MEDIA_SERVERS: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("network", "vl", "cp", "defaulticon"); + break; + case NETWORKL4: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("network", "vl", "cp", "defaulticon"); + break; + case NETWORK_ELEMENTS: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("port", "defaulticon", "network", "connector", "vl", "cp"); + break; + case NETWORK_L23: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("network", "vl", "defaulticon", "cp", "router", "port", "connector", "gateway", + "ucpe"); + break; + case NETWORK_CONNECTIVITY: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("network", "vl", "cp", "defaulticon"); + break; + case GENERIC: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("database", "port", "loadBalancer", "vl", "cp", "objectStorage", "compute", + "defaulticon", "ucpe", "network", "connector"); + break; + case ABSTRACT: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("objectStorage", "compute", "defaulticon", "cp", "vl"); + break; + case Router: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("router", "vl", "cp", "defaulticon"); + break; + case VIRTUAL_LINKS: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("vl", "defaulticon"); + break; + case WAN_Connectors: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("network", "port", "connector", "vl", "cp", "defaulticon"); + break; + case WEB_SERVER: + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + categories = Arrays.asList("applicationServer", "vl", "cp", "defaulticon"); + break; + } + return categories; + } + + public static void deleteVersionInUI() throws Exception { + + waitToDeleteVersion().click(); + ResourceUIUtils.clickButtonBlue(); + } + + public static void selectTabInRightPallete(String className) throws Exception { + WebElement tab = GeneralUIUtils.getWebElementByClassName(className); + tab.click(); + } + + public static WebElement waitToDeleteVersion() { + return Waitfunctionforbuttons("//*[@data-tests-id='deleteVersion']", 10); + } + + public static WebElement rihtPanelAPI() { + return waitFunctionForaGetElements("tab-api", 10); + } + + /** + * Click on HTML element. + * + * @param dataTestId + * @throws Exception + */ + public static void getWebElementByTestID(String dataTestId) throws Exception { + WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), 20); + WebElement element = wait + .until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@data-tests-id='" + dataTestId + "']"))); + element.click(); + // wait.until(ExpectedConditions.elemetto) + // WebElement serviceButton = + // GeneralUIUtils.getDriver().findElement(By.xpath("//*[@data-tests-id='" + // + dataTestId + "']")); + // serviceButton. + // serviceButton.click(); + } + + /** + * Move to HTML element by class name. When moving to the HTML element, it + * will raise hover event. + * + * @param className + */ +// public static void moveToHTMLElementByClassName(String className) { +// Actions actions = new Actions(GeneralUIUtils.getDriver()); +// final WebElement createButtonsArea = GeneralUIUtils +// .retryMethodOnException(() -> GeneralUIUtils.getDriver().findElement(By.className(className))); +// actions.moveToElement(createButtonsArea).perform(); +// } + + /** + * Move to HTML element by element id. When moving to the HTML element, it + * will raise hover event. + * + * @param className + */ +// static void moveToHTMLElementByDataTestId(String dataTestId) { +// // WebElement hoverArea = +// // GeneralUIUtils.getDriver().findElement(By.xpath("//*[@data-tests-id='" +// // + dataTestId + "']")); +// WebElement hoverArea = GeneralUIUtils.waitForElementVisibility(dataTestId); +// // WebDriverWait wait = new WebDriverWait(GeneralUIUtils.getDriver(), +// // 30); +// // wait.until(ExpectedConditions.visibilityOf(hoverArea)); +// +// Actions actions = new Actions(GeneralUIUtils.getDriver()); +// actions.moveToElement(hoverArea).perform(); +// } + + // public static ResourceReqDetails createResourceInUI(User user){ + // try{ + // ResourceReqDetails defineResourceDetails = + // defineResourceDetails(ResourceTypeEnum.VF); + // ResourceUIUtils.moveToHTMLElementByClassName("w-sdc-dashboard-card-new"); + // ResourceUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_VF.getValue()); + // GeneralUIUtils.waitForLoader(); + //// GeneralUIUtils.sleep(1000); + // fillResourceGeneralInformationPage(defineResourceDetails, user); + // GeneralPageElements.clickCreateButton(); + // return defineResourceDetails; + // } + // catch( Exception e){ + // throw new RuntimeException(e); + // } + // } + + /** + * Import VFC + * + * @param user + * @param filePath + * @param fileName + * @return + * @throws Exception + */ + + public static void importVfc(ResourceReqDetails resourceMetaData, String filePath, String fileName, User user) + throws Exception { + GeneralUIUtils.ultimateWait(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating new VFC resource ", resourceMetaData.getName())); + GeneralUIUtils.hoverOnAreaByTestId(Dashboard.IMPORT_AREA.getValue()); + GeneralUIUtils.ultimateWait(); + // Insert file to the browse dialog + WebElement buttonVFC = GeneralUIUtils.findByText("Import VFC"); + WebElement fileInputElement = GeneralUIUtils.getInputElement(DataTestIdEnum.Dashboard.IMPORT_VFC_FILE.getValue()); + if (!buttonVFC.isDisplayed()){ + File imageFilePath = GeneralUIUtils.takeScreenshot(null, SetupCDTest.getScreenshotFolder(), "Warning_" + resourceMetaData.getName()); + final String absolutePath = new File(SetupCDTest.getReportFolder()).toURI().relativize(imageFilePath.toURI()).getPath(); + SetupCDTest.getExtendTest().log(Status.WARNING, "VFC button not visible after hover on import area of Home page, moving on ..." + SetupCDTest.getExtendTest().addScreenCaptureFromPath(absolutePath)); + } + try{ + fileInputElement.sendKeys(filePath + fileName); + } catch (ElementNotVisibleException e) { + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Exeption catched on file input, converting VFC file input to visible")); + showButtons(); + fileInputElement.sendKeys(filePath + fileName); + } + // Fill the general page fields. + GeneralUIUtils.ultimateWait(); + fillResourceGeneralInformationPage(resourceMetaData, user, true); + GeneralPageElements.clickCreateButton(); + } + + public static void importVfcNoCreate(ResourceReqDetails resourceMetaData, String filePath, String fileName, User user) + throws Exception { + GeneralUIUtils.hoverOnAreaByTestId(Dashboard.IMPORT_AREA.getValue()); + // Insert file to the browse dialog + WebElement buttonVFC = GeneralUIUtils.findByText("Import VFC"); + WebElement fileInputElement = GeneralUIUtils.getInputElement(DataTestIdEnum.Dashboard.IMPORT_VFC_FILE.getValue()); + if (!buttonVFC.isDisplayed()){ + File imageFilePath = GeneralUIUtils.takeScreenshot(null, SetupCDTest.getScreenshotFolder(), "Warning_" + resourceMetaData.getName()); + final String absolutePath = new File(SetupCDTest.getReportFolder()).toURI().relativize(imageFilePath.toURI()).getPath(); + SetupCDTest.getExtendTest().log(Status.WARNING, "VFC button not visible after hover on import area of Home page, moving on ..." + SetupCDTest.getExtendTest().addScreenCaptureFromPath(absolutePath)); + } + try{ + fileInputElement.sendKeys(filePath + fileName); + } catch (ElementNotVisibleException e) { + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Exeption catched on file input, converting VFC file input to visible")); + showButtons(); + fileInputElement.sendKeys(filePath + fileName); + } + // Fill the general page fields. + GeneralUIUtils.waitForLoader(); + fillResourceGeneralInformationPage(resourceMetaData, user, true); + } + + + public static void importVfFromCsar(ResourceReqDetails resourceMetaData, String filePath, String fileName, User user) + throws Exception { + GeneralUIUtils.ultimateWait(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating new VF asset resource %s", resourceMetaData.getName())); + GeneralUIUtils.hoverOnAreaByTestId(Dashboard.IMPORT_AREA.getValue()); + GeneralUIUtils.ultimateWait(); + // Insert file to the browse dialog + WebElement buttonDCAE = GeneralUIUtils.findByText("Import DCAE asset"); + WebElement fileInputElement = GeneralUIUtils.getInputElement(DataTestIdEnum.Dashboard.IMPORT_VF_FILE.getValue()); + if (!buttonDCAE.isDisplayed()){ + File imageFilePath = GeneralUIUtils.takeScreenshot(null, SetupCDTest.getScreenshotFolder(), "Warning_" + resourceMetaData.getName()); + final String absolutePath = new File(SetupCDTest.getReportFolder()).toURI().relativize(imageFilePath.toURI()).getPath(); + SetupCDTest.getExtendTest().log(Status.WARNING, "DCAE button not visible after hover on import area of Home page, moving on ..." + SetupCDTest.getExtendTest().addScreenCaptureFromPath(absolutePath)); + } + try{ + fileInputElement.sendKeys(filePath + fileName); + } catch (ElementNotVisibleException e) { + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Exeption catched on file input, converting DCAE file input to visible")); + showButtons(); + fileInputElement.sendKeys(filePath + fileName); + } + // Fill the general page fields. + GeneralUIUtils.ultimateWait(); + fillResourceGeneralInformationPage(resourceMetaData, user, true); + GeneralPageElements.clickCreateButton(10*60); +// GeneralUIUtils.ultimateWait(); "don't change import of csar can take longer then 3 minutes" + GeneralUIUtils.waitForLoader(10*60); + } + + public static void importVfFromCsarNoCreate(ResourceReqDetails resourceMetaData, String filePath, String fileName, User user) + throws Exception { + GeneralUIUtils.ultimateWait(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Creating new VF asset resource %s, Create button will not be clicked", resourceMetaData.getName())); + GeneralUIUtils.hoverOnAreaByTestId(Dashboard.IMPORT_AREA.getValue()); + GeneralUIUtils.ultimateWait(); + // Insert file to the browse dialog + WebElement buttonDCAE = GeneralUIUtils.findByText("Import DCAE asset"); + WebElement fileInputElement = GeneralUIUtils.getInputElement(DataTestIdEnum.Dashboard.IMPORT_VF_FILE.getValue()); + if (!buttonDCAE.isDisplayed()){ + File imageFilePath = GeneralUIUtils.takeScreenshot(null, SetupCDTest.getScreenshotFolder(), "Warning_" + resourceMetaData.getName()); + final String absolutePath = new File(SetupCDTest.getReportFolder()).toURI().relativize(imageFilePath.toURI()).getPath(); + SetupCDTest.getExtendTest().log(Status.WARNING, "DCAE button not visible after hover on import area of Home page, moving on ..." + SetupCDTest.getExtendTest().addScreenCaptureFromPath(absolutePath)); + } + try{ + fileInputElement.sendKeys(filePath + fileName); + } catch (ElementNotVisibleException e) { + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Exeption catched on file input, converting DCAE file input to visible")); + showButtons(); + fileInputElement.sendKeys(filePath + fileName); + } + // Fill the general page fields. + GeneralUIUtils.ultimateWait(); + fillResourceGeneralInformationPage(resourceMetaData, user, true); + GeneralUIUtils.waitForLoader(10*60); + } + + public static void updateVfWithCsar(String filePath, String fileName) { + ExtentTestActions.log(Status.INFO, "Updating VF with updated CSAR file named " + fileName); + WebElement browseWebElement = GeneralUIUtils.getInputElement(DataTestIdEnum.GeneralElementsEnum.UPLOAD_FILE_INPUT.getValue()); + browseWebElement.sendKeys(filePath + fileName); + GeneralUIUtils.ultimateWait(); + GeneralPageElements.clickUpdateButton(); + GeneralUIUtils.waitForLoader(); + ExtentTestActions.log(Status.INFO, "VF is updated."); + } + + + + // public static ResourceReqDetails importVfcInUI(User user, String + // filePath, String fileName, ResourceTypeEnum resourceType) { + // ResourceReqDetails defineResourceDetails = + // defineResourceDetails(resourceType); + // ResourceUIUtils.moveToHTMLElementByDataTestId(Dashboard.IMPORT_AREA.getValue()); + // + // // Insert file to the browse dialog + // final WebElement browseWebElement = + // GeneralUIUtils.getWebElementByDataTestId(DataTestIdEnum.Dashboard.IMPORT_VFC_FILE.getValue()); + // browseWebElement.sendKeys(filePath + fileName); + // + // // Fill the general page fields. + // GeneralUIUtils.waitForLoader(); + // fillResourceGeneralInformationPage(defineResourceDetails, user); + // GeneralPageElements.clickCreateButton(); + // return defineResourceDetails; + // } + + /** + * Import VF + * + * @param user + * @param filePath + * @param fileName + * @return + * @throws Exception + */ + // public static ResourceReqDetails importVfInUI(User user, String filePath, + // String fileName) throws Exception { + // ResourceReqDetails defineResourceDetails = + // defineResourceDetails(ResourceTypeEnum.VF); + // ResourceUIUtils.moveToHTMLElementByDataTestId(Dashboard.IMPORT_AREA.getValue()); + // + // // Insert file to the browse dialog + // final WebElement browseWebElement = + // GeneralUIUtils.getWebElementByDataTestId(DataTestIdEnum.Dashboard.IMPORT_VF_FILE.getValue()); + // browseWebElement.sendKeys(filePath + fileName); + // + // // Fill the general page fields. + // GeneralUIUtils.waitForLoader(); + // fillResourceGeneralInformationPage(defineResourceDetails, user); + // GeneralPageElements.clickCreateButton(); + // return defineResourceDetails; + // } + + // public static ResourceReqDetails defineResourceDetails(ResourceTypeEnum + // resourceType) { + // ResourceReqDetails resource = new ResourceReqDetails(); + // resource = ElementFactory.getDefaultResource(NormativeTypesEnum.ROOT, + // ResourceCategoryEnum.APPLICATION_L4_CALL_CONTROL); + // resource.setVersion(INITIAL_VERSION); + // resource.setIcon(ICON_RESOURCE_NAME); + // resource.setResourceType(resourceType.toString()); + // resource.setName(getRandomComponentName(RESOURCE_NAME_PREFIX)); + // + // SetupCDTest.setCreatedComponents(Arrays.asList(resource)); + // + // return resource; + // } + + protected static String getRandomComponentName(String prefix) { + return prefix + new Random().nextInt(10000); + } + + public static ImmutablePair getFirstRIPos(ResourceReqDetails createResourceInUI, User user) { + String responseAfterDrag = RestCDUtils.getResource(createResourceInUI, user).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + String xPosPostDrag = (String) ((JSONObject) ((JSONArray) jsonResource.get("componentInstances")).get(0)) + .get("posX"); + String yPosPostDrag = (String) ((JSONObject) ((JSONArray) jsonResource.get("componentInstances")).get(0)) + .get("posY"); + return new ImmutablePair(xPosPostDrag, yPosPostDrag); + + } + + public static WebElement getErrorMessageText(WebDriver driver, String text) throws Exception { + + return GeneralUIUtils.getWebElementByClassName(text); + + } + + public static void fillGeneralInfoValuesAndIcon(ResourceReqDetails resource, User user) throws Exception { + fillResourceGeneralInformationPage(resource, user, true); + + GeneralPageElements.clickCreateButton(); + + selectRandomResourceIcon(); + } + + // coded by teddy. + public static void getVFCGeneralInfoAndValidate(ResourceReqDetails resource, User user) + throws InterruptedException { + Thread.sleep(2000); + WebDriver driver = GeneralUIUtils.getDriver(); + String version = GeneralUIUtils.getSelectList(null, "versionHeader").getFirstSelectedOption().getText(); + String name = GeneralUIUtils.getWebElementByTestID( "name").getAttribute("value"); + String description = GeneralUIUtils.getWebElementByTestID( "description").getAttribute("value"); + String category = GeneralUIUtils.getSelectList(null, "selectGeneralCategory").getFirstSelectedOption() + .getText(); + String vendorName = GeneralUIUtils.getWebElementByTestID( "vendorName").getAttribute("value"); + String vendorRelease = GeneralUIUtils.getWebElementByTestID( "vendorRelease").getAttribute("value"); + List tags = GeneralUIUtils.getWebElementsListByTestID("i-sdc-tag-text"); + String type = GeneralUIUtils.getWebElementsListByTestID("type").get(1).getText(); + int index = type.lastIndexOf(":"); + System.out.println(type.substring(0, index)); + String AttContact = GeneralUIUtils.getWebElementByTestID( "attContact").getAttribute("value"); + System.out.println(resource.getVersion()); + assertTrue(resource.getVersion().equals(version.substring(1))); + assertTrue(resource.getName().equals(name)); + assertTrue(resource.getDescription().equals(description)); + System.out.println(resource.getVendorName()); + System.out.println(resource.getVendorRelease()); + assertTrue(resource.getCategories().get(0).getSubcategories().get(0).getName().equals(category)); + assertTrue(resource.getVendorName().equals(vendorName)); + assertTrue(resource.getVendorRelease().equals(vendorRelease)); + assertTrue(resource.getCreatorUserId().equals(AttContact)); + assertEquals(type.substring(0, index), resource.getResourceType()); + + for (int i = 0; i < tags.size(); i++) { + assertEquals(resource.getTags().get(i), tags.get(i).getText()); + } + } + + public static RestResponse createResourceNG(ResourceReqDetails resource, User user) throws Exception, AWTException { + + GeneralUIUtils.hoverOnAreaByTestId("w-sdc-dashboard-card-new"); + ResourceUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_VF.getValue()); + fillResourceGeneralInformationPage(resource, user, true); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.LifeCyleChangeButtons.CREATE.getValue()); + return null; + + } + + public static void showButtons(){ + String parentElementClassAttribute = "sdc-dashboard-import-element-container"; + WebElement fileInputElementWithVisible = GeneralUIUtils.getDriver().findElement(By.className(parentElementClassAttribute)); + GeneralUIUtils.unhideElement(fileInputElementWithVisible, parentElementClassAttribute); + GeneralUIUtils.ultimateWait(); + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Input buttons now visible...")); + } + + public static void showButtonsADD(){ + try { + GeneralUIUtils.ultimateWait(); + String parentElementClassAttribute = "sdc-dashboard-create-element-container"; + WebElement fileInputElementWithVisible = GeneralUIUtils.getDriver().findElement(By.className(parentElementClassAttribute)); + GeneralUIUtils.unhideElement(fileInputElementWithVisible, parentElementClassAttribute); + GeneralUIUtils.ultimateWait(); + } catch (Exception e ){ + GeneralUIUtils.ultimateWait(); + String parentElementClassAttribute = "sdc-dashboard-create-element-container"; + WebElement fileInputElementWithVisible = GeneralUIUtils.getDriver().findElement(By.className(parentElementClassAttribute)); + GeneralUIUtils.unhideElement(fileInputElementWithVisible, parentElementClassAttribute); + GeneralUIUtils.ultimateWait(); + } + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Input buttons now visible...")); + } + + public static void clickOnElementByText(String textToClick, String customizationFoLog){ + String customizationFoLogLocal = customizationFoLog != null ? customizationFoLog : ""; + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking on %s %s", textToClick, customizationFoLogLocal)); + GeneralUIUtils.clickOnElementByText(textToClick); + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/RestCDUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/RestCDUtils.java new file mode 100644 index 0000000000..b2bad99d2a --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/RestCDUtils.java @@ -0,0 +1,344 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import static org.testng.AssertJUnit.assertTrue; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONObject; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.category.SubCategoryDefinition; +import org.openecomp.sdc.ci.tests.config.Config; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ProductReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.DriverFactory; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.utils.general.ElementFactory; +import org.openecomp.sdc.ci.tests.utils.rest.CatalogRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.CategoryRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ProductRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResourceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openecomp.sdc.ci.tests.utils.rest.ServiceRestUtils; +import org.openecomp.sdc.ci.tests.utils.rest.UserRestUtils; + +import com.aventstack.extentreports.Status; + +public class RestCDUtils { + + private static void setResourceUniqueIdAndUUID(ComponentReqDetails element, RestResponse getResourceResponse) { + element.setUniqueId(ResponseParser.getUniqueIdFromResponse(getResourceResponse)); + element.setUUID(ResponseParser.getUuidFromResponse(getResourceResponse)); + } + + public static RestResponse getResource(ResourceReqDetails resource, User user) { + final String getResourceMsg = "Trying to get resource named " + resource.getName() + " with version " + resource.getVersion(); + final String succeedGetResourceMsg = "Succeeded to get resource named " + resource.getName() + " with version " + resource.getVersion(); + final String failedGetResourceMsg = "Failed to get resource named " + resource.getName() + " with version " + resource.getVersion(); + try { + ExtentTestActions.log(Status.INFO, getResourceMsg); + System.out.println(getResourceMsg); + GeneralUIUtils.sleep(1000); + RestResponse getResourceResponse = null; + String reourceUniqueId = resource.getUniqueId(); + if (reourceUniqueId != null) { + getResourceResponse = ResourceRestUtils.getResource(reourceUniqueId); + if (getResourceResponse.getErrorCode().intValue() == 200) { + ExtentTestActions.log(Status.INFO, succeedGetResourceMsg); + System.out.println(succeedGetResourceMsg); + } + return getResourceResponse; + } + JSONObject getResourceJSONObject = null; + getResourceResponse = ResourceRestUtils.getResourceByNameAndVersion(user.getUserId(), resource.getName(), resource.getVersion()); + if (getResourceResponse.getErrorCode().intValue() == 200) { +// JSONArray jArray = new JSONArray(getResourceResponse.getResponse()); +// for (int i = 0; i < jArray.length(); i++) { +// getResourceJSONObject = jArray.getJSONObject(i); +// String resourceType = ResponseParser.getValueFromJsonResponse(getResourceJSONObject.toString(), "resourceType"); +// if (resourceType.equals(resource.getResourceType())) { +// getResourceResponse.setResponse(getResourceJSONObject.toString()); + setResourceUniqueIdAndUUID(resource, getResourceResponse); + ExtentTestActions.log(Status.INFO, succeedGetResourceMsg); + System.out.println(succeedGetResourceMsg); + return getResourceResponse; +// } +// } + } + ExtentTestActions.log(Status.INFO, failedGetResourceMsg); + return getResourceResponse; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static RestResponse getService(ServiceReqDetails service, User user) { + try { + Thread.sleep(3500); + RestResponse getServiceResponse = ServiceRestUtils.getServiceByNameAndVersion(user, service.getName(), + service.getVersion()); + if (getServiceResponse.getErrorCode().intValue() == 200) { + setResourceUniqueIdAndUUID(service, getServiceResponse); + } + return getServiceResponse; + } catch (Exception e) { + throw new RuntimeException(e); + } + + } + + public static RestResponse getProduct(ProductReqDetails product, User user) { + try { + Thread.sleep(3500); + RestResponse getProductResponse = ProductRestUtils.getProductByNameAndVersion(product.getName(), + product.getVersion(), user.getUserId()); + if (getProductResponse.getErrorCode().intValue() == 200) { + setResourceUniqueIdAndUUID(product, getProductResponse); + } + return getProductResponse; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static Map getAllElementVersionsFromResponse(RestResponse getResource) throws Exception { + Map versionsMap = new HashMap(); + try { + ObjectMapper mapper = new ObjectMapper(); + + JSONObject object = new JSONObject(getResource.getResponse()); + versionsMap = mapper.readValue(object.get("allVersions").toString(), Map.class); + + } catch (Exception e) { + e.printStackTrace(); + return versionsMap; + + } + + return versionsMap; + } + + public static void deleteElementVersions(Map elementVersions, boolean isBeforeTest, Object clazz, + User user) throws Exception { + Iterator iterator = elementVersions.keySet().iterator(); + while (iterator.hasNext()) { + String singleVersion = iterator.next(); + String uniqueId = elementVersions.get(singleVersion); + RestResponse deleteResponse = null; + if (clazz instanceof ServiceReqDetails) { + deleteResponse = ServiceRestUtils.deleteServiceById(uniqueId, user.getUserId()); + } else if (clazz instanceof ResourceReqDetails) { + deleteResponse = ResourceRestUtils.deleteResource(uniqueId, user.getUserId()); + } else if (clazz instanceof ProductReqDetails) { + deleteResponse = ProductRestUtils.deleteProduct(uniqueId, user.getUserId()); + } + + if (isBeforeTest) { + assertTrue(deleteResponse.getErrorCode().intValue() == 204 + || deleteResponse.getErrorCode().intValue() == 404); + } else { + assertTrue(deleteResponse.getErrorCode().intValue() == 204); + } + } + } + + public static void deleteAllResourceVersionsAfterTest(ComponentReqDetails componentDetails, + RestResponse getObjectResponse, User user) { + try { + deleteAllComponentVersion(false, componentDetails, getObjectResponse, user); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void deleteAllResourceVersionsBeforeTest(ComponentReqDetails componentDetails, + RestResponse getObjectResponse, User user) throws Exception { + deleteAllComponentVersion(true, componentDetails, getObjectResponse, user); + } + + public static void deleteAllComponentVersion(boolean isBeforeTest, ComponentReqDetails componentDetails, + RestResponse getObjectResponse, User user) throws Exception { + if (getObjectResponse.getErrorCode().intValue() == 404) + return; + Map componentVersionsMap = getAllElementVersionsFromResponse(getObjectResponse); + System.out.println("deleting..."); + deleteElementVersions(componentVersionsMap, isBeforeTest, componentDetails, user); + componentDetails.setUniqueId(null); + } + + + + public static String getExecutionHostAddress() { + + String computerName = null; + try { + computerName = InetAddress.getLocalHost().getHostAddress().replaceAll("\\.", "·"); + System.out.println(computerName); + if (computerName.indexOf(".") > -1) + computerName = computerName.substring(0, + computerName.indexOf(".")).toUpperCase(); + } catch (UnknownHostException e) { + System.out.println("Uknown hostAddress"); + } + return computerName != null ? computerName : "Uknown hostAddress"; + } + + public static Map> getCatalogAsMap() throws IOException { + User defaultAdminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + RestResponse catalog = CatalogRestUtils.getCatalog(defaultAdminUser.getUserId()); + Map> convertCatalogResponseToJavaObject = ResponseParser + .convertCatalogResponseToJavaObject(catalog.getResponse()); + return convertCatalogResponseToJavaObject; + } + + public static Map> getCategories() throws Exception { + + User defaultAdminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + + Map> map = new HashMap>(); + + + RestResponse allResourceCategories = CategoryRestUtils.getAllCategories(defaultAdminUser, ComponentTypeEnum.RESOURCE_PARAM_NAME); + RestResponse allServiceCategories = CategoryRestUtils.getAllCategories(defaultAdminUser, ComponentTypeEnum.SERVICE_PARAM_NAME); + + List parsedResourceCategories = ResponseParser.parseCategories(allResourceCategories); + List parsedServiceCategories = ResponseParser.parseCategories(allServiceCategories); + + map.put(ComponentTypeEnum.RESOURCE_PARAM_NAME, parsedResourceCategories); + map.put(ComponentTypeEnum.SERVICE_PARAM_NAME, parsedServiceCategories); + + return map; + } + + public static void deleteCreatedComponents(Map> map) throws IOException { + + System.out.println("going to delete all created components..."); + + User defaultAdminUser = ElementFactory.getDefaultUser(UserRoleEnum.ADMIN); + final String userId = defaultAdminUser.getUserId(); + + List resourcesArrayList = map.get("products"); + List collect = resourcesArrayList.stream().filter(s -> s.getName().startsWith("Ci")).map(e -> e.getUniqueId()) + .collect(Collectors.toList()); + for (String uId : collect) { + ProductRestUtils.deleteProduct(uId, userId); + } + + resourcesArrayList = map.get("services"); + collect = resourcesArrayList.stream().filter(s -> s.getName().startsWith("ci")).map(e -> e.getUniqueId()) + .collect(Collectors.toList()); + for (String uId : collect) { + ServiceRestUtils.markServiceToDelete(uId, userId); + } + ServiceRestUtils.deleteMarkedServices(userId); + + resourcesArrayList = map.get("resources"); + collect = resourcesArrayList.stream().filter(s -> s.getName().startsWith("ci")) + .map(e -> e.getUniqueId()).collect(Collectors.toList()); + for (String uId : collect) { + ResourceRestUtils.markResourceToDelete(uId, userId); + } + ResourceRestUtils.deleteMarkedResources(userId); + + + + + + } + + public static void deleteCategoriesByList(List listCategories, String componentType, User user) throws Exception { + + for (CategoryDefinition categoryDefinition : listCategories) { + if (categoryDefinition.getName().toLowerCase().startsWith("ci")) { + List subcategories = categoryDefinition.getSubcategories(); + if (subcategories != null) { + for (SubCategoryDefinition subCategoryDefinition : subcategories) { + + CategoryRestUtils.deleteSubCategory(subCategoryDefinition.getUniqueId(), + categoryDefinition.getUniqueId(), user.getUserId(), + componentType); + } + } + + CategoryRestUtils.deleteCategory(categoryDefinition.getUniqueId(), user.getUserId(), + componentType); + + } + } + } + + public static String getUserRole(User reqUser, User user){ + try{ + RestResponse getUserRoleResp = UserRestUtils.getUserRole(reqUser, user); + JSONObject jObject = new JSONObject(getUserRoleResp.getResponse()); + return jObject.getString("role"); + } + catch(Exception e){ + return null; + } + } + + public static RestResponse getUser(User reqUser, User user){ + try{ + return UserRestUtils.getUser(reqUser, user); + } + catch(Exception e){ + return null; + } + } + + /*************************************/ + + public static void deleteOnDemand() throws IOException { + Config config = DriverFactory.getConfig(); + if(!config.getSystemUnderDebug()){ + deleteCreatedComponents(getCatalogAsMap()); + }else{ + System.out.println("Accordindig to configuration components will not be deleted, in case to unable option to delete, please change systemUnderDebug parameter value to false ..."); + } + } + + public static void deleteCategories(User user) throws Exception { + Map> categoriesMap = getCategories(); + List listCategories = categoriesMap.get(ComponentTypeEnum.RESOURCE_PARAM_NAME); + deleteCategoriesByList(listCategories, ComponentTypeEnum.RESOURCE_PARAM_NAME, user); + listCategories = categoriesMap.get(ComponentTypeEnum.SERVICE_PARAM_NAME); + deleteCategoriesByList(listCategories, ComponentTypeEnum.SERVICE_PARAM_NAME, user); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ServiceUIUtils.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ServiceUIUtils.java new file mode 100644 index 0000000000..8b07e621d9 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/utilities/ServiceUIUtils.java @@ -0,0 +1,286 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.utilities; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +import java.awt.AWTException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.rules.TestName; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.StepsEnum; +import org.openecomp.sdc.ci.tests.datatypes.ServiceCategoriesNameEnum; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.ServiceCategoriesEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.GeneralPageElements; +import org.openecomp.sdc.ci.tests.pages.ServiceGeneralPage; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.Select; +import org.openqa.selenium.support.ui.WebDriverWait; + +import com.aventstack.extentreports.Status; + +public class ServiceUIUtils { + + protected static WebDriver driver; + + public ServiceUIUtils(TestName name, String className) { + super(); + } + + public static String defineServiceName(String Name) { + WebElement serviceName = GeneralUIUtils.getWebElementByTestID("name"); + serviceName.clear(); + serviceName.sendKeys(Name); + return Name; + } + + public void moveResourceInstanceToCanvasUI() throws Exception { + List moveResource = driver.findElements(By.className("sprite-resource-icons")); + WebElement moveResourceToCanvasResourceOne = moveResource.get(0); + // WebElement moveResource = + // driver.findElement(By.className("sprite-resource-icons")); + Actions action = new Actions(driver); + action.moveToElement(moveResourceToCanvasResourceOne); + action.clickAndHold(moveResourceToCanvasResourceOne); + action.moveByOffset(635, 375); + action.release(); + action.perform(); + WebElement moveResourceToCanvasResourceTwo = moveResource.get(1); + action.moveToElement(moveResourceToCanvasResourceTwo); + action.clickAndHold(moveResourceToCanvasResourceTwo); + action.moveByOffset(535, 375); + action.release(); + action.perform(); + WebElement moveResourceToCanvasResourceTree = moveResource.get(2); + action.moveToElement(moveResourceToCanvasResourceTree); + action.clickAndHold(moveResourceToCanvasResourceTree); + action.moveByOffset(435, 375); + action.release(); + action.perform(); + Thread.sleep(2000); + } + + public static String catalogFilterServiceCategoriesChecBox(ServiceCategoriesNameEnum enumName) throws Exception { + String Type = null; + GeneralUIUtils.getWebElementByTestID(enumName.getValue()).click(); + return Type; + } + + public static List catalogServiceTypeChecBox(ServiceCategoriesNameEnum enumtype) throws Exception { + List categories = null; + switch (enumtype) { + case NETWORK_L13: + GeneralUIUtils.getWebElementByTestID(enumtype.getValue()).click(); + categories = Arrays.asList("network_l_1-3"); + break; + case NETWORKL4: + GeneralUIUtils.getWebElementByTestID(enumtype.getValue()).click(); + categories = Arrays.asList("network_l_4 "); + break; + case MOBILITY: + GeneralUIUtils.getWebElementByTestID(enumtype.getValue()).click(); + categories = Arrays.asList("mobility"); + break; + case VOIPCALL_CONTROL: + GeneralUIUtils.getWebElementByTestID(enumtype.getValue()).click(); + categories = Arrays.asList("call_controll "); + break; + } + return categories; + } + + public static WebElement waitToNextButtonEnabled() { + return GeneralUIUtils.getWebElementByTestID("Next"); + } + + public static WebElement waitToFinishButtonEnabled() { + return GeneralUIUtils.getWebElementByTestID("Finish"); + } + + public static WebElement deleteServiceInUI() { + + return GeneralUIUtils.getWebElementByTestID("deleteVersion"); + } + + // get the service view data for validate. + // created by tedy. + public static void getServiceGeneralInfo(ServiceReqDetails service, User user) throws InterruptedException { + Thread.sleep(2000); + String version = GeneralUIUtils.getSelectList(null, "versionHeader").getFirstSelectedOption().getText() + .substring(1); + String name = GeneralUIUtils.getWebElementByTestID("name").getAttribute("value"); + String description = GeneralUIUtils.getWebElementByTestID("description").getAttribute("value"); + String category = GeneralUIUtils.getSelectList(null, "selectGeneralCategory").getFirstSelectedOption() + .getText(); + List tags = GeneralUIUtils.getWebElementsListByTestID("i-sdc-tag-text"); + String type = GeneralUIUtils.getWebElementsListByTestID("type").get(1).getText(); + int index = type.lastIndexOf(":"); + System.out.println(type.substring(0, index)); + String attContact = GeneralUIUtils.getWebElementByTestID("attContact").getAttribute("value"); + String pmatt = GeneralUIUtils.getWebElementByTestID("pmatt").getAttribute("value"); + System.out.println(service.getVersion()); + assertTrue(service.getVersion().equals(version)); + assertTrue(service.getName().equals(name)); + assertTrue(service.getDescription().equals(description)); + assertTrue(service.getCategories().get(0).getName().equals(category)); + System.out.println(service.getContactId()); + assertTrue(service.getContactId().equals(attContact)); + assertTrue(service.getProjectCode().equals(pmatt)); + for (int i = 0; i < tags.size(); i++) { + assertEquals(service.getTags().get(i), tags.get(i).getText()); + } + + } + +// public static void defineTagsList(ServiceReqDetails service, String[] serviceTags) { +// List taglist = new ArrayList(); +// WebElement serviceTagsTextbox = GeneralUIUtils.getWebElementByTestID("i-sdc-tag-input"); +// for (String tag : serviceTags) { +// serviceTagsTextbox.clear(); +// serviceTagsTextbox.sendKeys(tag); +// GeneralUIUtils.sleep(1000); +// serviceTagsTextbox.sendKeys(Keys.ENTER); +// taglist.add(tag); +// } +// taglist.add(0, service.getName()); +// service.setTags(taglist); +// } + + public static void defineTagsList2(List serviceTags){ + WebElement serviceTagsTextbox = GeneralUIUtils.getWebElementByTestID("i-sdc-tag-input"); + for (String tag : serviceTags) { + serviceTagsTextbox.clear(); + serviceTagsTextbox.sendKeys(tag); + GeneralUIUtils.waitForAngular(); + serviceTagsTextbox.sendKeys(Keys.ENTER); + } + } + + public static Select defineServiceCategory(String category) { + + return GeneralUIUtils.getSelectList(category, "selectGeneralCategory"); + } + + public static void defineServicePmatt(String pmatt) { + WebElement attPmattTextbox = GeneralUIUtils.getWebElementByTestID("pmatt"); + attPmattTextbox.clear(); + attPmattTextbox.sendKeys(pmatt); + } + + public static void selectRandomResourceIcon() throws Exception { + GeneralUIUtils.moveToStep(StepsEnum.ICON); + WebDriverWait wait = new WebDriverWait(driver, 6); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(@data-tests-id, 'iconBox')]"))); + List iconElement = driver.findElements(By.xpath("//*[contains(@data-tests-id, 'iconBox')]")); + iconElement.get(0).click(); + } + + public static String defineDescription(String description) { + WebElement descriptionTextbox = GeneralUIUtils.getWebElementByTestID("description"); + descriptionTextbox.clear(); + descriptionTextbox.sendKeys(description); + return description; + } + + public static void defineContactId(String userId) { + WebElement attContact = GeneralUIUtils.getWebElementByTestID("attContact"); + attContact.clear(); + attContact.sendKeys(userId); + } + + public static WebElement clickAddArtifact() { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking Add Artifact button")); + return GeneralUIUtils.getWebElementByTestID("addArtifactButton"); + } + + public static WebElement getArtifactName() { + return GeneralUIUtils.getWebElementByTestID("artifactName"); + } + + public static WebElement getArtifactDetails() { + return GeneralUIUtils.getWebElementByTestID("artifactDisplayName"); + } + + public static void fillServiceGeneralPage(ServiceReqDetails service, User user) throws Exception { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Fill in metadata values in general page")); + ServiceGeneralPage.defineName(service.getName()); + ServiceGeneralPage.defineDescription(service.getDescription()); + ServiceGeneralPage.defineCategory(service.getCategories().get(0).getName()); + ServiceGeneralPage.defineProjectCode(service.getProjectCode()); + defineTagsList2(service.getTags()); + ServiceGeneralPage.defineContactId(service.getContactId()); + GeneralUIUtils.clickSomewhereOnPage(); + } + + public static void createService(ServiceReqDetails service, User user) throws Exception, AWTException { + clickAddService(); + fillServiceGeneralPage(service, user); + GeneralPageElements.clickCreateButton(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("The service %s was created", service.getName())); + } + + public static void setServiceCategory(ServiceReqDetails service, ServiceCategoriesEnum category){ + CategoryDefinition categoryDefinition = new CategoryDefinition(); + categoryDefinition.setName(category.getValue()); + List categories = new ArrayList<>(); + categories.add(categoryDefinition); + service.setCategories(categories); + } + + public static void createServiceWithDefaultTagAndUserId(ServiceReqDetails service, User user) { + clickAddService(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Defining General Page fields")); + ServiceGeneralPage.defineName(service.getName()); + ServiceGeneralPage.defineDescription(service.getDescription()); + ServiceGeneralPage.defineCategory(service.getCategories().get(0).getName()); + ServiceGeneralPage.defineProjectCode(service.getProjectCode()); + GeneralUIUtils.ultimateWait(); + GeneralPageElements.clickCreateButton(); + } + + public static void clickAddService(){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Clicking the Add Service button")); + try { + GeneralUIUtils.hoverOnAreaByTestId(DataTestIdEnum.Dashboard.ADD_AREA.getValue()); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_SERVICE.getValue()).click(); + GeneralUIUtils.ultimateWait(); + } catch (Exception e){ + SetupCDTest.getExtendTest().log(Status.WARNING, String.format("Exception on catched on Add Service button, retrying ...")); + GeneralUIUtils.hoverOnAreaByClassName("w-sdc-dashboard-card-new"); + GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.Dashboard.BUTTON_ADD_SERVICE.getValue()).click(); + GeneralUIUtils.ultimateWait(); + } + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/CatalogVerificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/CatalogVerificator.java new file mode 100644 index 0000000000..25f71eeb0a --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/CatalogVerificator.java @@ -0,0 +1,168 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.verificator; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.ci.tests.datatypes.LifeCycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.TypesEnum; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.testng.Assert; +import org.testng.TestNGException; + +import com.aventstack.extentreports.Status; + +public class CatalogVerificator { + + public static int getResourceNumber(ResourceTypeEnum resourceType, Map> catalogAsMap) throws Exception { + List resourcesArrayList = catalogAsMap.get("resources"); + return resourcesArrayList.stream(). + filter(s -> ((Resource)s).getResourceType().equals(resourceType)). + collect(Collectors.toList()).size(); + } + + public static int getTypeNumber(TypesEnum enumtype) throws Exception{ + Map> catalogAsMap = RestCDUtils.getCatalogAsMap(); + switch (enumtype) { + case RESOURCE: + return getResourceNumber(catalogAsMap); + case SERVICE: + return getServiceNumber(catalogAsMap); + case PRODUCT: + return getProductsNumber(catalogAsMap); + default: + return getResourceNumber(ResourceTypeEnum.valueOf(enumtype.name()), catalogAsMap); + } + } + + public static int getResourceNumber(Map> catalogAsMap) throws Exception { + return catalogAsMap.get("resources").size(); + } + + public static int getServiceNumber(Map> catalogAsMap) throws Exception { + return catalogAsMap.get("services").size(); + } + + public static int getProductsNumber(Map> catalogAsMap) throws Exception { + return catalogAsMap.get("products").size(); + } + + public static void validateType(TypesEnum enumtype) throws Exception{ + int numberOfElementsFromBE = getTypeNumber(enumtype); + int numberOfElementsFromUI = getNumberOfElementsFromCatalogHeader(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating number of %s elements, should be %s ...", enumtype.name(), numberOfElementsFromBE)); + Assert.assertEquals(numberOfElementsFromBE, numberOfElementsFromUI, String.format("Expected : %s, Actual: %s", numberOfElementsFromBE, numberOfElementsFromUI)); + } + + public static int getStatusNumber(List status) throws Exception { + Map> catalogAsMap = RestCDUtils.getCatalogAsMap(); + return catalogAsMap.entrySet().stream(). + map(s -> s.getValue()). + flatMap(List::stream). + filter(s -> status.contains(mapBeLifecycleToUIStatus(s))). + collect(Collectors.toList()).size(); + } + + public static void validateStatus(List status, String checkboxName) throws Exception{ + int numberOfElementsFromBE = getStatusNumber(status); + int numberOfElementsFromUI = getNumberOfElementsFromCatalogHeader(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating number of %s elements , should be %s ...", checkboxName, numberOfElementsFromBE)); + Assert.assertEquals(numberOfElementsFromBE, numberOfElementsFromUI, String.format("Expected : %s, Actual: %s", numberOfElementsFromBE, numberOfElementsFromUI)); + } + + public static int getCategoryNumber(String categoryName) throws Exception { + Map> catalogAsMap = RestCDUtils.getCatalogAsMap(); + List serviceAndResourceList = new ArrayList(); + serviceAndResourceList.addAll(catalogAsMap.get("resources")); + serviceAndResourceList.addAll(catalogAsMap.get("services")); + return serviceAndResourceList.stream(). + filter(s -> s.getCategories().get(0).getName().equals(categoryName)). + collect(Collectors.toList()).size(); + } + + public static void validateCategory(String categoryName) throws Exception{ + int numberOfElementsFromBE = getCategoryNumber(categoryName); + int numberOfElementsFromUI = getNumberOfElementsFromCatalogHeader(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating number of %s category elements , should be %s ...", categoryName, numberOfElementsFromBE)); + Assert.assertEquals(numberOfElementsFromBE, numberOfElementsFromUI, String.format("Expected : %s, Actual: %s", numberOfElementsFromBE, numberOfElementsFromUI)); + } + + public static int getSubCategoryNumber(String categoryName , String subCategoryName) throws Exception { + Map> catalogAsMap = RestCDUtils.getCatalogAsMap(); + List resourcesArrayList = catalogAsMap.get("resources"); + return resourcesArrayList.stream(). + filter(s -> s.getCategories().get(0).getName().equals(categoryName) && + s.getCategories().get(0).getSubcategories().get(0).getName().equals(subCategoryName)). + collect(Collectors.toList()).size(); + } + + public static void validateSubCategory(String categoryName, String subCategoryName) throws Exception{ + int numberOfElementsFromBE = getSubCategoryNumber(categoryName, subCategoryName); + int numberOfElementsFromUI = getNumberOfElementsFromCatalogHeader(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating number of %s/%s subcategory elements , should be %s ...", categoryName, subCategoryName, numberOfElementsFromBE)); + Assert.assertEquals(numberOfElementsFromBE, numberOfElementsFromUI, String.format("Expected : %s, Actual: %s", numberOfElementsFromBE, numberOfElementsFromUI)); + } + + public static int getNumberOfElementsFromCatalogHeader(){ + String elementsAsString = GeneralUIUtils.getWebElementByClassName("w-sdc-dashboard-catalog-header").getText(); + String numberOfElementsAsString = elementsAsString.split(" ")[0]; + if (numberOfElementsAsString.equals("No")){ + return 0; + } else { + return Integer.parseInt(numberOfElementsAsString); + } + } + + private static LifeCycleStateEnum mapBeLifecycleToUIStatus(Component component){ + boolean isServiceAndDistributed = component.getComponentType().equals(ComponentTypeEnum.SERVICE) && + ((Service) component).getDistributionStatus().equals(DistributionStatusEnum.DISTRIBUTED); + switch (component.getLifecycleState()) { + case CERTIFIED: + if (isServiceAndDistributed){ + return LifeCycleStateEnum.DISTRIBUTED; + } else { + return LifeCycleStateEnum.CERTIFIED; + } + case READY_FOR_CERTIFICATION: + return LifeCycleStateEnum.READY_FOR_TESTING; + case CERTIFICATION_IN_PROGRESS: + return LifeCycleStateEnum.IN_TESTING; + case NOT_CERTIFIED_CHECKIN: + return LifeCycleStateEnum.CHECKIN; //to IN DESIGN + case NOT_CERTIFIED_CHECKOUT: + return LifeCycleStateEnum.CHECKOUT; //to IN DESIGN + default: + throw new TestNGException("Missing enum value in enum converter"); + } + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/CustomizationUUIDVerificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/CustomizationUUIDVerificator.java new file mode 100644 index 0000000000..9cb305deae --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/CustomizationUUIDVerificator.java @@ -0,0 +1,27 @@ +package org.openecomp.sdc.ci.tests.verificator; + +import static org.testng.AssertJUnit.assertTrue; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class CustomizationUUIDVerificator { + + public static void validateCustomizationUUIDuniqueness(List customizationUUIDs) { + boolean hasNoDuplicates = CustomizationUUIDVerificator.containsUnique(customizationUUIDs); + assertTrue("There are duplicate customizationUUIDs in list",hasNoDuplicates==true); + } + + public static boolean containsUnique(List list){ + Set set = new HashSet<>(); + + for (T t: list){ + if (!set.add(t)) + return false; + } + + return true; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/DeploymentViewVerificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/DeploymentViewVerificator.java new file mode 100644 index 0000000000..0d06d8ef96 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/DeploymentViewVerificator.java @@ -0,0 +1,328 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.verificator; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.apache.commons.io.FileUtils; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.execute.devCI.ArtifactFromCsar; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.DeploymentPage; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaDefinition; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaGroupsTopologyTemplateDefinition; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utils.ToscaParserUtils; +import org.openqa.selenium.WebElement; +import org.testng.SkipException; +import org.testng.TestException; +import org.testng.TestNGException; + +import com.aventstack.extentreports.Status; + +public class DeploymentViewVerificator { + + private static String[] currentProperties = {"isBase", + "vf_module_label", + "vf_module_description", + "min_vf_module_instances", + "max_vf_module_instances", + "initial_count", + "vf_module_type", + "volume_group", + "vfc_list", + "availability_zone_count"}; + + private static Map>> deploymentViewData = new HashMap>>(){ + { + HashMap> segw_heat_c3_base , segw_heat_c3_VMs1 ; + + segw_heat_c3_base = new HashMap>(); + segw_heat_c3_base.put("members", Arrays.asList("segw_internet_security_group", "segw_security_group", "int_layer2vlan_net")); + segw_heat_c3_base.put("artifacts", Arrays.asList("segw_heat_c3_base.yml", "segw_heat_c3_base.env")); + segw_heat_c3_base.put("properties", Arrays.asList(currentProperties)); + put("segw_heat_c3_base", segw_heat_c3_base); + segw_heat_c3_VMs1 = new HashMap>(); + segw_heat_c3_VMs1.put("members", Arrays.asList("segw_oam_protected_0_port", + "fw_oam_int_layer2vlan_1_port", + "segw_0", "segw_internet_1_port", + "segw_layer2vlan_2_port", + "fw_gn_0", "fw_gn_hsl_direct_3_port", + "fw_oam_oam_mgmt_0_port", + "fw_oam_hsl_direct_3_port", + "fw_gn_oam_mgmt_0_port", + "fw_oam_oam_direct_2_port", + "fw_gn_gn_direct_2_port", + "fw_oam_0", + "fw_gn_int_layer2vlan_1_port")); + segw_heat_c3_VMs1.put("artifacts", Arrays.asList("segw_heat_c3_VMs1.yml", "segw_heat_c3_VMs1.env")); + segw_heat_c3_VMs1.put("properties", Arrays.asList(currentProperties)); + put("segw_heat_c3_VMs1", segw_heat_c3_VMs1); + } + }; + + private static Map>> deploymentViewDataMixedArtefects = new HashMap>>(){ + { + HashMap> module_1_ldsa, module_2_ldsa, base_ldsa; + + module_1_ldsa = new HashMap>(); + module_1_ldsa.put("members", new ArrayList(Arrays.asList("ltm_oam_protected_0_port", "ltm_dmz_direct_0_port", "ltm_server_0"))); + module_1_ldsa.put("artifacts", new ArrayList(Arrays.asList("module_1_ldsa.yaml", "module_1_ldsa.env", "base_ldsa.33.yaml", "module_1_ldsa.11.yaml"))); + module_1_ldsa.put("properties", new ArrayList(Arrays.asList(currentProperties))); + put("module_1_ldsa", module_1_ldsa); + module_2_ldsa = new HashMap>(); + module_2_ldsa.put("members", new ArrayList(Arrays.asList("ltm_server_0"))); + module_2_ldsa.put("artifacts", new ArrayList(Arrays.asList("module_2_ldsa.yaml", "module_2_ldsa.env", "base_ldsa.3.yaml", "module_2_ldsa.22.yaml"))); + module_2_ldsa.put("properties", new ArrayList(Arrays.asList(currentProperties))); + put("module_2_ldsa", module_2_ldsa); + base_ldsa = new HashMap>(); + base_ldsa.put("members", new ArrayList(Arrays.asList("ldsa_sec_grp_1"))); + base_ldsa.put("artifacts", new ArrayList(Arrays.asList("base_ldsa.yaml", "module_2_ldsa.2.yaml", "module_1_ldsa.1.yaml"))); + base_ldsa.put("properties", new ArrayList(Arrays.asList(currentProperties))); + put("base_ldsa", base_ldsa); + } + }; + + private Map>> deploymentViewDataFromFile; + + public DeploymentViewVerificator(String pathToCSAR) throws Exception { + deploymentViewDataFromFile = getDeploymentViewDataFromCSAR(pathToCSAR); + } + + public DeploymentViewVerificator() throws Exception { + deploymentViewDataFromFile = deploymentViewDataMixedArtefects; + } + + + public void verifyDeploymentPageSubElements(String moduleName) throws Exception{ + HashMap> moduleProperties = getDeploymentViewData().get(moduleName); + + // add env placeholder to deployment view data + if (!moduleProperties.get("artifacts").contains(moduleName + ".env")){ + moduleProperties.get("artifacts").add(moduleName + ".env"); + } + + List members, artifacts, properties; + members = DeploymentPage.getGroupMembersList(moduleName); + artifacts = DeploymentPage.getArtifactNames(); + properties = DeploymentPage.getPropertyNames(); + + File imageFilePath = GeneralUIUtils.takeScreenshot(moduleName + UUID.randomUUID(), SetupCDTest.getScreenshotFolder(), null); + final String absolutePath = new File(SetupCDTest.getReportFolder()).toURI().relativize(imageFilePath.toURI()).getPath(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating group %s, should be %s members, %s artefacts " + SetupCDTest.getExtendTest().addScreenCaptureFromPath(absolutePath), + moduleName, moduleProperties.get("members").size(), moduleProperties.get("artifacts").size())); + + assertTrue(moduleProperties.get("artifacts").size() == artifacts.size(), "Artifacts amount not as expected, expected " + moduleProperties.get("artifacts").size()); + assertTrue(moduleProperties.get("artifacts").containsAll(artifacts.stream(). + map(e -> e.getAttribute("textContent")). + collect(Collectors.toList()))); + assertTrue(moduleProperties.get("members").size() == members.size(), "Members amount not as expected, expected " + moduleProperties.get("members").size()); + assertTrue(moduleProperties.get("members").containsAll(members.stream(). + map(e -> e.getAttribute("textContent")). + collect(Collectors.toList()))); + assertTrue(moduleProperties.get("properties").size() == properties.size(), "Properties amount not as expected, expected " + moduleProperties.get("properties").size()); + assertTrue(moduleProperties.get("properties").containsAll(properties.stream(). + map(e -> e.getAttribute("textContent")). + collect(Collectors.toList()))); + DeploymentPage.clickOnProperties(); + DeploymentPage.clickOnArtifacts(); + } + + public void verifyDeploymentPageModules(List modules){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating VF groups , should be %s groups ", getDeploymentViewData().size())); + assertFalse(modules.isEmpty(), "No modules found"); + assertTrue(modules.size() == getDeploymentViewData().size(), "Modules amount not as expected, expected " + getDeploymentViewData().size()); + for (WebElement module: modules){ + assertTrue(getDeploymentViewData().containsKey(module.getText().split("\\.\\.")[1])); + } + } + + public static void verifyComponentNameChanged(String oldName, String newName){ + try{ + GeneralUIUtils.clickOnElementByText(oldName, 10); + assertTrue(false, "Element name don't changed"); + } catch(Exception e){ + GeneralUIUtils.clickOnElementByText(newName); + } + } + + public Map>> getDeploymentViewData() { +// return deploymentViewData; + return getDeploymentViewDataFromFile(); + } + + public static Map>> buildDeploymentViewDataFromCSAR(String pathToCSAR, File mainServiceTemplate) throws Exception{ + ToscaDefinition toscaDefinition = ToscaParserUtils.parseToscaYamlToJavaObject(mainServiceTemplate); + Map>> deploymentViewDataFromFile = new HashMap>>(); + Map groups = toscaDefinition.getTopology_template().getGroups(); + List keyList = groups.keySet().stream().collect(Collectors.toList()); + HashMap> groupsToArtefacts = getDeploymentArtefactsMapedToGroupsFromCSAR(pathToCSAR); + for(String groupKey: keyList){ + HashMap> tempGroupMap = new HashMap>(); + tempGroupMap.put("artifacts", groupsToArtefacts.get(groupKey)); + if (groups.get(groupKey).getMembers() == null){ + tempGroupMap.put("members", Arrays.asList()); + } else { + tempGroupMap.put("members", groups.get(groupKey).getMembers()); + } + tempGroupMap.put("properties", Arrays.asList(currentProperties)); + deploymentViewDataFromFile.put(groupKey, tempGroupMap); + } + return deploymentViewDataFromFile; + } + + public static HashMap> getDeploymentArtefactsMapedToGroupsFromCSAR(String pathToFile) throws Exception { + Map combinedMap = ArtifactFromCsar.combineHeatArtifacstWithFolderArtifacsToMap(pathToFile); + LinkedList deploymentArtifacts = ((LinkedList) combinedMap.get("Deployment")); + HashMap> tempGroupMap = new HashMap>(); + for(HeatMetaFirstLevelDefinition deploymentArtifact: deploymentArtifacts) { + String groupName = deploymentArtifact.getFileName().trim().substring(0, deploymentArtifact.getFileName().indexOf(".")); + if(deploymentArtifact.getType().equals("HEAT")) { + tempGroupMap.put(groupName, new ArrayList(Arrays.asList(deploymentArtifact.getFileName().trim()))); + } else { + // update current key + tempGroupMap.get(groupName).add(deploymentArtifact.getFileName().trim()); + tempGroupMap.put(groupName, tempGroupMap.get(groupName)); + } + } + return tempGroupMap; + } + + public static Map>> getDeploymentViewDataFromCSAR(String pathToCsar) throws Exception { + String outputFolder = unzipCsarFile(pathToCsar); + + File pathToMainServiceTemplate = new File(outputFolder + File.separator + "Definitions" + File.separator + "MainServiceTemplate.yaml"); + Map>> deploymentViewData = buildDeploymentViewDataFromCSAR(pathToCsar, pathToMainServiceTemplate); + cleanFolders(outputFolder); + + return deploymentViewData; + } + + public static void cleanFolders(String outputFolder) throws IOException { + System.gc(); + FileUtils.cleanDirectory(new File(outputFolder)); + FileUtils.deleteDirectory(new File(outputFolder)); + } + + public static String unzipCsarFile(String pathToCsar) { + File csarFile = new File(pathToCsar); + + + File dir = new File(csarFile.getParent() + File.separator + "output"+UUID.randomUUID() + File.separator + UUID.randomUUID()); + if(!dir.exists()) { + dir.mkdirs(); + } + + String outputFolder = dir.getPath(); + ArtifactFromCsar.unZip(pathToCsar, outputFolder); + return outputFolder; + } + + public static void validateEditPopoverFields(String expectedVNFName, String expectedHeatName, String expectedModuleName){ + String VNFname = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DeploymentScreen.RESOURCE_NAME_ON_POPOVER.getValue()).getText(); + String heatName = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DeploymentScreen.NAME_INPUT.getValue()).getAttribute("value"); + String moduleName = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.DeploymentScreen.MODULE_NAME_ON_POPOVER.getValue()).getText(); + assertTrue(expectedVNFName.equals(VNFname), String.format("VNF name Expected: %s, Actual: %s ", expectedVNFName, VNFname)); + assertTrue(expectedHeatName.equals(heatName), String.format("HEAT name Expected: %s, Actual: %s ", expectedHeatName, heatName )); + assertTrue(expectedModuleName.equals(moduleName), String.format("Module name Expected: %s, Actual: %s ", expectedModuleName, moduleName)); + } + + public static void validateEditPopoverButtons(String newName, String invalidModuleName, String validModueName ){ + DeploymentPage.updateAndCancel(newName, DataTestIdEnum.DeploymentScreen.X_BUTTON); + verifyComponentNameChanged(invalidModuleName, validModueName); + DeploymentPage.clickOnEditIcon(); + DeploymentPage.updateAndCancel(newName, DataTestIdEnum.DeploymentScreen.CANCEL); + verifyComponentNameChanged(invalidModuleName, validModueName); + } + + public static void validateEditPopover() throws Exception{ + String moduleRowText = GeneralUIUtils.getElementsByCSS(DataTestIdEnum.DeploymentScreen.MODULES.getValue()).get(0).getText(); + DeploymentPage.clickOnModuleName(moduleRowText); + DeploymentPage.clickOnEditIcon(); + String[] splitedModuleName = moduleRowText.split("\\.\\."); + + validateEditPopoverFields(splitedModuleName[0], splitedModuleName[1], splitedModuleName[2]); + + String newName = "kuku"; + String newModuleName = DeploymentPage.reconstructModuleName(splitedModuleName, newName); + validateEditPopoverButtons(newName, newModuleName, moduleRowText); + } + + private Map>> getDeploymentViewDataFromFile() { + return deploymentViewDataFromFile; + } + + public static void validateModuleNameUpadate() throws Exception{ + List moduleRowsFromTable = GeneralUIUtils.getElementsByCSS(DataTestIdEnum.DeploymentScreen.MODULES.getValue()); + int i = 0; + for(WebElement moduleRow :moduleRowsFromTable){ + String moduleRowText = moduleRow.getText(); + String updatedName = "updatedName" + i; + DeploymentPage.updateModuleName(moduleRowText, updatedName); + String updatedModuleName = DeploymentPage.reconstructModuleName(moduleRowText.split("\\.\\."), updatedName); + verifyComponentNameChanged(moduleRowText, updatedModuleName); + // Close module + GeneralUIUtils.clickOnElementByText(updatedModuleName); + i++; + } + } + + public static void regularDepoymentScreenVerificator(Map> metaDataFromUI, DeploymentViewVerificator verificator) throws Exception, InterruptedException { + ResourceGeneralPage.getLeftMenu().moveToDeploymentViewScreen(); + List moduleRowsFromTable = GeneralUIUtils.getElementsByCSS(DataTestIdEnum.DeploymentScreen.MODULES.getValue()); + verificator.verifyDeploymentPageModules(moduleRowsFromTable); + for(WebElement moduleRow :moduleRowsFromTable){ + String moduleRowText = moduleRow.getText(); + String middleName = moduleRowText.split("\\.\\.")[1]; + verificator.verifyDeploymentPageSubElements(middleName); + if (metaDataFromUI != null){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating %s group version, should be %s ", moduleRowText, metaDataFromUI.get(moduleRowText.split("\\.\\.")[1]))); + String groupVersion = DeploymentPage.getGroupVersion().split(":")[1].trim(); + String increasedVersion = String.valueOf(Integer.parseInt(metaDataFromUI.get(middleName).get("version")) + 1); + assertTrue(groupVersion.equals(increasedVersion)); + if ( metaDataFromUI.get(middleName).get("moduleID") != "primary"){ + String moduleID = DeploymentPage.getModuleID(); + assertFalse(moduleID.equals(metaDataFromUI.get(middleName).get("moduleID"))); + } + } + // Close module + GeneralUIUtils.clickOnElementByText(moduleRowText); + } + } + + + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/ErrorMessageUIVerificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/ErrorMessageUIVerificator.java new file mode 100644 index 0000000000..f53bfa4e07 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/ErrorMessageUIVerificator.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.verificator; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.ci.tests.datatypes.ErrorMessageProperties; +import org.openecomp.sdc.ci.tests.datatypes.enums.ErrorInfo; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.testng.Assert; + +import com.aventstack.extentreports.Status; + +public class ErrorMessageUIVerificator { + + private static ErrorMessageProperties getErrorByType(ActionStatus errorType){ + try{ + ErrorInfo errorInfo = ErrorValidationUtils.parseErrorConfigYaml(errorType.name()); + String messageId = errorInfo.getMessageId(); + String code = errorInfo.getCode().toString(); + + return new ErrorMessageProperties(messageId, code); + } + catch(Exception e){ + return null; + } + } + + public static void validateErrorMessage(ActionStatus errorMessage) { + String errorMessageBox = null; + try{ + errorMessageBox = GeneralUIUtils.getWebElementByClassName("w-sdc-modal-caption").getText(); + } + catch(Exception e){ + ExtentTestActions.log(Status.INFO, "Did not find an error message popup."); + Assert.fail("Did not find an error message popup."); + } + + ExtentTestActions.log(Status.INFO, "An error message raised, validating its content."); + ErrorMessageProperties expectedResponseError = getErrorByType(errorMessage); + Assert.assertTrue(errorMessageBox.contains(expectedResponseError.getCode()), "Error message code is not " + expectedResponseError.getCode()); + Assert.assertTrue(errorMessageBox.contains(expectedResponseError.getMessageId()), "Error message ID is not " + expectedResponseError.getMessageId()); + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/ServiceVerificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/ServiceVerificator.java new file mode 100644 index 0000000000..2c1f59fe9f --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/ServiceVerificator.java @@ -0,0 +1,335 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.verificator; + +import static org.testng.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.function.Predicate; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.model.GroupInstance; +import org.openecomp.sdc.be.model.GroupInstanceProperty; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.ComponentReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum.PropertiesPopupEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.ServiceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.CompositionPage; +import org.openecomp.sdc.ci.tests.pages.DeploymentPage; +import org.openecomp.sdc.ci.tests.pages.PropertyPopup; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.pages.ServiceGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.openecomp.sdc.ci.tests.utils.general.AtomicOperationUtils; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Select; + +import com.aventstack.extentreports.Status; + +public class ServiceVerificator { + + private ServiceVerificator() { + } + + public static void verifyNumOfComponentInstances(ComponentReqDetails component, String version, int numOfVFC, + User user) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Verifing the number of components on the canvas; should be %s", numOfVFC)); + String responseAfterDrag = null; + component.setVersion(version); + if (component instanceof ServiceReqDetails) { + responseAfterDrag = RestCDUtils.getService((ServiceReqDetails) component, user).getResponse(); + } else if (component instanceof ResourceReqDetails) { + responseAfterDrag = RestCDUtils.getResource((ResourceReqDetails) component, user).getResponse(); + } + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + int size = ((JSONArray) jsonResource.get("componentInstances")).size(); + assertTrue(size == numOfVFC); + ExtentTestActions.log(Status.INFO, "The number of components on the canvas was verified."); + } + + public static void verifyServiceUpdatedInUI(ServiceReqDetails service) { + assertTrue(service.getName().equals(ResourceGeneralPage.getNameText())); + assertTrue(service.getDescription().equals(ResourceGeneralPage.getDescriptionText())); + assertTrue(service.getCategory().equals(ServiceGeneralPage.getCategoryText())); + assertTrue(service.getProjectCode().equals(ServiceGeneralPage.getProjectCodeText())); + for(String tag: ServiceGeneralPage.getTags()){ + assertTrue(service.getTags().contains(tag)); + } + assertTrue(service.getContactId().equals(ResourceGeneralPage.getContactIdText())); + } + + public static void verifyServiceDeletedInUI(ServiceReqDetails service) throws InterruptedException { + Thread.sleep(1000); + List cardElements = GeneralUIUtils.getElementsByCSS(DataTestIdEnum.DashboardCardEnum.DASHBOARD_CARD.getValue()); + if (!(cardElements.isEmpty())){ + for (WebElement cardElement: cardElements){ + WebElement componentName = GeneralUIUtils.getElementfromElementByCSS(cardElement, + DataTestIdEnum.DashboardCardEnum.INFO_NAME.getValue()); + WebElement componentType = GeneralUIUtils.getElementfromElementByCSS(cardElement, + DataTestIdEnum.DashboardCardEnum.ASSET_TYPE_CSS.getValue()); + + String componentNameStr = componentName.getAttribute("textContent").trim(), + componentTypeStr = componentType.getAttribute("class"); + + if(componentTypeStr.equals("S")){ + assertTrue( !(componentNameStr.equals(service.getName())), "Deleted service was found !!!"); + } + } + } + } + + public static void verifyServiceLifecycle(ServiceReqDetails service, User user, LifecycleStateEnum expectedLifecycleState) { + String responseAfterDrag = RestCDUtils.getService(service, user).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + String actualLifecycleState = jsonResource.get("lifecycleState").toString(); + assertTrue(expectedLifecycleState.name().equals(actualLifecycleState), "actual: " + actualLifecycleState + "-- expected: " + expectedLifecycleState); + } + + public static void verifyLinkCreated(ServiceReqDetails createServiceInUI, User user, int expectedRelationsSize) { + String responseAfterDrag = RestCDUtils.getService(createServiceInUI, user).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + assertTrue(((JSONArray) jsonResource.get("componentInstancesRelations")).size() == expectedRelationsSize); + + } + + public static void verifyManagmentWorkflow(String expectedName, String expectedDescription){ + String actualName = GeneralUIUtils.getWebElementBy(By.cssSelector("div[class='text name']")).getText(); + String actualDescription = GeneralUIUtils.getWebElementBy(By.cssSelector("div[class='text description']")).getText(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Verifing name ( should be %s ) and description ( should be %s ) ", expectedName, expectedDescription)); + assertTrue(actualName.equals(expectedName) && actualDescription.equals(expectedDescription)); + } + + public static void verifyVersionUI(String expected){ + String actualVersion = GeneralUIUtils.getSelectedElementFromDropDown(DataTestIdEnum.GeneralElementsEnum.VERSION_HEADER.getValue()).getText().replace("V", ""); + assertTrue(actualVersion.equals(expected), String.format( "Expected version: %s, Actual version: %s", expected, actualVersion)); + } + + public static void verifyOpenTabTitle(DataTestIdEnum.CompositionScreenEnum currentTab) throws Exception{ + List expectedTitles = new ArrayList(); + for(String expectedTitle: currentTab.getTitle()){ + expectedTitles.add(expectedTitle); + } + for (WebElement actualTitle: CompositionPage.getOpenTabTitle()){ + int indexOfTitle = expectedTitles.indexOf(actualTitle.getText()); + assertTrue(indexOfTitle >= 0, "Wrong title"); + expectedTitles.remove(indexOfTitle); + } + assertTrue(expectedTitles.size() == 0, "Missing titles in " + currentTab.getValue()); + } + + public static void verifyDeploymentPageSubElements(String moduleName, DeploymentViewVerificator verificatorObj) throws Exception{ + HashMap> moduleProperties = verificatorObj.getDeploymentViewData().get(moduleName); + + ServiceVerificator.moveMetadataPropertiesArtifactSection(-700); + + List artifacts, properties; + artifacts = DeploymentPage.getArtifactNames(); + properties = DeploymentPage.getPropertyNames(); + assertTrue(moduleProperties.get("artifacts").size() == artifacts.size(), "Artifacts amount not as expected, expected " + moduleProperties.get("artifacts").size()); + assertTrue(moduleProperties.get("artifacts").containsAll(artifacts.stream(). + map(e -> e.getAttribute("textContent")). + collect(Collectors.toList()))); + assertTrue(moduleProperties.get("properties").size() == properties.size(), "Properties amount not as expected, expected " + moduleProperties.get("properties").size()); + assertTrue(moduleProperties.get("properties").containsAll(properties.stream(). + map(e -> e.getAttribute("textContent")). + collect(Collectors.toList()))); + + DeploymentPage.clickOnProperties(); + DeploymentPage.clickOnArtifacts(); + ServiceVerificator.moveMetadataPropertiesArtifactSection(700); + } + + public static void verifyVFModuleCustomizationUUID(ServiceReqDetails service) throws Exception { + Predicate componentInstancePredicate = e -> e.length() > 35; + List customizationUUIDList = getAllVFModuleCustomizationUUIDs(service); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating vfModuleCustomizationUUID uniqness ... ")); + assertTrue(customizationUUIDList.stream().allMatch(componentInstancePredicate), "vfModuleCustomizationUUID is less then 35 chars"); + CustomizationUUIDVerificator.validateCustomizationUUIDuniqueness(customizationUUIDList); + } + + public static List getAllVFModuleCustomizationUUIDs(ServiceReqDetails service) throws Exception { + Service serviceObj = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, service.getName(), service.getVersion()); + List customizationUUIDList = serviceObj.getComponentInstances().get(0).getGroupInstances().stream(). + map(e -> e.getCustomizationUUID()). + collect(Collectors.toList()); + + return customizationUUIDList; + } + + public static String getVFModulePropertieValue(ServiceReqDetails service, String propertyName, String moduleName) throws Exception { + Service serviceObj = AtomicOperationUtils.getServiceObjectByNameAndVersion(UserRoleEnum.DESIGNER, service.getName(), service.getVersion()); + List groupInstances = serviceObj.getComponentInstances().get(0).getGroupInstances(); + List groupInstancesProperties = groupInstances.stream(). + filter(e -> e.getName().equals(moduleName)). + findFirst(). + get(). + convertToGroupInstancesProperties(); + String propertieValue = groupInstancesProperties.stream(). + filter(e -> e.getName().equals(propertyName)). + findFirst(). + get(). + getValue(); + return propertieValue; + } + + public static boolean isEqualCustomizationUUIDsAfterChanges(List listBefore, List listAfter){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating if vfModuleCustomizationUUID changed after certification ... ")); + return (listBefore.size() == listAfter.size()) && (listBefore.containsAll(listAfter)); + } + + public static void verifyDisabledServiceProperties() throws Exception{ + List propertiesForCheck = Arrays.asList("isBase", "vf_module_type", "vf_module_label", "vf_module_description"); + List popupElementsForCheck = Arrays.asList(PropertiesPopupEnum.PROPERTY_NAME, + PropertiesPopupEnum.PROPERTY_DESCRIPTION, + PropertiesPopupEnum.PROPERTY_TYPE, + PropertiesPopupEnum.PROPERTY_VALUE); + ServiceVerificator.moveMetadataPropertiesArtifactSection(-700); + List properties = DeploymentPage.getPropertyNames(); + + for(WebElement property : properties){ + if (propertiesForCheck.contains(property.getAttribute("textContent"))){ + DeploymentPage.clickOnProperty(property); + Select propertTypeElement = new Select(GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPopupEnum.PROPERTY_TYPE.getValue())); + boolean isTypeBoolean = propertTypeElement.getFirstSelectedOption().getText().contains("boolean"); + for (PropertiesPopupEnum popupElement: popupElementsForCheck){ + if (isTypeBoolean && popupElement == PropertiesPopupEnum.PROPERTY_VALUE){ + assertTrue(GeneralUIUtils.checkForDisabledAttribute(DataTestIdEnum.PropertiesPopupEnum.PROPERTY_BOOLEAN_VALUE.getValue()), String.format("Element %s not disabled ", property.getText())); + } else { + assertTrue(GeneralUIUtils.checkForDisabledAttribute(popupElement.getValue()), String.format("Element %s not disabled ", property.getText())); + } + } + new PropertyPopup().clickCancel(); + } + } + + DeploymentPage.clickOnProperties(); + ServiceVerificator.moveMetadataPropertiesArtifactSection(700); + } + + public static void verifyEnabledServiceProperties() throws Exception{ + List propertiesForCheck = Arrays.asList("initial_count", "max_vf_module_instances", "min_vf_module_instances"); + + ServiceVerificator.moveMetadataPropertiesArtifactSection(-700); + List properties = DeploymentPage.getPropertyNames(); + + ServiceVerificator.positiveFlow(propertiesForCheck, properties); + ServiceVerificator.negativeFlow(propertiesForCheck, properties); + + DeploymentPage.clickOnProperties(); + ServiceVerificator.moveMetadataPropertiesArtifactSection(700); + } + + public static void positiveFlow(List propertiesForCheck, List properties) + throws InterruptedException { + int baseNumber = new Random().nextInt(100) + 2; + for(WebElement property : properties){ + String propertyName = property.getAttribute("textContent"); + if (propertiesForCheck.contains(propertyName)){ + DeploymentPage.clickOnProperty(property); + int actualNumber = 0; + if (propertyName.equals("initial_count")){ + actualNumber = baseNumber; + } else if (propertyName.equals("max_vf_module_instances")) { + actualNumber = baseNumber + 1; + } else if (propertyName.equals("min_vf_module_instances")){ + actualNumber = baseNumber - 1; + } + + new PropertyPopup().insertPropertyDefaultValue(String.valueOf(actualNumber)); + new PropertyPopup().clickSave(); + assertTrue(DeploymentPage.getPropertyValueFromPropertiesList(propertyName).equals(String.valueOf(actualNumber))); + } + } + } + + public static void negativeFlow(List propertiesForCheck, List properties) + throws Exception { + int currentMaxValue = Integer.valueOf(DeploymentPage.getPropertyValueFromPropertiesList("max_vf_module_instances")); + int currentMinValue = Integer.valueOf(DeploymentPage.getPropertyValueFromPropertiesList("min_vf_module_instances")); + int currentInitialValue = Integer.valueOf(DeploymentPage.getPropertyValueFromPropertiesList("initial_count")); + PropertyPopup propertyPopupObj = new PropertyPopup(); + + for(WebElement property : properties){ + String propertyName = property.getAttribute("textContent"); + if (propertiesForCheck.contains(propertyName)){ + DeploymentPage.clickOnProperty(property); + if (propertyName.equals("initial_count")){ + + propertyPopupObj.insertPropertyDefaultValue(String.valueOf(currentMaxValue + 1)); + ServiceVerificator.verifyErrorPresentAndSaveDisabled(); + propertyPopupObj.insertPropertyDefaultValue(String.valueOf(currentMinValue - 1)); + ServiceVerificator.verifyErrorPresentAndSaveDisabled(); + propertyPopupObj.insertPropertyDefaultValue(String.valueOf(0)); + ServiceVerificator.verifyErrorPresentAndSaveDisabled(); + + } else if (propertyName.equals("max_vf_module_instances")) { + + propertyPopupObj.insertPropertyDefaultValue(String.valueOf(currentInitialValue - 1)); + ServiceVerificator.verifyErrorPresentAndSaveDisabled(); + propertyPopupObj.insertPropertyDefaultValue(String.valueOf(currentMinValue - 1)); + ServiceVerificator.verifyErrorPresentAndSaveDisabled(); + propertyPopupObj.insertPropertyDefaultValue(String.valueOf(0)); + verifyErrorPresentAndSaveDisabled(); + + } else if (propertyName.equals("min_vf_module_instances")){ + + propertyPopupObj.insertPropertyDefaultValue(String.valueOf(currentInitialValue + 1)); + ServiceVerificator.verifyErrorPresentAndSaveDisabled(); + propertyPopupObj.insertPropertyDefaultValue(String.valueOf(currentMaxValue + 1)); + ServiceVerificator.verifyErrorPresentAndSaveDisabled(); + } + + new PropertyPopup().clickCancel(); + } + } + } + + public static void verifyErrorPresentAndSaveDisabled() throws Exception{ + assertTrue(DeploymentPage.isPropertySaveButtonDisabled()); + assertTrue(DeploymentPage.getPropertyErrorValidationMessdge().size() == 1); + } + + public static void moveMetadataPropertiesArtifactSection(int offset) throws InterruptedException { + WebElement dragLineElement = GeneralUIUtils.getElementByCSS("div.rg-top"); + GeneralUIUtils.dragAndDropElementByY(dragLineElement, offset); + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/UserManagementVerificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/UserManagementVerificator.java new file mode 100644 index 0000000000..3b0b458f1e --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/UserManagementVerificator.java @@ -0,0 +1,152 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.verificator; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.text.WordUtils; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.enums.UserRoleEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.pages.AdminGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.openecomp.sdc.ci.tests.utils.validation.ErrorValidationUtils; +import org.openqa.selenium.WebElement; +import org.testng.Assert; + +import com.aventstack.extentreports.Status; + +public class UserManagementVerificator { + + + + public static void validateUserCreated(String userId, UserRoleEnum role){ + + ExtentTestActions.log(Status.INFO, "Validating that a new user is created and displayed in the first row in the table."); + + final int firstRow = 0; + + WebElement actualFirstName = AdminGeneralPage.getUserManagementTab().getFirstName(firstRow); + WebElement actualLastName = AdminGeneralPage.getUserManagementTab().getLastName(firstRow); + WebElement actualUserId = AdminGeneralPage.getUserManagementTab().getUserId(firstRow); + WebElement actualEmail = AdminGeneralPage.getUserManagementTab().getEmail(firstRow); + WebElement actualRole = AdminGeneralPage.getUserManagementTab().getRole(firstRow); + WebElement actualLastActive = AdminGeneralPage.getUserManagementTab().getLastActive(firstRow); + + + String actualFirstNameText = actualFirstName.getText(); + String actualLastNameText = actualLastName.getText(); + String actualUserIdText = actualUserId.getText(); + String actualEmailText = actualEmail.getText(); + String actualRoleText = actualRole.getText(); + String actualLastActiveText = actualLastActive.getText(); + + Assert.assertTrue(actualFirstNameText.equals("---"), "Actual first name is not '---'."); + Assert.assertTrue(actualLastNameText.equals("---"), "Actual last name is not '---'."); + Assert.assertTrue(actualUserIdText.equals(userId), "Actual user id is not " + userId); + Assert.assertTrue(actualEmailText.equals("---"), "Actual email is not '---'."); + Assert.assertTrue(actualRoleText.equals(WordUtils.capitalize(role.name().toLowerCase())), "Actual role is not " + role.name()); + Assert.assertTrue(actualLastActiveText.equals("Waiting"), "Actual role is not 'Waiting'."); + } + + + public static void validateUserRoleUpdated(int rowIndx, UserRoleEnum updatedRole){ + ExtentTestActions.log(Status.INFO, "Validating role is updated to " + updatedRole.name() + " in UI."); + WebElement actualRole = AdminGeneralPage.getUserManagementTab().getRole(rowIndx); + String actualRoleText = actualRole.getText(); + Assert.assertTrue(actualRoleText.equals(WordUtils.capitalize(updatedRole.name().toLowerCase())), "Actual role is not " + updatedRole.name()); + } + + public static void validateUserRoleUpdatedViaRest(User reqUser, User user, UserRoleEnum expectedUserRole){ + try{ + ExtentTestActions.log(Status.INFO, "Validating role is updated to " + expectedUserRole.name() + " in BE."); + String actualUserRole = RestCDUtils.getUserRole(reqUser, user); + Assert.assertTrue(expectedUserRole.name().toLowerCase().equals(actualUserRole.toLowerCase()), "User role is not updated."); + } + catch(Exception e){ + Assert.fail("The actual user role is null"); + } + } + + public static void validateUserNotFoundViaRest(User reqUser, User user){ + try{ + ExtentTestActions.log(Status.INFO, "Validating user " + reqUser.getUserId() + " is not found in BE."); + RestResponse getUserResp = RestCDUtils.getUser(reqUser, user); + ErrorValidationUtils.checkBodyResponseOnError(ActionStatus.USER_INACTIVE.name(), Arrays.asList(reqUser.getUserId()), getUserResp.getResponse()); + } + catch(Exception e){ + Assert.fail("The response message does not describe the user is not found."); + } + } + + public static void validateUserIdNotFound(String userId){ + ExtentTestActions.log(Status.INFO, "Validating that user " + userId + " is not found."); + AdminGeneralPage.getUserManagementTab().searchUser(userId); + List rows = AdminGeneralPage.getUserManagementTab().getAllRowsDisplayed(); + Assert.assertEquals(rows.size(), 0, String.format("There are %s rows instead of none.", rows.size())); + } + + public static void validateOnlySingleRowDisplayed(){ + ExtentTestActions.log(Status.INFO, "Validating that only a single row is displayed in table."); + List rows = AdminGeneralPage.getUserManagementTab().getAllRowsDisplayed(); + Assert.assertEquals(rows.size(), 1, String.format("There are %s rows instead of %s.", rows.size(), 1)); + } + + public static void validateRowDisplayedCorrectly(User user, int rowindex){ + String role = user.getRole(); + String userId = user.getUserId(); + String firstName = user.getFirstName(); + String lastName = user.getLastName(); + String email = user.getEmail(); + + ExtentTestActions.log(Status.INFO, "Validating that the row is properly displayed."); + + WebElement actualFirstName = AdminGeneralPage.getUserManagementTab().getFirstName(rowindex); + WebElement actualLastName = AdminGeneralPage.getUserManagementTab().getLastName(rowindex); + WebElement actualUserId = AdminGeneralPage.getUserManagementTab().getUserId(rowindex); + WebElement actualEmail = AdminGeneralPage.getUserManagementTab().getEmail(rowindex); + WebElement actualRole = AdminGeneralPage.getUserManagementTab().getRole(rowindex); + + + String actualFirstNameText = actualFirstName.getText(); + String actualLastNameText = actualLastName.getText(); + String actualUserIdText = actualUserId.getText(); + String actualEmailText = actualEmail.getText(); + String actualRoleText = actualRole.getText(); + + Assert.assertTrue(actualFirstNameText.equals(firstName), "Actual first name is not " + firstName); + Assert.assertTrue(actualLastNameText.equals(lastName), "Actual last name is not " + lastName); + Assert.assertTrue(actualUserIdText.equals(userId), "Actual user id is not " + userId); + Assert.assertTrue(actualEmailText.contains(email), "Actual email does not contain " + email); + Assert.assertTrue(actualRoleText.equals(WordUtils.capitalize(role.toLowerCase())), "Actual role is not " + role); + } + + public static void validateFirstRowDisplayedCorrectly(User user){ + validateRowDisplayedCorrectly(user, 0); + } + + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VFCArtifactVerificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VFCArtifactVerificator.java new file mode 100644 index 0000000000..ac009c6327 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VFCArtifactVerificator.java @@ -0,0 +1,347 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.verificator; + +import static org.testng.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.ci.tests.datatypes.HeatMetaFirstLevelDefinition; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.VFCArtifact; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.testng.Assert; + +import com.aventstack.extentreports.Status; + +public class VFCArtifactVerificator { + + private static final String ARTIFACTS = "artifacts"; + private static final String DEPLOYMENT_ARTIFACTS = "deploymentArtifacts"; + private static List vfcArtifactList = new ArrayList(); + private static JSONObject jsonResource; + + public static void verifyVFCArtifactsNotInVFArtifactList(ResourceReqDetails resource , User user, RestResponse optionalGetResponse, Map> expectedArtifactMap){ + ExtentTestActions.log(Status.INFO, "Verifying that VFC artifacts are not as part of VF artifacts."); + LinkedList expectedDeploymentArtifacts = expectedArtifactMap.get(DEPLOYMENT_ARTIFACTS); + LinkedList expectedInformationalArtifacts = expectedArtifactMap.get(ARTIFACTS); + + Map vfDepArtifacts = getVFDeploymentArtifacts(resource, user, optionalGetResponse); + for (Object artifact : vfDepArtifacts.values()){ + JSONObject acArtifact = ((JSONObject) JSONValue.parse(artifact.toString())); + String acArtifactName = acArtifact.get("artifactName").toString(); + + for(HeatMetaFirstLevelDefinition exDepArtifact : expectedDeploymentArtifacts){ + assertTrue(!exDepArtifact.getType().equals(acArtifactName)); + } + } + + Map vfInfoArtifacts = getVFInforamtionalArtifacts(resource, user, optionalGetResponse); + for (Object artifact : vfInfoArtifacts.values()){ + JSONObject acArtifact = ((JSONObject) JSONValue.parse(artifact.toString())); + if (acArtifact.containsKey("artifactName")){ + String acArtifactName = acArtifact.get("artifactName").toString(); + + for(HeatMetaFirstLevelDefinition exInfoArtifact : expectedInformationalArtifacts){ + assertTrue(!exInfoArtifact.getType().equals(acArtifactName)); + } + } + + + } + + + + } + + public static void verifyVfcArtifactUpdated(String instanceName, ResourceReqDetails resource, User user){ + ExtentTestActions.log(Status.INFO, "Verifying VFC artifacts are updated."); + List vfcArtifactsBeforeUpdate = getVfcArtifactList(); + + setVfcArtifactList(new ArrayList()); + setActualVfcArtifactList(instanceName, resource, user); + + for (VFCArtifact artifact : vfcArtifactsBeforeUpdate){ + String artifactnameBeforeUpdate = artifact.getArtifactname(); + for (VFCArtifact newArtifact : vfcArtifactList){ + String artifactnameAfterUpdate = newArtifact.getArtifactname(); + if (artifactnameBeforeUpdate.equals(artifactnameAfterUpdate)){ + String artifactUUIDAfterUpdate = newArtifact.getArtifactUUID(); + assertTrue(!artifactUUIDAfterUpdate.equals(artifact.getArtifactUUID())); + + int artifactVersionAfterUpdate = Integer.parseInt(newArtifact.getArtifactVersion()); + int artifactVersionBeforeUpdate = Integer.parseInt(artifact.getArtifactVersion()); + assertTrue(artifactVersionAfterUpdate == artifactVersionBeforeUpdate + 1); + + + vfcArtifactList.remove(newArtifact); + + ExtentTestActions.log(Status.INFO, "VFC artifacts are updated and verified."); + + break; + } + } + } + + + assertTrue(vfcArtifactList.size() == 0); + + } + + public static void verifyVFCArtifactNotChanged(String instanceName, ResourceReqDetails resource, User user){ + ExtentTestActions.log(Status.INFO, "Verifying VFC artifacts are not chaned after update."); + List vfcArtifactsBeforeUpdate = getVfcArtifactList(); + + setVfcArtifactList(new ArrayList()); + setActualVfcArtifactList(instanceName, resource, user); + + for (VFCArtifact artifact : vfcArtifactsBeforeUpdate){ + String artifactnameBeforeUpdate = artifact.getArtifactname(); + for (VFCArtifact newArtifact : vfcArtifactList){ + String artifactnameAfterUpdate = newArtifact.getArtifactname(); + if (artifactnameBeforeUpdate.equals(artifactnameAfterUpdate)){ + String artifactUUIDAfterUpdate = newArtifact.getArtifactUUID(); + assertTrue(artifactUUIDAfterUpdate.equals(artifact.getArtifactUUID())); + + int artifactVersionAfterUpdate = Integer.parseInt(newArtifact.getArtifactVersion()); + int artifactVersionBeforeUpdate = Integer.parseInt(artifact.getArtifactVersion()); + assertTrue(artifactVersionAfterUpdate == artifactVersionBeforeUpdate); + + vfcArtifactList.remove(newArtifact); + break; + } + } + } + + + assertTrue(vfcArtifactList.size() == 0); + + } + + public static void verifyNoVfcArtifacts(ResourceReqDetails resource , User user, RestResponse optionalGetResponse){ + ExtentTestActions.log(Status.INFO, "Verifying that there are no VFC artifacts at all."); + JSONArray jArr = getVFInstances(resource, user, optionalGetResponse); + for (Object instanceObj : jArr){ + JSONObject instance = (JSONObject) JSONValue.parse(instanceObj.toString()); + List actualDeploymentArtifacts = getActualVfcInstanceArtifactsFromJson(DEPLOYMENT_ARTIFACTS, instance); + + assertTrue(actualDeploymentArtifacts == null || actualDeploymentArtifacts.size() == 0); + } + } + + public static void verifyVfcArtifacts(ResourceReqDetails resource , User user, String instanceName, Map> expectedArtifactMap, + RestResponse optionalGetResponse){ + ExtentTestActions.log(Status.INFO, "Verifying VFC artifacts for instance named " + instanceName); + + String exCompName = instanceName.split(".vfc.")[1].toLowerCase(); + String exName = instanceName.split(".heat.")[1].toLowerCase(); + + JSONArray jArr = getVFInstances(resource, user, optionalGetResponse); + int jArrSize = jArr.size(); + + for (Object instanceObj : jArr){ + JSONObject instance = (JSONObject) JSONValue.parse(instanceObj.toString()); + String componentName = instance.get("componentName").toString().toLowerCase(); + String name = instance.get("name").toString().toLowerCase(); + + if (componentName.contains(exCompName) || name.toLowerCase().equals(exName)){ + + List actualDeploymentArtifacts = getActualVfcInstanceArtifactsFromJson(DEPLOYMENT_ARTIFACTS, instance); + LinkedList expectedDeploymentArtifacts = expectedArtifactMap.get(DEPLOYMENT_ARTIFACTS); + checkVFCArtifactsExist(expectedDeploymentArtifacts, actualDeploymentArtifacts); + + + List actualInformationalArtifacts = getActualVfcInstanceArtifactsFromJson(ARTIFACTS, instance); + LinkedList expectedInformationalArtifacts = expectedArtifactMap.get(ARTIFACTS); + checkVFCArtifactsExist(expectedInformationalArtifacts, actualInformationalArtifacts); + + jArr.remove(instanceObj); + + ExtentTestActions.log(Status.INFO, "VFC artifacts for instance named " + instanceName + "are verified."); + + break; + } + } + + assertTrue(jArr.size() == jArrSize - 1, "Instance " + instanceName + " was not found and tested"); + + } + + + + private static JSONArray getVFInstances(ResourceReqDetails resource, User user, RestResponse response) { + + jsonResource = getVFAsJsonObject(resource, user, response); + JSONArray jArr = (JSONArray) jsonResource.get("componentInstances"); + return jArr; + } + + private static Map getVFDeploymentArtifacts(ResourceReqDetails resource, User user, RestResponse response) { + + jsonResource = getVFAsJsonObject(resource, user, response); + Map jArr = (Map) jsonResource.get(DEPLOYMENT_ARTIFACTS); + return jArr; + } + + private static Map getVFInforamtionalArtifacts(ResourceReqDetails resource, User user, RestResponse response) { + + jsonResource = getVFAsJsonObject(resource, user, response); + Map jArr = (Map) jsonResource.get(ARTIFACTS); + return jArr; + } + + private static JSONObject getVFAsJsonObject(ResourceReqDetails resource, User user, RestResponse response) { + if (response == null){ + resource.setUniqueId(null); + response = RestCDUtils.getResource(resource, user); + assertTrue(response.getErrorCode().intValue() == 200); + getVFAsJsonObject(resource, user, response); + } + + String responseAfterDrag = response.getResponse(); + jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + return jsonResource; + } + + + + private static List getActualVfcInstanceArtifactsFromJson(String artifactKind, JSONObject instanceFromJson){ + Object actualtObject = instanceFromJson.get(artifactKind); + if (actualtObject != null){ + JSONObject actualJsonObject = (JSONObject) JSONValue.parse(actualtObject.toString()); + List actualArtifacts = (List) actualJsonObject.keySet().stream().map(e -> actualJsonObject.get(e).toString()).collect(Collectors.toList()); + return actualArtifacts; + } + return null; + } + + private static void checkVFCArtifactsExist(LinkedList expectedArtifacts, List actualArtifacts) { + if (expectedArtifacts == null){ + return; + } + + if (expectedArtifacts.size() != actualArtifacts.size()){ + ExtentTestActions.log(Status.FAIL, "Expected and actual VFC artifacts lists size are not the same. Expected size: " + expectedArtifacts.size() + " , actual size: " + actualArtifacts.size()); + Assert.fail("Expected and actual VFC artifacts lists size are not the same. Expected size: " + expectedArtifacts.size() + " , actual size: " + actualArtifacts.size()); + } + + List types = new ArrayList(); + List fileNames = new ArrayList(); + for (HeatMetaFirstLevelDefinition exArtifact : expectedArtifacts){ + + fileNames.add(exArtifact.getFileName()); + types.add(exArtifact.getType()); + + } + + for (int i = 0 ; i < actualArtifacts.size() ; i++){ + String actualArtifactsString = actualArtifacts.get(i); + JSONObject acArtifact = ((JSONObject) JSONValue.parse(actualArtifactsString)); + + String acArtifactFileName = acArtifact.get("artifactName").toString(); + String acArtifactType = acArtifact.get("artifactType").toString(); + + assertTrue(types.contains(acArtifactType), "List does not contain " + acArtifactType); + assertTrue(fileNames.contains(acArtifactFileName), "List does not contain " + acArtifactFileName); + + types.remove(acArtifactType); + fileNames.remove(acArtifactFileName); + + } + + assertTrue(types.size() == 0); + assertTrue(fileNames.size() == 0); + + } + + public static List getVfcArtifactList(){ + return vfcArtifactList; + } + + + public static void setVfcArtifactList(List vfcArtifactList) { + VFCArtifactVerificator.vfcArtifactList = vfcArtifactList; + } + + public static void setActualVfcArtifactList(String instanceName, ResourceReqDetails resource , User user) { + String exCompName = instanceName.split(".vfc.")[1].toLowerCase(); + String exName = instanceName.split(".heat.")[1].toLowerCase(); + + JSONArray jArr = getVFInstances(resource, user, null); + + for (Object instanceObj : jArr){ + JSONObject instance = (JSONObject) JSONValue.parse(instanceObj.toString()); + String componentName = instance.get("componentName").toString().toLowerCase(); + String name = instance.get("name").toString().toLowerCase(); + + if (componentName.contains(exCompName) || name.toLowerCase().equals(exName)){ + List actualDeploymentArtifacts = getActualVfcInstanceArtifactsFromJson(DEPLOYMENT_ARTIFACTS, instance); + List actualInformationalArtifacts = getActualVfcInstanceArtifactsFromJson(ARTIFACTS, instance); + + if (actualDeploymentArtifacts != null){ + for (int i = 0 ; i < actualDeploymentArtifacts.size() ; i++){ + String actualArtifactsString = actualDeploymentArtifacts.get(i); + JSONObject acArtifact = ((JSONObject) JSONValue.parse(actualArtifactsString)); + + if (acArtifact.containsKey("artifactName")){ + String acArtifactType = acArtifact.get("artifactName").toString(); + String acArtifactFileName = acArtifact.get("artifactType").toString(); + String acArtifactUUID = acArtifact.get("artifactUUID").toString(); + String acArtifactVersion = acArtifact.get("artifactVersion").toString(); + + vfcArtifactList.add(new VFCArtifact(acArtifactType, acArtifactFileName, acArtifactUUID, acArtifactVersion)); + } + } + } + if (actualInformationalArtifacts != null){ + for (int i = 0 ; i < actualInformationalArtifacts.size() ; i++){ + String actualArtifactsString = actualInformationalArtifacts.get(i); + JSONObject acArtifact = ((JSONObject) JSONValue.parse(actualArtifactsString)); + + if (acArtifact.containsKey("artifactName")){ + String acArtifactType = acArtifact.get("artifactName").toString(); + String acArtifactFileName = acArtifact.get("artifactType").toString(); + String acArtifactUUID = acArtifact.get("artifactUUID").toString(); + String acArtifactVersion = acArtifact.get("artifactVersion").toString(); + vfcArtifactList.add(new VFCArtifact(acArtifactType, acArtifactFileName, acArtifactUUID, acArtifactVersion)); + } + + + } + } + } + } + } + +} + + + diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VFCverificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VFCverificator.java new file mode 100644 index 0000000000..0872a3a5c3 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VFCverificator.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.verificator; + +import static org.testng.AssertJUnit.assertFalse; + +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; + + +public class VFCverificator { + + public static void verifyVFCUpdatedInUI(ResourceReqDetails vf) { + assertFalse(vf.getName().equals(ResourceGeneralPage.getNameText())); + assertFalse(vf.getDescription().equals(ResourceGeneralPage.getDescriptionText())); + assertFalse(vf.getVendorName().equals(ResourceGeneralPage.getVendorNameText())); + assertFalse(vf.getVendorRelease().equals(ResourceGeneralPage.getVendorReleaseText())); + } +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VfModuleVerificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VfModuleVerificator.java new file mode 100644 index 0000000000..7f01b86eaf --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VfModuleVerificator.java @@ -0,0 +1,156 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.verificator; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.GroupInstance; +import org.openecomp.sdc.be.model.GroupProperty; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.ci.tests.datatypes.TypeHeatMetaDefinition; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaDefinition; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaGroupsMetadataDefinition; +import org.openecomp.sdc.ci.tests.tosca.datatypes.ToscaGroupsTopologyTemplateDefinition; +import org.openecomp.sdc.ci.tests.utils.ToscaParserUtils; + +import com.aventstack.extentreports.Status; + +public class VfModuleVerificator { + + private static final String [] PROPERTY_TYPES = {"vf_module_label", "min_vf_module_instances", "max_vf_module_instances", "initial_count"}; + private static final String VF_MODULE_TYPE = "org.openecomp.groups.VfModule"; + + /** + * compare number of groups from HEAT.meta file vs TOSCA yaml groups generated by ASDC + * @param listTypeHeatMetaDefinition - java object created from HEAT.meta file + * @param toscaDefinition - java object created from TOSCA yaml + */ + public static void compareNumberOfVfModules(List listTypeHeatMetaDefinition, ToscaDefinition toscaDefinition) { + + int heatMetaGroupCount = 0; + int toscaDefinitionGroupCount = 0; + for (TypeHeatMetaDefinition typeHeatMetaDefinition : listTypeHeatMetaDefinition) { + heatMetaGroupCount = typeHeatMetaDefinition.getGroupHeatMetaDefinition().size(); + } + toscaDefinitionGroupCount = toscaDefinition.getTopology_template().getGroups().size(); + assertEquals("Expected num of groups in HEAT.meta file is " + heatMetaGroupCount + ", but was in TOSCA yaml file " + toscaDefinitionGroupCount, heatMetaGroupCount, toscaDefinitionGroupCount); + } + + /** + * check group structure and "metadata" parameters vs data on the service object + * @param toscaDefinition + */ + public static void verifyGroupMetadata(ToscaDefinition toscaDefinition, Service service) { + + Map groups = toscaDefinition.getTopology_template().getGroups(); + for (Map.Entry groupTopologyTemplateDefinition : groups.entrySet()) { + String key = groupTopologyTemplateDefinition.getKey(); + GroupInstance groupInstanceObject = getGroupInstanceByKey(key, service); + ToscaGroupsMetadataDefinition metadata = groupTopologyTemplateDefinition.getValue().getMetadata(); + assertNotNull("groupInstanceObject is null", groupInstanceObject); + assertTrue("expected vfModuleModelName " + groupInstanceObject.getGroupName() + ", actual " + metadata.getVfModuleModelName(), groupInstanceObject.getGroupName().equals(metadata.getVfModuleModelName())); + assertTrue("expected vfModuleModelInvariantUUID " + groupInstanceObject.getInvariantUUID() + ", actual " + metadata.getVfModuleModelInvariantUUID(), groupInstanceObject.getInvariantUUID().equals(metadata.getVfModuleModelInvariantUUID())); + assertTrue("expected vfModuleModelCustomizationUUID " + groupInstanceObject.getCustomizationUUID() + ", actual " + metadata.getVfModuleModelCustomizationUUID(), groupInstanceObject.getCustomizationUUID().equals(metadata.getVfModuleModelCustomizationUUID())); + assertTrue("expected vfModuleModelUUID " + groupInstanceObject.getGroupUUID() + ", actual " + metadata.getVfModuleModelUUID(), groupInstanceObject.getGroupUUID().equals(metadata.getVfModuleModelUUID())); + assertTrue("expected vfModuleModelVersion " + groupInstanceObject.getVersion() + ", actual " + metadata.getVfModuleModelVersion(), groupInstanceObject.getVersion().equals(metadata.getVfModuleModelVersion())); + } + } + + + /** + * @param key + * @param service + * @return + */ + public static GroupInstance getGroupInstanceByKey(String key, Service service) { + for(ComponentInstance componentInstance : service.getComponentInstances()){ + for(GroupInstance groupInstance : componentInstance.getGroupInstances()){ + if( key.equals(groupInstance.getName())){ + return groupInstance; + } + } + } + return null; + } + + public static void validateSpecificModulePropertiesFromRequest(Resource resource) { + List> allProperties = resource.getGroups().stream(). + filter(e -> e.getType().equals(VF_MODULE_TYPE)). + map(e -> e.getProperties()). + collect(Collectors.toList()); + for(String propertyType :PROPERTY_TYPES){ + int numberOfTypes = getPropertyType(allProperties, propertyType).size(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating VF property %s exist, Expected: %s, Actual: %s ", propertyType, allProperties.size(), numberOfTypes)); + assertTrue(numberOfTypes == allProperties.size()); + } + } + + public static List getPropertyType(List> allProperties, String propertyType) { + return allProperties.stream(). + flatMap(List::stream). + filter(e -> e.getName().equals(propertyType)). + collect(Collectors.toList()); + } + + public static void validateSpecificModulePropertiesFromFile(ToscaDefinition toscaDefinition){ + List vfModules = toscaDefinition.getTopology_template().getGroups().values().stream(). + filter(e -> e.getType().equals(VF_MODULE_TYPE)). + collect(Collectors.toList()); + + for(String propertyType :PROPERTY_TYPES){ + int numberOfTypes = (int) vfModules.stream(). + filter(e -> e.getProperties().containsKey(propertyType)). + count(); + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Validating VF property %s exist, Expected: %s, Actual: %s ", propertyType, vfModules.size(), numberOfTypes)); + assertTrue(numberOfTypes == vfModules.size()); + } + } + + public static ToscaDefinition getToscaTemplate(String pathToCsar) throws Exception { + String outputFolder = DeploymentViewVerificator.unzipCsarFile(pathToCsar); + String templateFileName = VfModuleVerificator.getTemplateFilenname(pathToCsar); + + File pathToMainServiceTemplate = new File(outputFolder + File.separator + "Definitions" + File.separator + templateFileName); + ToscaDefinition toscaDefinition = ToscaParserUtils.parseToscaYamlToJavaObject(pathToMainServiceTemplate); + + DeploymentViewVerificator.cleanFolders(new File(outputFolder).getParent()); + + return toscaDefinition; + } + + public static String getTemplateFilenname(String pathToCsar) { + File csarFile = new File(pathToCsar); + String templateFileName = csarFile.getName().replaceAll("-csar.csar", "-template.yml"); + return templateFileName; + } + +} diff --git a/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VfVerificator.java b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VfVerificator.java new file mode 100644 index 0000000000..e877146256 --- /dev/null +++ b/ui-ci/src/main/java/org/openecomp/sdc/ci/tests/verificator/VfVerificator.java @@ -0,0 +1,245 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.ci.tests.verificator; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.ci.tests.datatypes.DataTestIdEnum; +import org.openecomp.sdc.ci.tests.datatypes.LifeCycleStateEnum; +import org.openecomp.sdc.ci.tests.datatypes.ResourceReqDetails; +import org.openecomp.sdc.ci.tests.datatypes.enums.PropertyTypeEnum; +import org.openecomp.sdc.ci.tests.datatypes.http.RestResponse; +import org.openecomp.sdc.ci.tests.execute.setup.ExtentTestActions; +import org.openecomp.sdc.ci.tests.execute.setup.SetupCDTest; +import org.openecomp.sdc.ci.tests.pages.ResourceGeneralPage; +import org.openecomp.sdc.ci.tests.utilities.FileHandling; +import org.openecomp.sdc.ci.tests.utilities.GeneralUIUtils; +import org.openecomp.sdc.ci.tests.utilities.ResourceUIUtils; +import org.openecomp.sdc.ci.tests.utilities.RestCDUtils; +import org.openecomp.sdc.ci.tests.utils.rest.ResponseParser; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; +import org.testng.Assert; + +import com.aventstack.extentreports.Status; + +public final class VfVerificator { + + public static void verifyNumOfComponentInstances(ResourceReqDetails createResourceInUI, int numOfVFC, User user) { + ServiceVerificator.verifyNumOfComponentInstances(createResourceInUI, createResourceInUI.getVersion(), numOfVFC, user); + } + + public static void verifyRILocationChanged(ResourceReqDetails createResourceInUI, + ImmutablePair prevRIPos, User user) { + + ImmutablePair currRIPos = ResourceUIUtils.getFirstRIPos(createResourceInUI, user); + assertTrue(!prevRIPos.left.equals(currRIPos.left) || !prevRIPos.right.equals(currRIPos.right)); + } + + public static void verifyLinkCreated(ResourceReqDetails createResourceInUI, User user, int expectedRelationsSize) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Verifing that a link was created on canvas")); + String responseAfterDrag = RestCDUtils.getResource(createResourceInUI, user).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + assertTrue(((JSONArray) jsonResource.get("componentInstancesRelations")).size() == expectedRelationsSize); + ExtentTestActions.log(Status.INFO, "The link was verified."); + + } + + public static void verifyVFMetadataInUI(ResourceReqDetails vf) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Verifying fields on General screen through UI ...")); + assertTrue(vf.getName().equals(ResourceGeneralPage.getNameText())); + assertTrue(vf.getDescription().equals(ResourceGeneralPage.getDescriptionText())); + assertTrue(vf.getCategories().get(0).getSubcategories().get(0).getName().equals(GeneralUIUtils.getSelectedElementFromDropDown(ResourceGeneralPage.getCategoryDataTestsIdAttribute()).getText())); + assertTrue(vf.getVendorName().equals(ResourceGeneralPage.getVendorNameText())); + assertTrue(vf.getVendorRelease().equals(ResourceGeneralPage.getVendorReleaseText())); + assertTrue(vf.getContactId().equals(ResourceGeneralPage.getContactIdText())); + List tagsList = ResourceGeneralPage.getElementsFromTagsTable(); + assertTrue(vf.getTags().size() == tagsList.size()); + for (int i = 0 ; i < vf.getTags().size(); i ++ ){ + assertTrue(vf.getTags().contains(tagsList.get(i).getText())); + } + assertTrue(vf.getContactId().equals(ResourceGeneralPage.getContactIdText())); + } + + public static void verifyVFUpdated(ResourceReqDetails vf, User user) { + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Verifying fields on General screen through Backend ...")); + String response = RestCDUtils.getResource(vf, user).getResponse(); + Resource resource = ResponseParser.convertResourceResponseToJavaObject(response); + assertTrue(vf.getName().equals(resource.getName())); + assertTrue(vf.getDescription().equals(resource.getDescription())); + assertTrue(vf.getVendorName().equals(resource.getVendorName())); + assertTrue(vf.getVendorRelease().equals(resource.getVendorRelease())); + assertTrue(vf.getContactId().equals(resource.getContactId())); + + assertTrue(vf.getCategories().size() == (resource.getCategories().size())); + for (int i = 0 ; i < vf.getCategories().size() ; i ++) + { + CategoryDefinition expectedCategoryDefinition = vf.getCategories().get(i); + CategoryDefinition actualCategoryDefinition = resource.getCategories().get(i); + assertTrue(expectedCategoryDefinition.getName().equals(actualCategoryDefinition.getName())); + assertTrue(expectedCategoryDefinition.getSubcategories().get(i).getName().equals(actualCategoryDefinition.getSubcategories().get(i).getName())); + } + + assertTrue(vf.getTags().size() == (resource.getTags().size())); + for (int i = 0 ; i < vf.getTags().size() ; i ++){ + List expectedTags = vf.getTags(); + List actualTags = resource.getTags(); + + assertTrue(actualTags.contains(expectedTags.get(i))); + + } + } + + public static void verifyVFLifecycle(ResourceReqDetails vf, User user, LifecycleStateEnum expectedLifecycleState) { + String responseAfterDrag = RestCDUtils.getResource(vf, user).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + String actualLifecycleState = jsonResource.get("lifecycleState").toString(); + assertTrue(expectedLifecycleState.name().equals(actualLifecycleState), "actual: " + actualLifecycleState + "-- expected: " + expectedLifecycleState); + } + + public static void verifyVfLifecycleInUI(LifeCycleStateEnum lifecycleState){ + GeneralUIUtils.ultimateWait(); + assertTrue(ResourceGeneralPage.getLifeCycleState().equals(lifecycleState.getValue())); + } + + public static void verifyInstanceVersion(ResourceReqDetails vf, User user, String instanceName, String instanceVersion){ + String responseAfterDrag = RestCDUtils.getResource(vf, user).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + JSONArray jsonArrayResource = (JSONArray) jsonResource.get("componentInstances"); + for (int i = 0; i < jsonArrayResource.size(); i++){ + Object object = jsonArrayResource.get(i); + try{ + JSONObject jRes = (JSONObject) JSONValue.parse(object.toString()); + String componentName = jRes.get("componentName").toString(); + if (componentName.equals(instanceName)){ + String componentVersion = jRes.get("componentVersion").toString(); + assertTrue(componentVersion.equals(instanceVersion)); + } + } + catch(Exception e){ + System.out.println("Can't test object in componentInstances array"); + Assert.fail("Can't test object in componentInstances array"); + } + } + } + + public static void verifyVfDeleted(ResourceReqDetails vf, User user){ + RestResponse response = RestCDUtils.getResource(vf, user); + assertTrue(response.getErrorCode().intValue() == 404); + } + + public static void verifyPropertiesInUI(List propertyList){ + + for (PropertyTypeEnum prop : propertyList){ + String propName = prop.getName(); + + String actualName = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPageEnum.PROPERTY_NAME.getValue() + propName).getText(); + String actualType = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPageEnum.PROPERTY_TYPE.getValue() + propName).getText(); + String actualDesciprtion = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPageEnum.PROPERTY_DESCRIPTION.getValue() + propName).getText(); + + assertTrue(propName.equals(actualName), String.format("Property name is not correct. expected:%s ; actual %s", propName, actualName)); + assertTrue(prop.getType().equals(actualType), String.format("Property type is not correct. expected:%s ; actual %s", prop.getType(), actualType)); + assertTrue(prop.getDescription().equals(actualDesciprtion), String.format("Property description is not correct. expected:%s ; actual %s", prop.getDescription(), actualDesciprtion)); + + if (prop.getSchemaDefinition() != null){ + String actualSchema = GeneralUIUtils.getWebElementByTestID(DataTestIdEnum.PropertiesPageEnum.ENTRY_SCHEMA.getValue() + propName).getText(); + assertTrue(prop.getSchemaDefinition().equals(actualSchema), String.format("Property schema is not correct. expected:%s ; actual %s", prop.getSchemaDefinition(), actualSchema)); + } + } + } + + public static void verifyToscaArtifactsInfo(ResourceReqDetails vf, User user){ + String responseAfterDrag = RestCDUtils.getResource(vf, user).getResponse(); + JSONObject jsonResource = (JSONObject) JSONValue.parse(responseAfterDrag); + JSONObject toscaArtifacts = (JSONObject) jsonResource.get("toscaArtifacts"); + + assertEquals(2, toscaArtifacts.size()); + for (Object artifactObj : toscaArtifacts.keySet()){ + JSONObject artifact = (JSONObject) JSONValue.parse(toscaArtifacts.get(artifactObj).toString()); + assertFalse(artifact.get("artifactUUID").toString().isEmpty(), "artifactUUID field is empty"); + assertFalse(artifact.get("artifactChecksum").toString().isEmpty(), "artifactChecksum filed is empty"); + assertFalse(artifact.get("payloadUpdateDate").toString().isEmpty(), "payloadUpdateDate field is empty"); + assertFalse(artifact.get("artifactVersion").toString().equals("0"), "artifactVersion field is 0"); + } + } + + public static void verifyVfInputs(String instanceName, Map instancePropertiesMapFromJson,List propertyRowsFromTable) { + + for (int i = 0 ; i < propertyRowsFromTable.size() ; i++){ + WebElement row = propertyRowsFromTable.get(i); + String propertyNameFromTable = row.findElement(By.xpath(".//*[@data-tests-id='" + "propertyName']")).getText(); + String propertyTypeFromTable = row.findElement(By.xpath(".//*[@data-tests-id='" + "propertyType']")).getText(); + String instanceNameFromTable = row.findElement(By.xpath(".//*[@data-tests-id='" + "instanceName']")).getText(); + String propertySchemaFromTable = row.findElement(By.xpath(".//*[@data-tests-id='" + "propertySchema']")).getText(); + + assertTrue(instancePropertiesMapFromJson.containsKey(propertyNameFromTable), "No property named : " + propertyNameFromTable + "for instance " + instanceName); + String expectedType = instancePropertiesMapFromJson.get(propertyNameFromTable); + assertTrue(expectedType.equals(propertyTypeFromTable.toLowerCase()), propertyNameFromTable + "type is incorrect"); + assertTrue(instanceName.equals(instanceNameFromTable), "Instance name of property named " + propertyNameFromTable + "is incorrect"); + } + } + + public static void verifyOnboardedVnfMetadata(String vspName, Map vspMetadata) { + SetupCDTest.getExtendTest().log(Status.INFO, "Verifying metadata"); + assertTrue(vspName.equals(ResourceGeneralPage.getNameText()), "VSP name is not valid."); + assertTrue(vspMetadata.get("description").equals(ResourceGeneralPage.getDescriptionText()), "VSP description is not valid."); + assertTrue(vspMetadata.get("subCategory").equals(GeneralUIUtils.getSelectedElementFromDropDown(ResourceGeneralPage.getCategoryDataTestsIdAttribute()).getText().toLowerCase().trim()), "VSP category is not valid."); + assertTrue(vspMetadata.get("vendorName").equals(ResourceGeneralPage.getVendorNameText()), "VSP vendor name is not valid."); + assertTrue("1.0".equals(ResourceGeneralPage.getVendorReleaseText()), "VSP version is not valid."); + List tagsList = ResourceGeneralPage.getElementsFromTagsTable(); + assertTrue(tagsList.size() == 1, "VSP tags size is not equal to 1."); + assertTrue(vspName.equals(tagsList.get(0).getText()), "VSP tag is not its name."); + assertTrue(vspMetadata.get("attContact").equals(ResourceGeneralPage.getContactIdText()), "VSP attContact is not valid."); + } + + public static void verifyIsElementDisabled(String elementLocator, String elementName){ + SetupCDTest.getExtendTest().log(Status.INFO, String.format("Checking if %s is disabled", elementName)); + assertTrue(GeneralUIUtils.isElementReadOnly(elementLocator)); + } + + public static void verifyFilesChecksum(File actual, File expected){ + try { + String actualMd5OfFile = FileHandling.getMD5OfFile(actual); + String expectedMd5OfFile = FileHandling.getMD5OfFile(expected); + Assert.assertEquals(expectedMd5OfFile, actualMd5OfFile, "File does not exist"); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + +} diff --git a/ui-ci/src/main/resources/Downloads/CP_WAN.yml b/ui-ci/src/main/resources/Downloads/CP_WAN.yml new file mode 100644 index 0000000000..eeabbb8490 --- /dev/null +++ b/ui-ci/src/main/resources/Downloads/CP_WAN.yml @@ -0,0 +1,23 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 + +node_types: + org.openecomp.resource.cp.WANTedy: derived_from: org.openecomp.resource.cp.CPTedy + properties: + type: + type: string + required: false + requirements: + - virtualLink_in: + capability: tosca.capabilities.network.Linkable relationship: tosca.relationships.network.LinksTo + - virtualLink_out: + capability: tosca.capabilities.network.Linkable relationship: tosca.relationships.network.LinksTo + - virtualLink_in1: + capability: tosca.capabilities.network.Linkable relationship: tosca.relationships.network.LinksTo + - virtualLink_out1: + capability: tosca.capabilities.network.Linkable relationship: tosca.relationships.network.LinksTo + - virtualLink_in2: + capability: tosca.capabilities.network.Linkable relationship: tosca.relationships.network.LinksTo + - virtualLink_out2: + capability: tosca.capabilities.network.Linkable relationship: tosca.relationships.network.LinksTo + - virtualbinding: + capability: tosca.capabilities.network.Bindable relationship: tosca.relationships.network.BindsTo \ No newline at end of file diff --git a/ui-ci/src/main/resources/Downloads/Fortigate02_vFW_VFC.yml b/ui-ci/src/main/resources/Downloads/Fortigate02_vFW_VFC.yml new file mode 100644 index 0000000000..a24d004929 --- /dev/null +++ b/ui-ci/src/main/resources/Downloads/Fortigate02_vFW_VFC.yml @@ -0,0 +1,63 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 + +node_types: + + org.openecomp.resource.vfc.vFW.Fortigate02Tedy: + derived_from: org.openecomp.resource.vfc.vFWTedy + + properties: + att-part-number: + type: string + default: "ATT-FortiGate-VM02" + vendor-name: + type: string + default: “FORTINET” + vendor-model: + type: string + default: "VM02" + vendor-model-description: + type: string + vcpu-default: + type: integer + default: 2 + vcpu-min: + type: integer + default: 1 + vcpu-max: + type: integer + default: 2 + vmemory-default: + default: 4 + type: integer + vmemory-units: + type: string + default: "GB" + vmemory-min: + type: integer + default: 1 + vmemory-max: + type: integer + default: 4 + vdisk-default: + type: integer + default: 20 + vdisk-units: + type: string + default: "GB" + vdisk-min: + type: integer + default: 2 + vdisk-max: + type: integer + default: 20 + vnf-type: + type: string + default: “Advanced FW” + software-version: + type: string + default: “5.2.4” + software-file-name: + type: string + vnf-feature: + type: string + default: “IPS, AntiVirus, URL Filter, APPID” \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/conf/attsdc-packages.yaml b/ui-ci/src/main/resources/ci/conf/attsdc-packages.yaml new file mode 100644 index 0000000000..dcb78eefc1 --- /dev/null +++ b/ui-ci/src/main/resources/ci/conf/attsdc-packages.yaml @@ -0,0 +1,2 @@ +packages: + - org.openecomp.sdc.ci.tests.execute.resourceui \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/conf/attsdc.yaml b/ui-ci/src/main/resources/ci/conf/attsdc.yaml new file mode 100644 index 0000000000..c5ed3db724 --- /dev/null +++ b/ui-ci/src/main/resources/ci/conf/attsdc.yaml @@ -0,0 +1,63 @@ +outputFolder: target +reportName: index.html +catalogBeHost: 127.0.0.1 +catalogFeHost: fehost +esHost: eshost +disributionClientHost: disClient +catalogFePort: 8181 +catalogBePort: 8080 +disributionClientPort: 8181 +esPort: 9200 +neoHost: neoHost +neoPort: 7474 +neoDBusername: neo4j +neoDBpassword: 123456 +url: http://localhost:8285/sdc1 +remoteTestingMachineIP: 0.0.0.0 +remoteTestingMachinePort: 5566 +remoteTesting: false +resourceConfigDir: src/test/resources/CI/tests +componentsConfigDir: src/test/resources/CI/components +importResourceConfigDir: src/test/resources/CI/importResource +importResourceTestsConfigDir: src/test/resources/CI/importResourceTests +errorConfigurationFile: ../catalog-be/src/main/resources/config/error-configuration.yaml +configurationFile: ../catalog-be/src/main/resources/config/configuration.yaml +importTypesConfigDir: src/test/resources/CI/importTypesTest +browser: FireFox +windowsDownloadDirectory: "c:\\apache-ftpserver-1.1.0\\res\\home\\" +systemUnderDebug: false +reportDBhost: dbhost +reportDBport: 27017 + +useBrowserMobProxy: false +captureTraffic: false + +titanPropertiesFile: src/main/resources/ci/conf/titan.properties + +stopOnClassFailure: false + +#List of non-abstract resources to keep during titan cleanup between tests +#Only 1.0 version will be kept +resourcesNotToDelete: + - tosca.nodes.Compute + - tosca.nodes.Database + - tosca.nodes.ObjectStorage + - tosca.nodes.BlockStorage + - tosca.nodes.LoadBalancer + - org.openecomp.resource.cp.Port + - org.openecomp.resource.vl.Network + +#Resource categories to keep (including all their subcategories) +resourceCategoriesNotToDelete: + - Generic + - Network L2-3 + - Network L4+ + - Application L4+ + - Network Connectivity + +#Service categories to keep +serviceCategoriesNotToDelete: + - Mobility + - Network L1-3 + - Network L4 + - VoIP Call Control \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/conf/credentials.yaml b/ui-ci/src/main/resources/ci/conf/credentials.yaml new file mode 100644 index 0000000000..481b12b1e0 --- /dev/null +++ b/ui-ci/src/main/resources/ci/conf/credentials.yaml @@ -0,0 +1,48 @@ + designer: { + username: m08740, + password: 272v!suAL37, + firstname: ASDC, + lastname: VITI + } + admin: { + username: m08741, + password: 863B@rroN27, + firstname: ASDC, + lastname: VITI + } + ops: { + username: m08742, + password: 364K!NDRed63, + firstname: ASDC, + lastname: VITI + } + tester: { + username: m08743, + password: 373m@rBLE28, + firstname: ASDC, + lastname: VITI + } + governor: { + username: m08744, + password: 742M!DDLE44, + firstname: ASDC, + lastname: VITI + } + product_strategist1: { + username: m08745, + password: 824S@Nder35, + firstname: ASDC, + lastname: VITI + } + product_manager1: { + username: m08746, + password: 747ICK!Y99, + firstname: ASDC, + lastname: VITI + } + product_local: { + username: m08747, + password: 623z!Ggy75, + firstname: ASDC, + lastname: VITI + } \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/conf/credentials.yaml_prod b/ui-ci/src/main/resources/ci/conf/credentials.yaml_prod new file mode 100644 index 0000000000..481b12b1e0 --- /dev/null +++ b/ui-ci/src/main/resources/ci/conf/credentials.yaml_prod @@ -0,0 +1,48 @@ + designer: { + username: m08740, + password: 272v!suAL37, + firstname: ASDC, + lastname: VITI + } + admin: { + username: m08741, + password: 863B@rroN27, + firstname: ASDC, + lastname: VITI + } + ops: { + username: m08742, + password: 364K!NDRed63, + firstname: ASDC, + lastname: VITI + } + tester: { + username: m08743, + password: 373m@rBLE28, + firstname: ASDC, + lastname: VITI + } + governor: { + username: m08744, + password: 742M!DDLE44, + firstname: ASDC, + lastname: VITI + } + product_strategist1: { + username: m08745, + password: 824S@Nder35, + firstname: ASDC, + lastname: VITI + } + product_manager1: { + username: m08746, + password: 747ICK!Y99, + firstname: ASDC, + lastname: VITI + } + product_local: { + username: m08747, + password: 623z!Ggy75, + firstname: ASDC, + lastname: VITI + } \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/conf/credentials.yaml_webtest b/ui-ci/src/main/resources/ci/conf/credentials.yaml_webtest new file mode 100644 index 0000000000..ab37f7bee8 --- /dev/null +++ b/ui-ci/src/main/resources/ci/conf/credentials.yaml_webtest @@ -0,0 +1,48 @@ + designer: { + username: cs0008, + password: 123123a, + firstname: ASDC, + lastname: KASPIN + } + admin: { + username: jh0003, + password: 123123a, + firstname: ASDC, + lastname: KASPIN + } + ops: { + username: af0006, + password: 123123a, + firstname: ASDC, + lastname: KASPIN + } + tester: { + username: kb0004, + password: 123123a, + firstname: ASDC, + lastname: KASPIN + } + governor: { + username: ah0002, + password: 123123a, + firstname: ASDC, + lastname: KASPIN + } + product_strategist: { + username: m99126, + password: 1910-FruitGum, + firstname: ASDC, + lastname: KASPIN + } + product_manager: { + username: m99127, + password: 747-Airplane, + firstname: ASDC, + lastname: KASPIN + } + product_local: { + username: pm0001, + password: 123123a, + firstname: ASDC, + lastname: KASPIN + } \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/conf/extent-config.xml b/ui-ci/src/main/resources/ci/conf/extent-config.xml new file mode 100644 index 0000000000..ab04b2678a --- /dev/null +++ b/ui-ci/src/main/resources/ci/conf/extent-config.xml @@ -0,0 +1,51 @@ + + + + + + standard + + + + UTF-8 + + + + https + + + ASDC Automation Report + + + ASDC Automation Report + + + + + + + yyyy-MM-dd + + + + HH:mm:ss + + + + "); + $('.logo-content' ).remove(); + $('.charts div:nth-child(2)').remove(); + }); + ]]> + + + + + + + + \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/conf/log4j.properties b/ui-ci/src/main/resources/ci/conf/log4j.properties new file mode 100644 index 0000000000..3e159ec8df --- /dev/null +++ b/ui-ci/src/main/resources/ci/conf/log4j.properties @@ -0,0 +1,34 @@ +# Define the root logger with appender file +log4j.rootLogger = DEBUG, FILE, stdout + +# Define the file appender +log4j.appender.FILE=org.apache.log4j.RollingFileAppender +log4j.appender.FILE.File=${targetlog}logs/ci-log.out + +# Define the layout for file appender +log4j.appender.FILE.layout=org.apache.log4j.PatternLayout +log4j.appender.FILE.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p [%10c] : %m%n + +# Set the maximum file size before rollover +log4j.appender.FILE.maxFileSize=5MB + +# Set the the backup index +log4j.appender.FILE.maxBackupIndex=10 + + +############################################################# + +# Direct log messages to stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %10c:%L - %m%n + +log4j.logger.org.apache.cassandra.service.StorageProxy=DEBUG +log4j.logger.com.thinkaurelius.titan.diskstorage.cassandra.CassandraTransaction=INFO, FILE, stdout + +log4j.logger.org.openecomp.sdc.ci.tests.utils=TRACE, FILE, stdout +log4j.additivity.org.openecomp.sdc.ci.tests.utils=false + + diff --git a/ui-ci/src/main/resources/ci/conf/titan.properties b/ui-ci/src/main/resources/ci/conf/titan.properties new file mode 100644 index 0000000000..94d12cfba0 --- /dev/null +++ b/ui-ci/src/main/resources/ci/conf/titan.properties @@ -0,0 +1,7 @@ +storage.backend=cassandra +storage.hostname=cassandrahost +storage.port=9160 + +cache.db-cache-clean-wait = 20 +cache.db-cache-time = 180000 +cache.db-cache-size = 0.5 \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/drivers/chromedriver.exe b/ui-ci/src/main/resources/ci/drivers/chromedriver.exe new file mode 100644 index 0000000000000000000000000000000000000000..97464543e73f9e52f64a802ce7b09d96590f9e39 GIT binary patch literal 7442432 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

p^`r^Iaia*uI>WcSP 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

fsima+# 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

X+Y$t-~pfKs>M3 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 z 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

gz}wzWN2OLmAB+6|}x4(Um)5x7g(d#McQSOuk+x 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�R!zbUzCL1!$*T5YyZCg?#BJW}Jl85(ieFx{CeT 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 rYvZbc`JlGP7vYW?LSu7J7?HW$Z94~}sG#2b2g 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 ri%wJCQ+v?=o< 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

pzv%q6!$Ip-- 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/w(OxEEzsefpM&oxlB4qxfMm*p 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

GSxBI76 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%0D#69O9?*F`XTD+Kh4B z@hI*Q{i7#Myau`a>c zS^zxPbwkx9C|5hdz&%r)D{vEY0>Awcdt?&{)gvl!1Rio;up6Q>Rfj2r@zY2e{haOw z`+9(Lkq-%86)e}FJR;i8L9Mk~o=AaT>A0ZSj{pJPuC$50n?vj?{yDZo)c#QWTlvdO z#)a(PWRqhtRr-s`@%>?|zqz3%UCzeU#r-L5y@PC3?4XZ|MoW)d&9ruE0KdhgKU)&& z#IaJBOX(k>t3&!r^tecia_JulpnX_y4Q)m60!X$3N!Hs z2g_8#NCL5sh9$+q5RE@6$nxSbrLfcIV#>ivYt_p(rp!skl>c9B9Yhg~S`Q*`+x@pY zpRfu9L0%Mg95@F%!Z&>&cI;1q9S1aaY;TKV#~h6vm!!syie6RHdw?$%e+7TM@ zxdA>uvFzK90jh-jmWQ8GPqc%88}%fiELQwVIS6p{Xh;;4WTuSz2ds6EGd69-!B1-& z52w;L#>T511{g2i0^&Cy+ZGZHS#z;%ZO?%c>Hj&-1FU}8uugwU4}$p9s2jmcS}S

H{J4LNN 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

O|u5}tFF3JWSzR|-G?%&ZV}6h z<5V4{qOO?Kut*mnZN7sK>uMt#bsN^}4>=U18mp79CAoiN7m*U%IbDh>$!uhy8k{OQ zkXiCM1556cw%i|?C`kF5fk-)(pcWSzr2ICvoX${iZn*n`rCD3}+r!`6{1s1Jnl+QZ z#r!?P-$DKcPg&;dQ2?@ z7&I{XB8PP1)nb3)AcisrF{E+Kx>IE6`GU0-4ms7?xrT%`+mYkMY;8+`0H`%O)4jczlCG(pJCiw%l*Q|#PXfqtU&NRd{m>lTcr1Mody4jeiDC# zuH1$3u!BX7+k~f+)$lb#`!sx!K5M=JyotzsPGxBh`VT3BR1B462!w0V8kzjx#FtcS zbm7H9*1#X+Wu*HsTw>JETQqm0C9D?eEIyq>>_lG>UJYu3XaH0bJSHMFW#&Ie=Pz;_ z3n0?oT0*?NtDc8lK-4yvi3!j83j9GVgj+I#V(bw{h9m|?FcNW-nJJ;YuLo8#OeVO| zwZe$r#p6#UO|w+6$8O0^tjLD^8z0&7-lnX`FBq1H_kHe!D^QnyR)a>FHFh)V`tggp zDI&hQobVm@>Dy4bVZGm{j#Hnc{mb?JM}evDR9)X2>H73-s=nUi)F)~Ga(!nw_5Jce z>EEGrefl<4U)Jr%j;Eyk%k}+kr0L&OLfT((yl?}}#R>(LUMzn{C?;dsENFXvQ-rL6N@O)>8j2wlI*lGfi?Z#iP4t{3D zNS-XU9j6iQLmI=H`rcJnQyglR%|!(L50}eFGgiBWQAlOxil(a9dt80;x$4zd?IeUm*3Q{Kwta zLz?aTZL9(=Bf?wcyGUZ4kZ{AP1%ZHkw(H2->motktEk#8*rCQjGEs7-zBz%gYU{LhztP%eqgU0gVhR$L3`x{ps&1zT~5f}4n$!mP9QMxAB6lt#}X6w2#(sjF#pX6?h=(M zw4Efh0CwBzn&&79oVP*n>=V6u1P{}0f>b)Vwx$lz9|8>%R!rT%vSgzF<#?5qG}(z) zxkv(tjdNo{o&aqF61uDT(pBfdz+*pq1jsKx&LH+h@we@bBhhnox2F8N;Woir!d}5> zY1L=dVDP%rOsOClW_FjkbYuZvs6ok7Yp^rBEx2E9)i*YyTC{4H6%7zoSWF7lA4Lu( zUX8`L#5ii*g`?JN_1g1-r|{C6YQy7ScG?i#JMNXXpkO`fIN;S6Wu62Dk|;P3hc&&p z9KKa{*Tz+yIK~vmm&xdUU2i4zW>m_A*t_uXo~`Psw~~tE3;gUBL$Db;pgsdQk^}p+ z1L{IfUu@s2dRI?kUhM_FiLx!ovUwv*N+RA@_auC4%5iQUyqf2ou=Qw}r4EUZH#4&g)hTQuT`sM^f%V9c6V@6mA#i>1TJQKNkb%IVlh zI;Ig?|0$w8luoMvcCM`xl+lRZTFnS8YL#R~`WqdvpyM%mCO%$Fl6|uCJT%}%L2kPUr7_xE_6}oJI8R^}4aj>}-EBj_L@owi=)v0o;RmDkWi*5)2asg~F9 zdz$kyWE5&GX9-1>)7J7jSy28(zS5ZA89Uf$w;J+FD67`|PTf3HNREWdBhR?uYmny%b-Bl$fa)aWh@`1ge@A_vKq7JC5a3{n$Z~ak9T^;6pY|1O!CZ|xghu!Ke z%(IjDe)zp!7-f&^9ki%FN$T#PgH_S5|8mS5!LFfuY?DR0fL@PL?CnMM^#E$K)(=P7`X5m?Lg#6jojk1Q==RXjt z5fBn;2;cT+hP*X1S%GSa_&LER-cHnLP&qriJsS_4Tj$_Y57>GZ0J2|h>GI~hOdhU> zw-0JKOMC~j$l8GmeIsxv3rChmPK$=L{LaJMJq_dRV2?gVnXD{|bkW?a3_;1i;EoGV%Gd@W-huXUQ+8XBG@%icX+ zazDJ~Eqc41JKaiyH*0O}EG?5#FpbpnUnD48LNKCoz6`T$XiJ&rIzc8_q%!d1H)NVrtF<;1P<5+Tjf1bl({|N8?n z$_W5llZ*n5NZ^|~pCfzKgtYWW=+Tav+LpHp?UxAQ8+b7~)*$0R2d|>18TM76BRYJR z+RwndyEiX|$gtM_nncK?JfuGCvZEI|+j{&mPsWyRZH|KD{hG|$OsFAb+;2l;JROgE zb!{CG5!Pn(hTGTxpsO@a=X-|LDbG+6nhJr~dQ%u!h6aJI5O$oQJ#w}SnIUC5l!w00 z?^zUImZCcrO1YFuyR-UJ9E``!Os)Oy+UFV;h$YAY0^l{S&dX}J90V4yw$6ZJ!l`(> zgSlnnkPYiuoQvnk4=o{HamJ6k6F3`%e4uv*JflkW8Reu;eQAKx>zDTYRv-rr)dg!> z^iFa=8vY;>yWORN+oqVEA?>4=I%6*^=Eg=)C6G(d=l1^T8$9^6F5%+KO}T;77lP z6{oiD3-@*`0*L`e$hCU*PQhCT= zomZc%p4yM8=Tvy-{p*?Q*7FXMf9I7u1NGz8oEh%^Q~indj|bBGM;iyDWb!+0<;CVw zVlHFlVzwx={y19wKqk1B@Cv(=<(_(v_{J>%8T}9Wb3&emLF)?<@|EX={M=5oXZT|+ zgK}ng8V27SJi0zxKj%2l$@ST>kjDY_A8f;70k4UYVZt|LfgI?Wkw*LWMN*S$5hVkc1w6AWt)`};x)*+n;E#Ml<>)GIZ(S5|C1cmVF7xqCyc z%x2@M#-ZpNTI^Zf36>ZXFQqs<7JdhUIIyE(6pXAAJ|HotN7d`ZXcvu=Z4dt1C7$@0 zgzvY6ZVv0zW@NTo(uUO2rf!qi)|5$sz^_p|)%wWas-LJSiI={AYPwg9W- zQX60FIMzp&fyqRj(MpKylA>TWqRQ~SjWjcgzej`@1@;V-;Z&(eNoN!hE1idBoU-j1 z#fjhn9=3w$?HMHmCFS9WaO{KdkRG5Zgra8G$2*aDgu8=NEKxF=H_ed8jb^mTJH2o_y{oA0Fa7W4A;3sXO*&DLc0i}AG6BZw;@HkI7!Qc#s!QN>aD{v1k_P%p{la`+Wk%S3 z&wkn-aMd-^+iWXtwaEAf z{o3t1tl`60AH}Qvb!(r7D4obj;=RKygBpf3uE@^9IBNHx!z~_p8l;~*hg-bzl%turx+_zK3ks!r= zJ5?MBQrx#w#rf@%?9;5R@L_fk>kGk`5$Lg5#J zZog+ukwx&PH_&cPA;e*?K8f(yYfTaUCr6Jry_4qn7Fko~_|B|8#8g-N^Q-%qYGzzc z9{r)o$kRnC?5&OU4zX@}fn|&SZ0Em={;bytz5@G1m`3uoJ*QC8?V%bIP^Kh`9vG)T zH2&0M%$cBW;!>Iyqzdq>se%r*m=fs*+e`mkWFaH|0YHsios{P${8|#)+zR})YW~1a z(ID%(*ZsmDRss3qj*NtQNmv`{0d?1ZE#f^B%}Hb6(jF*dB{H|L23-Bw7OpJqEi5SaHtv*9>wJJ$*kXij~ z$n|>5@ZS=dPm2@P+tlloxp;u?ZEVPwr#WT05U#xuEfZa9%7IcX=G{z)-F9{RQ+ZiG z^`a-n{)%h8Gp9PDX?bcJEHC7r%6HOJIPjSI8=d<9yugJSP^>~_cl~`nmKrduXDnFVM1d-Aw!}@#_Bn(B4`!?jt_yqJ=8#v>*jK`iAiX z9mobA*b^PB?PbJ?)l`;0{xa517BXNa{Fmj#B(|C!r)#KSG>swo<_h11RX(d}B=?gC zEkD^%xhF$m_uwHZ&?628P^=}ifiJ8^qD3=lPFl&C>tgAj#UY^Wx{BtZ#Gh$Nx>(^e^$YkL(k1ce|NMmZdg z<=!i;wzgMW+n3wgimep1+9p7gfE1!~TTpDN(st9NH7dnmQ|A4xz0XW0A-28m`@Hx0 zp6BzC$vOM%KWp#3_S$Q&wf0&I(X#Q&&HV+t^-t=EGu~BCX0x0y__Z+jZOshH+WMwW zN|&Vc*36u~B)=s2TQf%`ldK=HKT3S(A21mrM7>RZ`WrJnA=z8Q786r{J?iSKpG|u~ zlDe&J=kj`yTWP6X42pBUtZY+z`iUp0P?wyX9{s?4Iw58oPY67%;keW`iQ)e=L?-O;HP(DUOCMxYwDAaoh465e_O+6q_S(MERV`0$*XL*TX{xZMP+7S z(mT)51xyV>hS4{k9lAkQmKkLkUt#!bYt%ig4z>&0z?*|->BX8RD+_9|pBw%Bz2q?T zn!o28XW{dYTH|-G$gpZ(Cv9l(9wd0L-~ybmsXBap7cg>93plY8Bw`Z@xHl zN`6?eN{a0FiiA?X+%8`Zd0(Eri+enX`gLHwm-r9DKKXCJo?fFwpPB+Y9$2Ff z!TYp}9#MzAAGS0@J-`JW2(r_I4I`$=SrcBxNEH3hnlcGgP+EeElL@En(uxVq?yO+z zv>{{tCHA#;6@(-}tjE=VG<*Ms8=%9U4dNA;4Ksk^?eE&98O}a?k{Zg5SO(PdGY6{h z;<@&V<9QRyp}lc&BGq(SLfJ#?;So{X>ft1&|mo0Qo8xmv>3|5!79My*UnJD}|)C+szk+|l{N=ec{szdig5(E}5F z=vb1Z$$L(`@7?St;Okt!HSP@&N?IG=pm9=41J<}^ld{)K2_{o^n3SrJHSSfD=UXP_ z_H1k1ag!n@8&XeBveY`0a^EuYIJvwzG`I zKt#Pbe&{j64=fwbTc-BsIKE}s+1a%|O%#$6&oNrN5%)bG7b+JWw-X$}Q645+>abib z2@~QzfHdgtpsM2w)5T)&eDV5y#UB^yTEDOO<3iBucRic_$@Ytzn~vo+HBan(-YFr< za7NQHkzYl>D>H2{0<7(CO{U?mcIM(R`wc604kU$LzIdpH=yG;!3?M^`v7+7(KDRY| zo&aH|E!2=|tzq#{fdX=?bN+6zXeZM;Uo9RgKqZn7>g4p!A0vl{Z@3nMemV8&R5ph5 z(xg^cB7a0U3N$<_ry$F>aOXsNZA`B25&v#?P^PIRJ6Q}#GQ}i_$h4w~HgRzD(O39p11|S^ zcX@`^yJirbmGG6l_7FssO>F_3c2zS!wW{{M9ADx4uD=)~n~2(bzpS?$cWTBWreGm+ zpu3UWuc!p)w}>Y|6>l2~iQ_>q?1*ed`vir|R@7oW_!%aJgbJ9%`O|S(ZL(P7`Bd(G z%9BrEV9F=af=MYn4$hwrc~AK?-1`KtIe$7tKIPLXIxnU252mRl-KXmMz2&+O6rQ0()z^Il*N)VDK+I*NlER}iYbzk+VBc7 zBd8dgT1pi972+w_I9u(5e?|XAYUmlkw;S*uAB^X_o0l)+5*J)|PeydePR*b zbA$?L6E!?5vrN+MG@%Wf?jCN;gUIy;vdYo!F%5DNX z5EHLDPyU`n`lTNDyu>1@UqW{7FjVJpOqtbAHM2UbA3b=Kz0iqv6LFn(3ww|`ThHv` zFJkRtr}1QATLk%ZVJq~s3xDR+6cPB|L5YkfRP~8(r2Fhud7OUi<+(Fm({p!TJsrxYhjC2n1II)vf$x!!|;U z#LcT4$LrBby?I4>EkDNsMglbin|ksay?CFw3A8xO^^GYQUhN+T@9N!6x!MaXYnrte z5+yuTZ7Hq^TQud(phm_jBi*kp{D>uR(Wa~@6I zPE(8$BC-+O3aMcezCx5qJt(}WQG$yRvGrd}CUe7Xw^V|?U8G)nQcbW#^sfqnc6uWw zqYWXuv6o|C0myynvuT|8hVhgwX5w?Gy)`SHC>G}UvN4Mj--pT9J_<>Fg68*R$L|T? zT(&(vyQm)zgJKMz&*LkeX5%pWfqvr6{Y$e|?3zU13fg2u`t0zG?6O2SFA}wN%s2C3 zU3Rx+${+c!e{Gr`Ry~=^$K-kbBFXtpNqRyay>oLBJ-vdXt|WO!T{<3D+ILZ=q^5TU z;kR`eecBx=O|l-((YuOV1g7JNxsyj-Jt%s7g-e8xs$ahVCl7+K#0g|V?jn8MMY_{V zzumE*kDRHf^fFnbY0`Q7-jIE7V3B=K5TWj|Rm*(bVUsqOaor>ZGZm7Jo; z1usTG$6#B!uI*+7J0bh#P#gT)hGjmia%9xF`@B1G2j7-aiMwf|=C4PG`4)grCmZMv5 zKnEO9@5yDI(FP>;WBls|-CO*9$T>@l_?+4xL`Y2j*m+Ss&#bU(^6awwwlX8_FVoWg zwzA36=eDvE^Jkj;QU7|VSKKVRWjOQyMOndwy=`Sh=DV=|zJ~&>Wf7lSHlwxdR^N4d z9}H-+Ht+}|gCSu|&WWJRmi6y9$M=NNKns?ouWAZi1wQpLnvJiRtiG{=&0%J?Ss!Nw zDG{Bvgc@JH6}Yuz+SF*qzb#8w`3_)8mA`z=R5|M(s`6^8>@OU@;OevXiNt(ApAS{g zY^P9!rsnke_xh0}4}Wnc$w{TgDVwx44e>$Qv}&f%txGFjSh8je)8@21*7R0J#;%s0 zbhLkEB`wF&!Me%n8X$&#NPH~*CxX<%Y4hyK8w?|;DSTSIpV2k9)VL`#$z3E3eHIPv z4Gq)Q40p;Wd)Co@{IX74{m#bn8E(T2*teUUk+D~!SL<%b#h7GQ+(dom&i>0_rZ@DMOUF zZ~cOB=nNGiWrnJ+_F;+I-SSD!zJ~%2U10jC*N4-BI}vca)+s_|ToQ2o4?2grvWKR$ zGaVMB{0P`T%G{5TWhWu47#DLPa9Nkwc?b?(f`8|Ft-3Hc$npXhS(Ea|*pBp@JbF~) z-ZM#j{YLY3H#R@-!5_fj4fyxU=nymf*$V{z_NL#Qaat0nofr?jzH8U6xfSQRV&CX| zsz7#G|mm#GXtK|{}T26uN z0m(!THam-uOl(WDZ_d%BH6-Q-{L~`11)j`}cR7#9eFrFC23YYh`sLaGE@Y7EwL5pHa}gX@1VJ0W!sQvAdmP(a9Dy5D=w_d004$aoDSQ1}Rr`dXrphaAcP8_Y? zzHIOa^42f&sZWFP92C8dd;M)9ro-wE&ox{byKGJ!y2=`LfR4eNO~9|RH_4{HAm(JOzYVe!rBZ8?aXQZN4mXVdrc*p?O^s~jUMHd-~lEt1~{M!9lt7jFr zExU!w6kMGOpZ?$-NcroJ6}Lnuk#%BK9OLH0!o$2#e-*$#mX|o|jDnI2N3P+oMOQrn z*l~PJ>J8L%Vs37B@1A?MkjzBgDbPm z^}xzLR1G&=tL}hCQ~v?gDPpcx@r%RBmiIUM-WM*Kz@^;X=C?mS>-qhpo?rGB=69T) z-vU})k!SMO7pTMwUyU{amU6*~m-*t2wfs3Tum3xtRSQc4AN&(nGT(FBW2aV+1iAOt4^1M4@GqcV zf=2e`uXR3jx?}Ox76lMDNRRx*zpR%)o%iOXJFU_D=MjxblwDKta9#0vvPxRW`3rLH zby{$Ml>(jFALhuZ3PN94gV|?}^-N86A>y#0dz5AP+OdpX8CiY1F8xJPynwSXWHFnS z5o|i+Uww^R>)l7U#(%nJ#Wno)t|+m_U$o+S9{no{p@VMOUz>J?irZHoEq-^+P-}ed z7guDK79Uvs=VC&0hoa{nnYOJLlDNC6C8M(o?ymFqrJcuN{IZU)&uSgD|BJ|{=YO%6 z-)UbYuL&v_@^6rY4J6M+=Um4nUX)%7vX6wbAws}g%YpdGT$W#t(1CdU97s07+1Pf9 zYTAZO9>dwErnNVoj8LMb9t`oNPB{~cGC88Yv{i=%$0bmP!0Ub8&+zQk7=Z6FHfsnO`L8}VrT_mc z+5a}e7qNCZ;`SiL`aJcnLw|ug2)_XD-s;7kLK>$Y6>l$$$hra-U5*gkYt-9Orsj z+Yo_@*+Vn%X{}K#qdMk#|&E?iNnO{PUoG-v1dSDj;NB1gbu zg2^bLUur-T@XXuYU z5i{t5m&O&|MA7X6bYSmR9;BAZgi82%814x>k7@RXQl7ntY zmxyGK=9n=^mG`7{>HDmf!Mn7FNYu6JYo@rVQ+g$JZZL_mlYAt6Wr$gXvd~|P{S`~+ zh-&$!EFwR?V+I?;YTe*iQ@2P~zOk!Ub8`fOrZbDA^6yKb%ObljMQn`m1e(e@_tl*llc<^^tr#CANe=Z0mQQ<42UP5t&g$}(cFBB zQJ}$Zh}8)S{-Af^oHcao(x7_d0^Jh^b(F*$z7{cjF8m1WnTf-v<+P0f&g14F$FfVV z-}jZ&yx-K2@P#F|c$xtGmvJK`#7UxxT_~m_X+}yxpvn>2_|XV~2Z(?fFSckPI$z}L zC=zk|xn!PzNmvs<7x?ZGT5`1MIzZAD>TcBI84H^sy>#0Xp2jO%a&e7Ouqp zAeLzdoF4V8)CB$6?Hrg8SKmy$q3u{sJyJ_^{pB#5uz>h6m>?r`z@tT!UY^L0MCgFM z#;-n;NHB!g`(>_k0RA$8%-erIfh5udpj*MwNw!5d;%BPPmHiZ7jhwdI?1o@6a2U4E zK3D+ZV;2g)W#l=+!AA4wbZfQ;thN5HWCSO6>VvknrkA0yVqzJ{@t|pvuRaVj@JOOW z{Ro^mVGmVBp|?3a8CxoP8*lKd>p(*A0U6ynTBD?d+JBw zrc^YViu{9NMh8QX80W+!f?rOST)D!B2F52fAv=NxkZijm+Yorse4|j59NiKu62DN9 z+z56#wRxJ=PUStMPSJgdGB`Wl5RmhWRIYP+8J*H#zasH_{A%mhHR06h=(Dii>C2+u zu@$O6huMw#o0@~>9&G}Cy*Q(3yOB`!l}~9x>fi7msr847OM{r|dQHgp9Me9sq%Dc$ zMD_cfDnDi}5--aXG4#M0o`KK>dZ)gRE-#YRC3Sax z3B{scK$P~Xf`wHfZk1HatrCotoaxzw$K$*J8MvWF?wfs3*iyK=Nd=4BxS-;e25T~Q z%l#+ylbRe~n%w#bIu}paTX-h=D!ixmv5IiZ*#$S%r#UuVrakd99&}C%RT_dFG=SI* zxGXk#1)gwFvs=!rP(}+1km6k{&T)20)UhBDI%h22em z3Ksv$n({sr3j=gO+!d)(mjIyVmxCDxh_qMys};hP7ye3uX2D=-(f}9tywR}&ZCXP% zO{A5}9Xf$X;L$43k)jclKA-zFnQf?ZKsz5E&_U^+n9FJxK~62lzfj>W5pm1q9e@sD znO&2yuPUM*z=Z|%q=CoUSF5Rr@^V=R4!APDG_A@YxGCJewe`EZ;;jdv2l&!xuD=3(`Qv)sKp{CFFWfD= z#G7ByN!~U=d@Zk-K^}g+1Io69kWr5}{0kBm9N+aU8-!{!j_=(q zhCMVCQS)>*5+NZ>*13vM0g>=dny$2ha261Hhn=G7cW`!2@<3LzMT4kSPas)mx5VjWtW&Dt_ ztv@Wg_1{AA0^LZO2gj^H+M=K_i@picSy<{P>^3CyeV&SUL+^xt5`z0m6|_Y99E9Yh z-R&>@6^%xRCmr4ewEbo{@DpuV^DC?TeK@s<`fx7Nxx?;Et}6#KUY5$->R_9QT70wZ zYQK%$R0B1qE%%GLjiziNI|npbB!1jQ9~pXD7YNtvp#JH>dZ-JIqC$ zFMvGKR?2lE*)P_01&|f=HOX-kdM+;XY_|vLVJ&zzZKsbs*k7zWBMx&V2OKOe)f$ZYi@`agXT@#r@FK^_$j)rh6DKVM=7YAXLoB45f{ zkXFc#s3WZnxy#y{qUTaJ^Kp#vJFzQmp3qDkxMH?TgHFr3+k-ObnqI9fNe-eej}My4 zKuY0Esu9!s(DaE`?W@-K4j5bG!uLoR+l_?1wMkrilTQ4g6rFz&=A?7AW0WWoF>QLe z0+UqjJ~|xK`TB-NKhZwR1YoW4<^C07S&TEw3s2yjNI+aisAW1P8VjtQo70^G;IH~C z@wh`c6mkyeF;ciu)hY13Udoq9v38*BBLB_id6>h6>-)tlYAy*}6*6cf{qGVfEE|C} zzRbT2Lr>Y8KynG_cFkkB7u->X58dvF+9u(&c9ad{#jENkL|g-wvH-~1ZGic)m*nqD zY9|T%GP1DP$ezWV;#f65jS}IW4dFBD0&eHA<)khoZ=8S+ObC^7okb>s$LWC;!@OhU z5e)t~#UE7^k2}XUbTw2QKCn~Ydrx(c#k89E9_ZO_YS+@zqKK*f>AKH=r}6upQjEOeRwlQo5v-KOqD7rP*_je-IpH4zBClQd8(i@F&TGf^ zCspUC(HxI7B0gOE)7|@1-^IEMc!@fy;jNUj(4~EV-8Z5?2!aE0J(@OuGnzKz_n+6U zVb)FdtylUlJ)S5%zDRofDaL_a;(GSPwzQtB%eA(H>V_N^>yMB==R4*3Zsp;oV-~g<6w%HOICkLSf&zze=xm2^27N4|E)daO zI3M1^ioFDdXlg9rSS(LB;I=LH91oP|jI^=j`ex-P^4|I!C04gc8V!ayxbp z>atpOA!>3=%BUL4ungP@9@ZTUAGIrUiw{~&W1z0i0&w`%%^)*&ySaky?ZAqBzNM+v zUo9&c0uT!CCk3ze!`aHB{4eeqIwI;yu5?iPhQ{1wKXJmxaPoZ@N!IKjPE@g+i>^TZEZrB^Uv0a>WR5rWeeC?+LHxT>X@S_p+Fo3%k$D=>H@!b~6+pmqYfqKw2|u7JE-({bmhY4? z;n_>mnDQ#F^}&a~gB!;VxGIRH6U~PMNlbsY?)*tHeYT_dDx01+HRgd!q5Ao9fYUb7 zUmr&5o*)+Ge1p7(#I&5T?2cZ@OQnJq4i&du{5@a(cFImClsgob>k$%{KpsM2x!a(p z5o3+u#!`bsG*N#(_dWhRL@w?e#(y2cI^l_jgE2+2y23~CZw`7fiP%YI!lsfD1&KUy3_Ta|UcoGV6yyYjjgMVc1V5EJUL1C+ohkWi zS6=O_AG&sBA#Q1P*j}_#Z$Nn0zX5s1waSK3oD%2NXOdOxtzeqaTUB9YlASD#%X>mk z3@^=*7|m7)cR0y6Z-NBgnfVEOFaxzQ3sbK=F4luZYOnq~S+($2+}6UlIjveTw)Unz zz`gnye@{N4N_TRbp`qmO4#%jOdN`{3#$!*-QXGYZjCliRw(?5^Z*!r&Z~ltIz^s7Y z=+S9%8cQ>V90@j4w~unIA@FzGeX>%w3q>_8bF^Smi#!H)s=V`V>A_zyUTtDewG$-BXh7B(vu-`qVQ?@itgDkqH#!#AbqqpqDdOt&SqEj*C4>?2Zvg~L>vUEXT=~?+) zE;-c_tPi2q@(a$>GJ+sD_N=wPNoRS@^Dp98xX?%lvX;R^1te_lYivX%_~dE%KsKpY zH2cgFFXI;4aHO7SWxa}|V(D7qJwa*AU)?_@2qwL4h)@@Ikv~bu?+*>2E+INP=u($f z6VydZpA$SA^C6P&HPzTjP2zkeqTI4jyuQ81nbzJ5X_(0|RFa$-?LEZ@ms#$ElZRsK z*1kN`o>|m+PL-rP?We0l<7H z@jhe^{BV``A%Eb9Vcv&{eIGVYprIN3yOV!w_?H+K51tfOOc$=N6P9_hu*`Y^c8s0*_!LzhgWd^HyoMQ`Su zW;IBL;o(j46S5w-84iw&A};nOWO?4<7rfB7c= z<8t(t5u<$8Pp4k+=7N*raP*|-a8&a&n{ZE>(Vd$65|bM%cs!K$6=(~02!h+uL+@K- z+cVm&9aBRYt#;*MI2xWuWVEck3GU`t{cUdekX#s$;MlKNX~b#S592LHr*M>b|EN}- zvwS|zRjaJgYo$sTA9DxcmSBSa6-HFboxaGFtA88GypilY(tDv6r(_ed{E%~?%AJ*? zMi3AKJ5w&@=R}-VuJJ|GO;x(?(QdRW(cEg&T#yhK(!Lr?BjVSEQ04Q~r;^ns&{6oA zq<*&q{1tuhL#HofYZ^RY7Wp9=ZCQQ}H|pTbK7+*BgBKdC{;LMhs$n93l}KZ!r;Q(+HA$I=l$Z&RB5P`Y%dRU>_=ru3)DKh_P{+tt!8c6TnK` zFU$Cr>ONLWzKiK&eWo@^gau=HrrV*N9ov>kDf}ux3G=Zv#Djds7+&3qU*@Si5b;&o3x#wXLWT%WK42{nx8fMwLbTk7iq}`;(o4c zHaiWITmE!G)9*4igwJa_lTJ8=y+o7OW>KD}}ReKB-xM+bBGmcCej-mX_py#L*idl$d| zU5w3=B}{&1lp_sS+H}^`9DLUdWJorJMcS!U%Iz_uFVxqnI4FiZA?1P-*OSpSLV1QS z2M#Tlo2~ViV?`ZdZ6s|p)jSw*_);iM7QtA=UN4>=oeb9pxy3#Kxm_VlX<4=!@ymD| zM13894Zo00$d40|1FDzj2*gpHy7L#FPXI4>YypSwFdZRLkis zg6QqF=Iv#l;qV%gO6ppyf_AA(X0e1_rcR&jbk)nY!7L81#E0Zb-I_C}M~n3P%|}yL zQQv;X;GsN(y)Bx@?g>ozIgYVD;Q^&_PLF?{^ePp`6`2EJG}I7~Dv`i+6Z;L} zkPIEd5S;R#lxDqnc#_(yj>EH)JA8~y_?o*L9~RHx)~!EdH)bwE;p55I4r}}?E6!os zt%7}4fpj{o_!%SO2r|+CL#7;TJ8=e>zE_fE+wt%tWp`TzNAx5oT#q2Cn7f~>FE1O7 zr-)@28Ja3{&x(~V!_j~0rD~+x{pOqL#lU0DRkOsX=aqM4Y|3ScEDwsenZio0yX*-y zwT9S4qQ74_FLm{L>rZ?!YFi;zX;7V>p-ZITdu|^-8NrCO1lrr-;EK@Lf3x-5($0( zf64g)sYBOQhO1#1#^Pvb^;TgEw4!FrNrR?|^;kilg)M7Zlapb^9%OFC?^~J!8tLVa zp-SOQ6chRYy#nbQ!lE93eh~O8lQR_AJ^F#ZK#%|5p1<>E{dec@$jpKBC-;v+ z%op0shvjYnEoLX^lXm8*XACqIRx{xX{|7@x`38Ey7w@KFCR8SKK=!7T?5y0R-+U1w zh%`9hR0Px+?z_QUTHZ~?Xs^)m2zLB-~P-obDKv++`tNPD)0C&F`?iR-T)hy{B+%<7T z63|M|&PdO&m65SXP1-pxPEx*jE#zwlZ+Fv-;&+7=7yKLZI zjL`&4++y25v%DDaHZ7%}!Z;hD;DG*p{-wX)Ke?*%5A^T7%zwOpc$oXU{TtoCe<81b zrhB&kVbi<2`t>eBUzh^Wuhv-^fKV75toGu=AzU%@^Zo#Yx=zF2KMI4)&-*F!lfcz1 zfq#ykAFOdMEF3ZbaSs=FEWZTPA7^)At-r8b=4Tjav^1@nU0(acE`!2Yo4x?_Cd^WT z!s_|?AEti==l(tV_f9JP)5KV8Zi}IIT1uLU(4q6<+6Z^qRUxuc=fT_9Xq}(j!LP_8 zijm5kDxI8GU#j_lQo}`axl-1jKi0#!${gH}Z$SXY9sq*`UR-XP1iZNux2CNYFz3%kKW8#|TySZcF3+hu*v4|Hh{7heDjBB{&R@ zxQ`Qj5iAYEB?df%KK^F-xDcG%(`7*(7lLyZBEJRk!Vr4kEQiv!g;Ah)4&qx|3bB^%M5@X-^qRb6=Y+lMbo!-<;Q&W z*%AQJ4B2K=0=X34Nb{01#*2IL8lc%nk}NCs0MrY;oyr&~lIwi63fVRC&&Af7W|;|s zxjJ)BR&bYU`jj#WLd~dJ^O_@CL)S$Dkudg<081of`wP3gXXGYdX!V|ZWc>BC4uf~q z!5R&Sf9%wq0z@~wM{Eloj`!lT$cimz-IIk2YDgX0lDQK6#ch54myN74n^DN&+JNlb zcI8t|#Hg|tJP{pfZqsT6dcah&d+nNOK5Vg92D5Poz*E%sFl=`BNVNpH0a+VXuGyirL~YSMbZ5k_-ax zEqIOt)+dmeS01w~_qdhMRmG!EK_F17Vsb%X?jAY0K|84YxY+Sn>z|VQsg*mO1<%2K zKu@lBCcOaB@nNi4yw94oulRLq*6R-Dz$L+q*D_iPi68bv;a?)NYid>3<>HmfT7SE) zg2ik&$hS`z^fv1mriNJ!E)|VqNs+J?oEZeedLr`Mt6Di<@J%mO>()#;ADBTVi==ZP zll3;>6CUBUAx9szGW#LoqO{`l`!7Y3T0F&nKNb`i>;_gNmJJq939jxJDXrQ$3Vt*l z@8-Zd$N6W!eOJC;Or{=1Q<{R6Q{gg~%fhr{xx^Q7riScTjy#xkYQ;{$)C!(j>$~(* z9#3!Sr+l6c^W;p;wqr{O_R$vG#xKL``=Dg9oEhs0Q0uz#NqsF$#&&i6&$tx1U0QN0 zx5gXtR1C2;E3gbzzmnzZhPMug=AX&pSd2U%dB5SPS@=c$gbd^>Bi(y7WSBbHPbFq0GXg|dXe>u z`IO-8_Vo&mpT!4;Uu3E2^=ZfQ=_u1H=$TuNC_(NlrTUpb`IxBl3(OE0#lkT->;m`0KcO1Y;%g9Ltq2t@ifG{Iz4#beceI z$13!*bjyxS)|~@hRsOmF(7J(yG_!z$QU@=WekdcVY!c!Ry-?Yx#HwcT#7i7P@8SJ z4@kl(>*4$4@7{!*1uMdiuZt6s8IG3R7)dB_aCHLE;S+`tYXV{grB$S!O_pl$1h z@rr8ewp~|xYsO#gYT;29tF=BzYlzs?=xf*(q9>hh6!i9X$*b=Am`GK#UAG70aP@_I zS&zC2lTfI~Ll(FlQ)F=TG#AFCy9i~s%S79;F21<2bTd{pN+g(rGs) zr6GTMX}fhoLU+6=Lt_#I;{N0l$VzfOG!vG%B+rdWF_JW?G&}8U@BTH8F5J~MdiwDH zcu}BzRGOGbqvo5Mi{#7e!%Y3C2kEuLlB#D>HOTI-d#2G}^mh3SJn!j7hm*u%z`lIXWBwZsL^0b54#>7^Vt1Wg1zw`oB zyo)D0b~nFn>`{INJvZyO+xTT}1d_Ixyg(CtwA2<`;=RmPC-mifmXhRRAhAlfV|6^M zMc?5p?n-Bz(tH*=4{~0Qj;sO|C7){iE;;lmC{nAscMM^Rdrs0b8`F5ySw8t^+4!Vw zb^ovAcEi;_(drD&FM6K~{5o~e6XSgr|A-MrD*q@~gy=tX@8`gtiPzTl6oa200&}EH(-Fomk!6x11w%AjEAt>R- zcJgG$p4PwH_;q84`E83m!LQ&zTWqWMWXC%67g<(P7PadbBHgmCNr=>P6s%FL-^Plz zUCgO;L$+Rn$fvOL7&D=H($pMo_C>1VD^Q}6KfYb&Mcwo65QL{jzP)x;j<0^?sq)Eb zJJ2`j}7HZaA&jp$=rGDyj2im!2&=s(8%@=Gbw#iJ#T)JI%U~ODSfvLDkn-2^VHwv z#@17&P5;UV4t+}RBs3`YXW?~mQD$4~pW!3WyOkZPf-2TFqV|r7Fg(6pYS5wfYScB5 zL9`{3>(viUuKHhfu5dJDuAbwzm<)upWyc=p$<`C=#@cxnLeVU>>6H|j&E&P|M?sOA zwwU0AJgT1&upEbe`F3oBWEaWNvXjE;vyte@e(LqUF}?ncm(SbsCQjpzPx;jN-pv^G9YRZWeXm{{>v?&uaczs#T^wfo_} z!mezBk>rgF)@^>-vV7{6AF(0poVvq9y$)OJzrj}#6TKYaHu|5tD78FqeX|?gV@>Hwk)VS;EMmN`D63~8aJ0~*K)?1$C&=#g3jXDiD`mUeu z+(Nv_ov>kT;hoYmtbEj^-%10`qEAaMPR0N6j!=;Lo8#N1O>)yYwUk@d@#s$V)(*Xm zbdF8TXuB1byJ}CXNiR?vGMbm;(MQDlk}h4Np42`HHtBg;)1>m-L)9=r)H8BHCs{(0=DXcJCQ|u8EaAyAS z5G;n!1q)_du@8sH<~SLtf_m>8m?=Rftyn%3U6#IEK)R-;UI+H zlyuiUCSQe2|MU<8T*i`=f~G|$CSUE?CdsLPBWfkC9473wV=GAm#Pk>P7=A8_+U{yn z99M%L&vQPoX1(WZkv2|E!T4kp&JX_jJM3$8lF25LQVd|He#tpWJc2z@QO>5JD;lhl~{4Toax{8A8 z223DM;CvAYP(T|4{hOa<#8xnjA8Y+A2-b;Be8#ZCik0%_=&^5F>4&Ud%X^i^&b2oo zK%l;eYHydiACTQ)N!LT}mec@se3e`mW}q;38PG_xreJ4Qa?5B!E>jve>j1Kzvx z-h-x>q!QCo3U=`UmPE>1SI49|arBsLB$U~Z(ggZE!6$VqYGBQ7%bUk;Z{DUEd{<|9 zpB3!H+5xL+Wv&my(V1iA9K>ppAkkYS4`9pp*){RV*iQVz>BE7vdw{8zFA?=uS%a}d zf2S7tK6owiC8Bmv3j_PDr+DM<_qOua8uwd6RGUENQ!yF8H1>O%ulFy-+zM0OZS)7Q z0r`?7$nouulQX{k34S>R#v`H5(edRua6bm{{@>LfVQx*W>a9(3z|g32)fZ$HYXl0i z1WybDAt%Idcu6W<(;;q4P#&%aF2NLO4=8|pevhDszsD-TczXVSX$yS4< zNx(B?v{(~P>wzjgUb@r2VD)&#E@pI23{72L6jXnH&|6CKvi18~I{&o}UYyubel-S| zD?(a>DRV6i@>dgEt87X_x}2NH%#iCwt79(-(0Zb9os zBcHIRFw|bFw5PSm7#gDGZ*kq72HP0anhd>i-12y_Zqa&V*M==JzYO!GP8x$NdHExw z(Ql|PlcAo?d4%tJoFxb3zzp}Fu%k9~tHeNugN+CNsSgh^u=kzV4zz4nu1tlX&bN3^ zSxP|-7>UJ)g}0LXs#g+b#W`4ml%JyU<=OG=QW+uzX-WNwsW|ZpKTi2r z5h_&_5E(t7V%3o$A-LGmA#+pwo8KRu7s$H-r=^#(%{?L z;nZnQ!>_)#PY^_&or=lY+K!kSCnPF%({Bhsl@S3Xlni_~fKj);S_sr0j8*Ey&!jVB zU3Zg6CjR*@nF482J#k!?lSnnxZwYq~Q;Ko+E!s@hpO~7Z2a;2x*+PAOVIxmv{EU0N z##|&4T#R&Y1sJg`wWE)t=ujU%Ak#02>YeW*ZqlZNM;1Wm_3cfw-h^`9gTPfZ2RiHe z?|A#Mym|Yv?>||Em75s>706Fx7&e6WGYsMkY=4#d0W=82=dj@rOZ`Q+ssKMW9~@cg zBm8(vM%8Su;#H4`%u~D#g_|?v)+M@{{Z4qZ4C%29JN$%t3~%#@e4kRAU#27FNc{u` z+z4o?U#9?3%Vqdp4*&fkCz^crg{p2VS;G5o2sc|zD?lkX+#IQizb5{x0+=-;LtbA- zvYZQEDgk$hM*?Feh#1}~7fI%Fkwm?@jB8gr@QlJN&48e6(|dcpS;+xtvyvGXiLkWGaUoClfk4ah5QD7J24l z*E8pFfr#6iJ!`=w>4 zv-~^2zXS;y{QPsaJ~x{fOl*&$XDiLux?MToh)m9XghYGGckIM$R53-164D<8+z z^7?T=IzY8@F-buu!(k4;vjfanAcncxba@VuH}^@7q%H4o zNgqDvXhH~p_EaQ{)_Mt|D;QXmV#a*mr@%c=;5q*i@!G-r`QG0#Cb;KtcRhWe&aZ7S zfAzeb5E)j}OEU85(Tf~CD@cNPbz&>|H51=?shN}b-Avc5zt%g5$z^Ym@d2Ljao5$w z((KryQoNLf9r~I)vQ#b+n`DGkCa-RpRDE&Us=dUhHbQrDpV*6PSNArnR&Gtl4A9!L zdA@A#8a8RKi!SOMQfcQ{FNsPdlh=^gL-&<9o~Y0I^d3lr=+M=h{ErGV@}_7#m8dOM zip`2{9c?GXKQ;H|ACX)7uXFE7&3)*N!Rrl3h5P!= z5q0BeEiZ`O4mxZUN*;oC(5o2xYT3L%F|}Woj0ZCl}tm_2gir_I+;%ba&=yE_UDy|ojNmB+SQ%~f&i&@ z!$o-gt)Ram*cNusONugx36|j#tx1+4qO->S1kgai|@<@j-y z#x2+aqEM>Iw_U|MYDIq6-X~I{V=_OrxuUlIFCLrj7wZ_&+&A4X)-f$SWt8V-ykb{& zIj$7*EC{hxo0%WMTY(yLi9w7nku|)wq7Sv}G$GbfK;W>eA> zVUv^gxmxk2cAT7p8b434RSTX^zbR9UFke?xxQ7Gx^U}0=znFLAB^c;eKF8n6ZWb|r z=ZICFzPN&wmVECKt%|nGGj~7c9A)8)!iDwD4?$mVKZOE3{9FPU1hd@$rCtYeY(*;M z`TH&OqVhTQyFX~wE&Lo7Nu-;va=erhte>OUe;~H>N*(^Qu%NoKp?f4%kML|6VKWI2 z5lAh8O(%AzVAJ0|50td`!>6g72ZUK?H_l0(2ZZ~VyPk&oAJ0>g`@dXpLAd`V@aBg5 zN46W9noS5n?6p$)rKxOKu&hj-G@#_%aN=#|;G>QKS@5QV9s`Clm;;XibKSF!0pI?K zY&CKW5P+m{ebO<|nS+6&6?1YDs4=W8{4qC2^8g(l**m}JQ;P?6mFoDh^fTW(7|gyc zc`$hBu%MGZ80=?;4JUQob&MLf3cWL1)vn~cq@LOI`9S3QDS~0*ht0tjhbtfWLZ6KS z*S&*Y6K`;(vC`Yhi6>=r#B@vjgwG>A@M_L+!OafrUcfGR&EetwP-Cf9 zeFr_h$cWbhgqEj-JE(+xki$Y(QZ!(y8AdhE9HL&~E#^-O3*uIoo#4VQ?0L)v*jt!ra3;M#U5k-%S?!CrvD%CsJ5dY=7K1#h-{ z8;y8u-L^bmz2BI7Nj(prBDv=xlB^^-rjbI4FeN?UAIFvq;GJU(%B+=DnY8w74eP?N9UD}{>yf~UnjiUBnsJvDzaVR9HQ-HI3aP#VPDr-Wq(V05#KJuN<~^ZW(FB-8R_2K=Osgb zBIY@P&!wgzCU8t3zFjJ?uT!J^(!r1i_8VW(8%#{#ia0TuEMv$A+lYLaCFy8;LlIUN zXkm5iW~6BZb9LRZ8Y001?0)!-H9IkxXDd84zb!VICz(488F*47Zp0yBdtx-qEIDYZ zVekLIJ1^9xE+rMLBMe2!<2_Rbp$&Bfzm(A7&m+S$2NCJIEcUmxo zJ$0E_GeZugs8>iiqlC=KR(-3P9b5uORMdgL(Su^9(RM?WVIVyF-J7vpkrdm_mbxmR zv)vpX%v8>nxg?MibuQI-caE!VO~rMNH>WaCse>ZJ$Ds5LNn)J3b<#;QN<9X`_}wrD z$0Mp^oMza(Ws?}JErNz-%3|q^gvTem52kr2nG^l1(D(~L+&)XXXfldzOjfz;%E~Wp z5l8gxSm~$i1m!O#cY=KJm%FZu?IVT$3*|RtQ#9G)4JM*8{rd7Qm=8oX>dGE%*RNw9 z!!}eltMw1bZdAZm_1HZuTXE;tT*%E}F)j!daw$e%KJ0I0AO{|EKP2{uwk#>*+Ulcl zIS~FnBd}@OIIK(*N_~kUfBK{BDI8-qnTBD|m!{d_4Jv@h2zN5R=unaJYnXluf!8N# zPSdFM0278@cSc==lG)4k)8()%>10mUZYxSAHr&aZwt&~>@a%=%vKJ=I;D7oHvx~}&6{j*Zz}!9665dW5 z@R1vUz4&R`mL~V!xT>FUiN*Xjb!8*obEfOL2y;6VpPuNQgVYJB+XLZo)Or`kRlW`5!>M2p5dqGc! z@xg+ss!qgwb+`j1rj1Ml$1pt+;js;}2FUi0n1MBkb|;2hnKA)hsS&*3&|_Wm>xMBRz{n5`_MHYeOv->-&a@ ztX3Ph5jc#}<0Gq9%WCRMWX!--8P}77wI`EUOO}e{YQnlE6ao9qT9QR1Jpl{n?~|f@ zF~>MFB7&U|xIG6(iBOCi#IW(Ra7)2d%@6m&bqxoW%t;UxYRoiO!nqegM09-Yo5g&E z#`|7bvhirIxr%=yYmybq&G8y_$Ij%yvI=G5JrKO14LbN(>|2$|Ug`P&|Hk-vbVtb$ z$w-Ra%#5Tre(Qfe==goa=!rIcu<>KmyzyfsljE0F08|95wQ|BYBu+_aE+M2zpfPgvkd;tlU~v)m!%}Z;Ge9caF5_$PjaTn(uaRF zy!GK9*k}-tDhvXGS&(0TwA&?(&miE`{bm4rk1UY&DR;5XLOZ<_=&~T}NH4!e*jqqY zQ|coI9KU@7$6Nf@2$mWPdY;5ZC@5Q_p4)E5Td0-BR}Wylr|9ACT4)<2?lyaecDvnw z^FT?U@i%wC`jyDpE~}j>;E4de;LR5Voo!^BFLC)mm}UVGcxRRX4sDI^M*OG z&Kb`6;oyH`oh!4>Ra^MD8NuU;aa;Y|fN|679HFtv@i;I^2>-y=v|L@lIj354=t?PvTDY-xX53FyETG~A;_@y19i%*+D*72(L|K2*j z#moQyU>$coI{+U&fdA2TZ17RgH^e33Y;i3aa^9`tvbnwBq}>SC2qD_oW;(27Ma}&C zJEw5NeY9xwN9>)|wKZz22R}j4u0rmVhS)Kt%8SIfEVE&amu`)8#dSU!teE> zJHfep)b`=!KlC%x>yrsOX!xCv=(Rq=^iA4jdeX%4kZc=<;pB2y|C2o>+xk(N zcy1M^SmbLuoe|9@K>Z*e{LzbDzg+C~$sMw@3N~YMa&~fpRO!FK$H@d23r(lfR~X1b z+JarIwb9&AHG}jytj6E4#vNr|?+j{}aQJD@CJGonS|uvWuw-a=?X3c^aRjVAVtL*z zto7nmoNf113F_ucxZ?cTA0v6>j9dE#_1_uv#E&gNLY823DFd>YFCnV{zHWX=h$C^| zk++>MnPVAx@#b_B*Gg6l@wBWOGv^)xE}&ztn|r>n#|dw?*c3{C#_oEh2fwmd#%TBQ8ba6?;w%B)n96A6rNS5rI5=$kQpB-Oe1sQi=}WKep;sopsUn_8lQ1+Z&yRxVF6%ZI->J>qrKE)V0MNVCy z`2EIfot1=G3l{e@UUkEQ-p0#|qdkq66n8X^Dn8wKzLu3wXkN5_??M8eX_nfLapS<0 zWb*?5x~}!W*iWCNw>s@DMjU#q#V7{ZT72S9ROKx~1=iZ@q)2??*VW`i!Uhr?FW-Y| zj7b)QnsuA_f`&+4c7U?5Dn3=RSL}tACjbYlN6dEX3WFI+5PY^ z*+SC}^R6?C3p=sNH2Nng9zL#K_>pn267Jb*MaR39>($nu)9`||r>2fwTR+St9?+M) zEK|plrZYXQn#k1oaW}jkgPlVv_JRmZqkB_4m^6Pop;&UmPe-Jh+jOS-H}ty{yk)-H zByEY49CPKvNfz>kT+erbNHH3Zb9d9JC~7MyVt~Xl>k@God^i6SyMTa5@oRBtJ|7!^ z4LWT3+MjA%ver*v|FC{EtB!rZySd!*ry&{dHZ^AB@b;MX@Cd$FyNl-QJ$3C(T86gv zCeI!>>E`p_xpyN(d}_XEtC9X5=3W%it18eDT@sq4K7aa>!@CdQ&##VmFzOP%q9?B7 z8t`_$Soc6jbVL`Z1->AyG7*^w!Eeaop{0{a3pG;+&$l84k=s4S#Z_HqJB|?Fv&PEg z;-6Qd!bly1RHM3>HtHno1blP#h zX3bonh@3=K^~BTuh4sv@tY;3id>Cl?OQ7X63$RD(`Lf`+vqK~H7X^v2c5PYr`?wEd zgl8IiTTTS9lU(;3^Iq9IhKIQIOt`n@oxp@1XP3!ImIvrg(ZV2&wULQp)1Tx$T^gK3}(2JEI`Xcv11c?np?6 z{m!)4`P1R}Kg2(iGwnlO4mz^b$N*1!CcarR=SICZf zH(2}46d676$(ex-b;*m6)TNk*s7Gh^>Puf8P}(I&S3hi0 zA0Snt9QMBw$RcT4Q{i*6qWR9uirNUvY^ZvOSbI)c#Ugg^-4e=oM=f{Z$|`L9eWkFD zdVpwO?@#Ye*b5lh#5lxFs>J{H+iL<%asP^oT>ne5enq1@9u0@EW;psO3wByuw3|6|8D#LbxQFsSHDMzd4QEAp(6>Rg5Ua-d6NDU$*Hz^ zvGt2AJllh^=xqb~Pu6X$A+@o9_+>D}P*(nihz8VJmhan8Hbz%8aKoWK;`=(M)r2bo zzW67cZXIr}=5o<&1qgSD_DJpIlhY1EH$+_{Xy1;ID;S&n$oFxjV6<3!#UBJLXj)Q> zrQJC)cv64u(gM}-btX}ak{E@Gy{~dpy^! zA-aH*H9H;}fbmkFc0PR}hQG1BYeE@&>w{IIQvAX1#jAJ__tU9Vg#7EeCNY{U(NmPMShx!gaGTc}WJVQiufs!WR zyw4hT!yDSdLZxNzLEnsP9JTRr?fhJS+7#rI9bRvWFP#XndAu#Gw^43|KJwW+mo0A# zKRS_2>ek;}=!=IpQ>-bxX)^ufj%h4Fqf$G5Vv9%Zw&&j$;q%ZQF!_gRJn8F(>|!k@Kl|MfNsW+OQh6_z?J{rA~{R*oNjgKD;feSyj*m+$m0{y zz`xHW6^h$wPK)vXO3;QzLeI;9LR$jP1;o5aBc3;5uVuUPi@y8GA{J#+7Y^p$rOFU! zuA};BkKN=TR8wm>?o%T`LW#}_GF2)VapD%QZH)WsFKlW&>5C3`vZ`*CL{_^}i)oK~ zZxfcvn#vQ_Bu6!>9%t7_@4NO=&vW5nWI8Qhm8%t(( ziq26)Vu{FInGhU~*!wc-C)L7>sVW*I4w26}XfKdMJ9e}12WmYPeM%ONwZ4vt>O41b zKP(!o(BU+#hn~`W?b<`34@)3s! zrsQj!Xb@DfmMHn{WXaA|0QtWtfD7KrV@~*}G2zJkt)9xJzxY>-aQ$DS7D!gaBzB%V zVK1Y?rIcwc;xqavaa=!6Ew@W8l}By=v-tmA_NUIvNUPMK^mLxjb1Bb48Kh@q8ZoNv$BO9R2NA#-Pn+=mleVGUK3Ge|4iB(9Zr@F30E*;OiS0#Ns3ErQxldnE)ur-Xk*;Sm|OayjT`3LGxUrMaL%Ny=9pUjJf>fC1M0~x5@s)G-ippG7~l5RJ>^6#@*Tl z@!%EI=nBT03ZU#SZN6mKa$gny9RBU%U#_*>SHQm?g0{Y_thB83tp7j$m*LOsNB)FA zgX0x%CeF*X){dGGveFSPZw1cl;9;bGn619dQgyNj5MO`A(lqB~^^ktYze15(?L9gp z<4DQ^5y5)QsK`17i?)~5eEClBC&?R0Jon2SFqyN+JYHuA=*(9np8I7MZ<=!vuz-Kr zOa2P>Q|dGes+Pa+%EE%tUdaXH`iVqf> z1FQeALgUEj$58s@LSU*UwT{St-J@W zCSUhw68WA>&F7C2Ce`1TSx3HX$rno2w~2gI1%D!uHxhAC?;EmH@-E=MOu{dTj+eSq zAX=5VQyN?#^7f`K&YK(^QLZ3p5L>eMt=}~hmi0ZW&i}I~kSsW9avjEzTY3vKi#{(G zi@a-%+CoXf5}}3BatZALMOT4FmLM6}T_4b1!kgVnGQoz%%9uK|(-AF2Y zA5Xx?hzvC_EF3B@X|xFqE#Xmp{VQkpxDPgYqJBAhB04vc4&JMrmf8uzWC`Uet*(K4 zyF2JiyEG44C?RRj zW~pCvGaQkVTz-V`PpvQHvp7C@%i7%X!IAUYt5n^;CAf)eXrj=qz;TJ3zuQV-yD<2i zp5In_R2EdzpVFd#NJL#kw%y$K?DfxUk0=!C=7%ptq96e&V1n*>4JHS6WL6!gMdS=^ zcy}vC`#1Sd4JD2 zcP0}A_y4~8qLce|zRz=>^PJ~%p}thhIQ)fvo#Bgt@rxW!7Txzrsi&5@F0r2*kl z{^Vv*Wq&MPF7hvxM#BV zs<*#J?Kt9sPL;TlV*lb><*uu(w!hhd8CL65sK`G-)B~%@Jpz~q= ztGQY228wz7?>S(HM{r1j74zpQevDm4bBWk8rR@8tf+ z+(%l8^m&veR2MdESJxyMdjn1&7(3faeH_OhvQdc(1W3qSvmfKD;(ktPU+wwYwvoK$GC)&~=u|UK1SbDAUS=TSK59A2<*Sm^9dOi)}_R?qqzhnWg(=U-VO9Wt% zz12t8<8?oe^Ox-*);91m2G$b~IX!;&{MAjMiN+PQY!dX5v_Y7CNmh~SwZiAH)Ngl% zt8c@FHhWHD$#A|Kd{*$4I3!B=BZ|2-`t~`9Jo2_XJR zGMQDruWpsO6+aY#;$DN0^`YAvE$^VTMd7FX+B)O6uy0^_?~AgzAbDG0?`C15tx*@5 z4}8{Eo7XS&T)zNm1cHdJ;733yunOD=2%iF0Dd1i>K?+v6e^0nV*Za+*b@q*&43x7B zPZ|tHM75{D>~&hSj2g!fcA6+PpBnS>qCXqlciS> z06IX3bsBc|#6=|ZKdT8F9q~=qD9u`|n)OChuNFtf+kQ`OTm|b;VSxttsKU}t*oz%_ zg}(!fSD?yoEnm?4@f0Ei_Kr@$`$q4ZX<0`ReHp)HWMAlgGdJrfU8yHPxzBC}A^mTA zGHtvk4|41Dtd0AG1UOLp`MCalhs7)Zu%djt`$ z^U`{O4Qc;>fbRZR;PGY5#uMPNmwN|1N+J`$tUeqB{{fyozs4aK@}$W0}N984=m>iIvaei`SDE3E#C)2X>zZf260i|Zw{LXP8J88 z9lNBr?JRR>dT;NCX(fF|)sSrcyTemD_lGApC6PJNS@7}7RsqNCCH5^gb7&?uDX!ts z;vRV~5>CXdtCqdxL#7uV58J5scFSW=NQ&Q3(p~*tkK@La?KN2 zqWpFita`$mT{)}eGXO$#mVmpgEztq{ZBJHAba8qKI0F1S=+3Uj1YLpfnZS>*FrL8M znc`3cWa9^5Qef|5L94L&QL#!DN(+3c-JTgoE>|6G9V0NTLutn#_7Lb)`s|;*OI0AL zb!_cEX!*|lZI@bY`Ec*dNeoIrjxAYM$qT4%J!&wXuU3BPL!D#;msZ#ea;pjuvC* z*EStgUUn3KA^vbKl zS+}y&tFiaGqE`zp5EBN$o918>X9Ue)^>9y8*nQd^# zg&>P_k}}jYM0gygLIkEG8IC-*lH&_tiJr{akI{gHv`Fp8pD1rOFD)=S3ey9S&zi zLL7y%AcW8VCl&DUyhxkRMW~cELJ%8@qRmu-omchqIXhlh=R1o7mFDTgpVq=s%`fSn5I|w^5RphP5FG3)f zwzJJpA>%wH!XS{jtWCkGMAwdGv{R#aZ=0cCs{X1CQ|EV@^zG(TH0eX30Fq5QvMr@a zGij18Uz#Q5Z*NtVPALE0BS#qWarwINFsvB>Fd^Oa+Qvv)9)r2j---Ac!)*Dh%x3Mc z-GxXli0%CLSTG<{7)7uyx$R#IL8Aog$g=IoE7CAupNV*h<8)!_4Jt

G&&1Z56l8&O`pJ^g&sk2^id)08tHt8aC`FSr`sv{DRw)A!C;8uny3waP7qc72(S!Kt%XlGvg#^ z_|*mt4fY&y%z@k#KoLEQe{$YyeycJYK{=Q?ReU{7VMpEd_J6^gX=334ukhRSvM@2fR)o_mAT;w$h?s@p>B`{ z?ZZMWjAODa*mv5*zGdmYDb|C1EBbhv2|<04BXcGopIT7?42m;yQOl$Cq6Ju*O9()- zh8=vn**YAp+GA$o9cp@IfLKP*q5|(`>(DAp70U9am*IBi2!Xj!^2DA4%?zvR02&(z zDUQUe3#47>OU;TSBJ8mi<%ugV92|)>JC14Z3-NWc;_Gk+T4+yul0k3X&i3x;kc@n( zR+KU(-6Jk)TFx?;4y*kRZz2q;J9^GYnHk;#=|f1`YBOWHryB1)>VCdY9)d%Wo_W>r zFuJWoe{@dgRC{2Qx6@9x+?OG>(q}1DD!kOiM9hU<9|}vrPkbYV;=`3unP6VdI6IGYvHD^oAoLvmCUdtyU&7 z)1YS{CLwhM*a2AY?4G86D9S6>`P!!G^QMVDq<<60A=BOkjwDf5sAQdQ!&{B0nD;kI z22Gecf3ZeJdDqvD)(({XSX3RfY&5No@8)u(7%;3WQM}#8skXIze!x+y<;t>yd zVLX6Ml!4zRP;sG>X5WUL3S$L_8#Tm0@2{}`&sq&MBI!}t z0$ew}YqW(B@9hotydT`s&f7w1vN}Bl4`88D^{D+G%&2qn(unOzc+ZA2< zQ=BmiID)$ZR{i*JMz1Dp(wWx$LbK|pL18om}LSWW(-Yby^JeS+R)3m5*7z5eeqnh zmeHY|7hOD08YnSFH-1C6Z(Ihh>Z?wLPq8-v!B8ji#vUOjF(O&I#at}*1+8Fr&&bWf zW!c)M#xt=W!lNGKl(YmnZx^geLG~U{AyaaI8RN1E`LaTbBRTQ#b6_We`ozOe#>1QJ zx88-GTDnDTr2lRPd!+rT2>qqi$;GAG3qKI)Aczl(l~E!JLBCs=(*nv>{%ZRde-Z?O zvV1sG@n__8SZ5cX^%A@`Io`6mZ^aWMr@LUjP-H85B$NUgBBD?uZ=GO;UYzCr@KwrU zeWDCyA3Nrh`$N!^&EuUkl zC}fNMfv~E|9adF2^C+yUa)(t_UV1WfN|&z~Qw{NhY5}S7nKeG2N?0jG%?>ee!}1^p zoo*bkV{mSKuh(4CVm!T7w!GcqLh^ccWVjifJ?niX!%#n4N7A*kKhFI-%+eO+p0DE) zp@ zQQ2VY?CW*$=wJ}Iek1+aY+s zQJBA>g3g{ce`K_<)$taWmuy**AyN4C#2RDOK@Td#a8~lAMsvx(%vX&=kVN_?)koeK z1zJM+o?+yc_DqY@s6Ir_8`OtLE3}|wc&!0P&VGtA*@>c)psis%Pl`6?$FG1hKlHhF z;NQ=pkUcR+NdRV>i^Q1MykXa3b#U%x|@6{j*{aM(|8 zq+-Qm;W#yp%xLwg{daDDRN_-?0=tYu9%Q;@J%+N1P`vgb!Z6~wG!}ePaBnpD8~{o1 zgdqJKvN|OhL{nWXxJigYxF~Yr5F5uEb=4+&FRIk|o0FiD*fTtQAvP2l`msjWQ3Dr) zc@v_2sd9rUNget7xs_C{15z%!JaJ3H+ifR)w4}A?e_Em8UpWQ5Qt-F z@b^-lwBD}0SsQk!kHvpzYP6@_t^h#-I(uFAPm(!ZBU_TwpBzu&<)_4V9+vUE3A8sp zo~HQs?V>8STs5{5@l)+~cLxagB%w9zwlDonVnC@d8^KM{;7?_gA5%{LHd`u0DBC}v z%RoOO^MJLDGtjZ%qjIOl`(gW5$b?GKG7|g zT{-R3I@LLy!Ej1=A&jNK-q<<&C&D@_$y%UiX7B9S#*-3 z<)xcNxQIyxyJNJx0t|mHzcNux{Stb|64fVgt*CX@pyQf-%NT!PUlsNuZ^eBB_^_N* zE6YR`+4(46$`z_CCrhAAbXm9X8Tqh$p=55Q81#+%R0*iit}H`2gRfE!DsfUS`Bq+= z&+}5L)XAN%J{3s0g}Qb6GtMF>e@Xit-ek#%mL=vns+L+AH}it%RH!JYD33&;380Pi0?n_r z3v^MUx=1&kuJm<<7}?6qu25!o<>amqBU_o(70N;zSj?Hn*)s@ItLl5t-VU#@0}3S(TcrZqv&}>NaBn5cy&EKl71|is&Kv( z0N$od@8u{ljQB`#Lx`lN(pW{vx6pPD9z{Qo!oBip55Jv4)AHNL{jgE=u4+<{BvQ&BxJpZJ+^;n74;eT9 z@f}Ly*M~m-JI3;15_tFWyiIX_R}!LRIe|x3?t?3gzam{)kx>{+bXIV1O5eqwXx^(- zowwI0dR6Man^)O)2x4r&v&67{zJgDeEf#c=d_87A-%sl~cU1YDn0<&Z z3Cek?l@o+#U$xnR~kics~ZAV?NB$D8bxoYn+qIVW0=y+AG9;0KgT)jre z4z6Y8B|A0@v)v33NWQCbGAq-vZilXfP^ty!k&o09?2nK$;_boysE|E6V^v1N-F?>Y z6^wtOcq_wjt0pJ{jZB+F@(p~Q@pus)K94U!RH4jCryCyY6ke1zDtxFn+IpNP73QpX zzkJEA`l(4Uc7K%s25ZrHs2|?ErvWlyIP!*+aEl~>?2!?CO!)TVX-j8=B;xiC{g&mH z9oA`?wnSQ1V&d)N+&1X6o48fws#nqAld9a!iMP?J2T**8Hf)bp4e^c&!jD)I2Jt!4 zu~h|oc&qAK#hT~4$cBQC)kTAY_FK<6yW4{&?{4S6z?X%8!-VG%Iql+cdEwuNv4@g9 zO?I>gJgpDlpWf5(07J(>(S4eL?~jUtz`NehU&9br{0*uFR;^#%3y@V5u*d=xuSkzz z;i`M-D2_mXcn{%DhnyXe*p*C0#8@jwZ&WKR^2N{4^AM7(?{z!<@C|o?rQmx>@f%% zJM7>6rxey9{<*Ywk&}-g?B}OEe&ncw!H5A6y9O#Jryc%0tc~#l2;wP-epb3-`#-c? zAsON1sr_l;_+k=HzidvdDWZ75AYM&C)x3JUfQDIBo9*pfWp~ zcq!v69?AxS``zXo6$oDGhx~@|OYC2-1KH00HJWbR_gfxuDN((o8S+;WSJ%dgaS~{6 z-S29-lF$?Ga4`n45_fz$V#8&h)te7Y9ZY1CldP5lbNm6c^WmE*l8F~j0(%rd27y`_ zLTGr9A-LVHeU_0%7*(}r0!&tV?I@I_q!ln%H`}=>^$t`5k}|TH6fMm>q?#!yaf>^l zA+iE#$ZBbbqUqBTsY!gu;Y0P!;;SgGuS$L;!YIYb^3mWdF3BBeR?fsVFst}v-U6xk z5W+NF*A|GFku|FjvFK*;@rbTSi854ZL}xK51VQt9^T=`yNb}S*PrX$&XkSKTHO6Rg zd>MR=Jr3vjn&w%I1;+s5BzOh)*BG8Za?lCF??#>dcOuGk0R8bg zU2#%fBypbhJyX@77BB0Qz8db_n zgJ!F2#fr_vV;{bsd0cwjT*|&A zX7JfdaT~BZifpA&&`&~Sa`zccD+WRf5;Yk`+cagik=juXg+qhWSU8E|VGV7c9C3o? zk!H@9W-9STVPrHdJSAF}8*R%&@(^t+7@2}NTdV?#VfRsM@or-#)ql574uc#QzuQ~f zQ&LwNtt*AW$*eC&9*p{n5@A-WB&m-gF~4lTpd6uCBLdKP897fK|0okz*b9 zm)<5PW4D!d$?)~=LVK%*@#_$eoXsPA4Q?m7IP~)NN|?xN(3PXe&W~sqrY>efM=aPb zl&cvYl3hJG>UlTv<|N@-hPUHl!`ak1vjC?R?>zwMIs5v18`Ztq*Pqw>y`X@K=l4(> zpFn4Q2IV$TuFvx-!~Mo22n9*_38oH{^6zlkM!k~Ks8_~^=?7DE*Nx6^ zNWUHIe|gG@_Y$E-Aa6JD-JbCuf(5lpSg#T+aPIv|FKv@OK$Al30@ivGlgl2%Q0?z_q=fvK)CMG8%V6w=^H5MgpaZre8kR*rBV|7X<+&~`Qi)}!LKe9CzsawO$^ zEy^kCG=NjYl+(bhguSai4|s(B2c3Qdrj+x*yK?0`Fv3-z2Y%y*5bD?sC8UpoPxl+a z!LG%VISsRnI1{jTI2Jqy-u$Wk7CY&x^i}C>nVanof33)esaDk%=5~=xD(Fv+0NG2o zL&dU45Vr^SKuAf#?5ZI}-w#3D^TY(Ri1Hd}2sE`2_*E$L^6{YhD22gc-)@EnHK8x6 zzNqcO_T>9g$?Q-&DiX?29W=A}`3fGjzf8Lni)qUQf(I7U!~ew>i11HP-`1QGY)@HH z`0G+|I&8KMrchik5vUbl{njNI+r3LdlA}wUNXzlj`4@!v{e zoRQ&l&P1dna<_G&tbolPet0iuSRlG6P&21;3aag~U(%(eIkI7)Q|N422+phRB_B|u zY#xpF^HsV>kU6XuM_y2G51mC`Oz*wMeUAW6FfmrI#3NQ{Mr0IkL3rj^Gy@eL3XO*5 z;6gN%i@2aE8p=}w0lYHcg zFp%)Ey!ePC1Hc&5N zP5{H5k7&hd@$d@if`g%O&b}tEg!0g-Wv=)lX@5f6eaf>wvu_Iyc-I<8Z=AnFWr2ui^^0z zKo%4jM6HU=A_-~D*|esveqW>4Hve_1NCc3yu(kj^p?j3v3G*TRjS4e7A$xJ)_1+^- z($sN!MUHPAAi;waAQ9nKX23@`?i*$j<&9q`L1Y-bdY)INVLYwEPuwA3e~UkIXP&F} zKL!67D6e+j44ST{L(w0~!IswEE+^{j0+gYK*wR!}TjrZPJNCCsb5h%t7r9(`OVFfE z;q?jNr1(y;Ow_}pF@q}q@NC*)sc+R*=M7S$X$aM>)ZLyzQq)MyvQk=OnQJ@UDDv+Dg7kCo|b?i4fk2pP% z3iJTnT;M${j7v)qa}179ahT=EXiglkI=h=$5m{9(4h&V42+OZ_lbV_Y%WB!LI7IwT zO2@+l`njCzLDnjE2TE zNY93-w$|o}S?_@)Fr0U70vN^{0NBV7R@(s@kW6`OK_aEJNQP!Yi}avNizd?|p`sOM z<3E$R9Haq0j2s%Jh+r;$6@;%+)C<-X$hfOOUi(vvO(2J-FK`Y}IXDnBYx42=aG`l^ zj#)vRi;99=u5>bRLqRT2dE6~5$V02T5Zf*av=$cRGvB=@7pwxR(ctLTL~Q4UFtH>u z)r6Glm4g-T=WpEO2u{fl>G}b=_W&kIlyCSGV3T0J@#uOZ=XvOj@!W;$hja zaU*b-y|Tb>+<@KNjf3P$2KxA{YA%(F%*UC%#0WfjesTmPi};VH*!~(imqXd&(ybAp zA;Pglv66H7VScZXkTzud8DB~T9Y9Z(*?hi`cfY89K)S*ar7cQR>hN9IZ8(NFv3DWS=5mq>{TedFjw{+B8) zSBlG{I4QY|@+sOc_vN{AU!JGfj|1fwxl@%1PC@@D{Zr11oFPT0n5r<6#V=NodguTZpK2s-)!5>x|?fMA5{IQ@?_Oad-%pQ9Xz8 zoVr>&=Lu{j@yw8eHOw+;mCVZ&rFw(PCsR>{8QYz>$k=0lP^;H3Zv$1^IR_wJL)jUY zCtn4my(ys?$muVri4U<)nz1Aanp2^W8!91!pN<41HUx56@v`U}!ITZ4l4T=H4p_qH zAP?eQaU~NFJW72$>v*uo#g+pv5=FcfoOH*S0)kAV$d;SC7c$ViX1NA#k^&IeuM~Z$ zKs7@WSRjB0RIj|2SIb}F_a?uWjG5q$3fQpllF^# z4U*I9Jg}rt>erpv-99gETyi>Qzx7i^sgI3Q>X&e=OyPQs3r?jx8djAH?*~z_5Xc2Q z2XoZavV^7WN}$dB8^o%1R`5xzsriyhgF_+@{gv%vKe}p(0#orGqa>f7N_ zS=}%-aGm9q)FM$283nl`et;H^d;)pt^>*)(A(nh9J$S4;l!U#>g}OOr+$ZY2#?04@`@SnT^;_v`hypNsA8)o$UGi?!R0J4B)9iNM zg!z-LNO$ygNu-!?fjc@5|AC1jnQ)F*ioy@q?1zLDHx)silKY23!I_HkOXmJIxsf_q z{$sR8mK&41GWdYhRjr#+2CCNlOfhVI#(~2O}!)g|;<%`JH1MJ=_W%rihRM{G2DSXp{B{^K-{A7ny3383FRq)xn6JB3u<1o+#d}X;tH%XZ3t0<^<<#{AjKklI z;hSega*4kF#l#Y2MRv-9!Sd&UYWq3O1z>wY$9zSj{cJMbtq&}^t=YAXUz_vm{8OO36DX2P%<%Y%KS+Orbgj*^x_zCG|X0ta_@2^ z@XLGH?NQstH&z$9d1ulac+w&7>`kOP*w929<;X{nIGXS?xOPbRkv$S)BHJKL~R!cp5r32f;{ z6J(CpzS_yj82(S2x>Nv_hGQbR%agmDL=9@A&sF20`U|B9hvyKzCKMmZg}PhswUl@- zlxHnswgPp$T;30Xz5I`q)j%?tK&WkFW|~onOKF@T&6IBOG-%0dVGIRAIYwolRfp!F zd~>S@D8MwGaGQReY1E(5j_MCzd0+Uh(R5g?i|jiXndMuQqUkbBt@P<4q-nD)iRUlS zo;$_}chI@}P9Gt*a8-4J(`>ew>)}F`cdw~;`>e76aq}iwS?^lu_eg5U7(rFH%~bH;yPB*p)U% zX5+@)XuS^d4Mv&xK#+rNU{QdVL!>fp?3d5H-o^FpTaBX2Y=%RsxO*N6#qi({>Tt}_ zbb0z}n1bq@43GDG4&l!mGY=Z~T}~&Z?ORma4TaOmD>D@c$&4-n2m)to9GtSM5@&8$ z$V1I#qKjK7F3V&5xPts{?A3>Il^|agv{?u!r`+X;r&uwqJ(A84d-gYtaNToe#--RW#2s6_an^?>|)DcrXZ5BbQx?6zcx3=DRI$&O{ z_KLee!t51$nwybdQ=}ADiZv4AhtH`3(~Zs>Nh2cV3w04x?{8W$UL?{0Oh1qxi&A?I z+-NsZY#Hg=QaRU95dR&;fTilgBix5d(OuX%sIEl!k0p zMXj79hg!zl_L&}jwT>NSz3~y4$1RrvJPzQ20XAiGk z1Fq$FCX+FR-x7Y0@DqFsesT0u#mG3v@?QPD6CaiAZMlrm0)YI-j3WOowN0MKW5qFc zr;1%_v%YJx<-JNJ4(|t^`c^2W1?3g*7703BX}@(H6d9@rCCA!Y(Nb;0`$5~^toiI3 zfd!*5q}Qf{DinLeCr=qXSv8VnLCUkBq6MI&#CH#YLL)u-B|A54ZYtT)T7Xq4zGxHj zJ`$_Ey5urKRG{tmcCvYnK7i^n{q@m8^BwZ!fHVUu|LDc}e#r~1BBH6-Nmu(-&u8%H z-O2JJN^aqhxeME7*#FcpXdWvod11pYSVD|<^m5$vp}CjSgyXC}xtIMc^YFPpmO!-5 zKgP$*#0ejc2-_~e5(}q50mW%NCT2?&$HZkWkA4h7_`sC~#=7(Kq|1!hV6Jr%C-8SVE35gH|pZMzob;KPTlTJ+^YQ}I~Q zgy>@h{DirZzUA!rx_pf9!;Eavacm69NKfTzN->(<6;568%mncR>95F;mx6lSzd@5rZUsB@dw{iyx;LlW?6FT zbR3q&f`cGwENQmL<8W2v9Bc(DW)@B zjTLhngWn1dFzCaMI=L#BegGA5@D~I;RYSJf1 zv~nVh%SHfKnZF9&OUIc-IPYyMn#3NnYCPQ$yN`6NY-LOkK5oqXmAC%&^Oe}uv zvPAI!TS6)St>jCMf8m7IssQE8)TpdsF-G#3t8*k&C=M`iqRuSYYxn{x^{Lna=n~5I zMqev9PEQ|T^a0D9>N?bEzxr#DzvEs?WFdG~EI!$GZUG4#+c|~xvnQn_PX+cw`!L=j z5dH4jXq7#Cf1T-)C~Bj#y6bmNN?9HnS0DMO%-ccqr;B!9yiO zhSdwKK&!~nxWy+@(Ru-*c#C&a`pB6$6EnA+*hLh((%fz@<`$yL2AVPMyMR=nn#bFO z**N+iZq#6?7-0i0qZBtkAln0Kn?0PO57R6~v?J{pRyT;)@vx!be-a($x^ZGJL#cawTDFjc+%D!E}S2^zv;!TBgOpqhg&H z9FX{MRiqlZObt?Y$Numck=CQ^uD^9#Ful`K7E zZ2SQSbSezrU=+Qls2ez4%JAlHFD)Z<1!|yX)e*2$x_Fo(AZts$@}|;~)^)BK&Sk9x zpqh$zqb_%4)luWYzUWl(eW7$=7@GHH_we@(qv)N)NWU&OM)yBbagq#Ry{yaRgvTIC zdI+?YNc9d*06vuUwd-ndrUy%V?dR*PF;QrPJe%1=^-O%hhn)3Tk z?o&b3#DC73d>lk?m}4%lRumX@P@+&pgyAYHF%7wb!rm5S^G6=`lK0!4p z{JCHpe~Rn|Gz-Gqte9)hO)q0>?lH^Qnztmk<}F~+s?BV@^pl-f`1M@2>x0fuCF?uD()ut8w;Kv6^)6VZcei42f`6c?29KVzF>BYb!a0-2T=?NmRuP#RyiQQW? zc>fzxS?C_oGHbe2Z%z~Zzx@9PZ+%^-gSS!C^jVGnBmb?P5>nwU&HlZU^Q1YF!sIY; zTA|tmdjZ62auGyaONE zg7|45IOejC-0xGQ&|g^V9I1)Y8bwYynzkm793gMD89YJ`yw_;wM{?LB8J_(2^^OLx z-Y4kFsIS1&`@y+b^tZnz4tje(`b>5E8=kI3S@!Q)vz%Cgs()rJUw_6Yb>`$>oDsRZ(N^vla_eX)i_xv zOT0*g=b5;^(ce2}e^(aSsSUTs?vti2y+}26g2RU(?${{+9();Hhv!sV%^4(^rzemO-btk zv-O7+zZo z2-aKk2Cq+nz#M@<>}`DTogzZec4vfel3_f3uK*pBKQE?~dWHB$srT`&W*K;Rq0Ep{ zDA0NcBKx5IZ(};*$YoWUKq8IIj-=5&SIiQfQL$0TnUCMT!$63XUOuMmBgP_c6FNn} zTu+N)!01u@)S@nV6*^UfY0}EvL;^AiT*=ZyIa{L;Cv;s+&EXWysM;so^JU=QZUc)Bc8itEEEOikvg^p`|WyIxi` zp0dpK`4IP|;wdKZO+Z$hHjG8*6|kP`g`0i-19~<4niwP*Ii(pgE-g~@h7a;@)E>H5 zKwj`f(06OBG{jS>>g}j{rvP*mo`cZR39LzbX{+$3(&SkFf9C<0HLrYThk zo+3b?G)4g>r90;=I@ys0XfHX$6gzasTNk8IxU|R7Z^s`_B_e^T(TwOhFzb|5z#Cnx zyxnv!5{EZkiYa26GvGQPSf?Je@ zfU;z*mgntu^d14DA>c4!rm1OE+`9fADnP(%O9B?Ra|0{}_d$)koHi1XkG54MR#SY@ z%RgZs`fK=khZ|{fz23LluaRlB?;?FqiBI2sX0Ce^^A^^zJnKnj{rlkWRGq8Gsa9kp7K~ z3VMdUCx&`Qrxg?Ha?j!KP!>5#j<$qQ>&2=D4$L0x*#RGxZa021s`hBm=??Desv346 zr)r--PVi+Qr#ra6tLkM3aH{q@N1f;Fbn3^o2~Gl4x8LHB&+^l83;diQ+sxpXrFF1R+Z7_7To zF!*wVBl@7SO6gsDF{$9DG|bUjTtm3H{Gd=zOV9`wA@f|&a_R6)`|V7_|yscr%bbdo}SnV~PU z^kt5|%$18%AO1-9)e-lCFjO&*)CHxiTxy>b$-}(9;Iv=FNBC^>8)H@(YDWZM^scq$ z-3#l;i2N0Q(f0d2AH^kb@UeJ!%zh_V4Hq>wnb!+h?nH-4i2)LC&bQ0|UiqVsdAewl zI%Eh-T=oY}6hV-S_$3n$-MLd$c_%qKa{!L?N&jV1kYsr4?9*o;y^vWF@3bEF<34x+ z4Wsc{R<&T=pZXF@?lzYMx-x|n0DrTU$H1nUHlH-V&|Fji9WX0%Io4a zAb~NKyCtV&2-T{7&_s zBBB_4{>VXhQhX%i@qZJq?GmspojNIAoA2a!ZKGnDjY|OHwfRN#BJtXo#X_@f%xWC7 zy!Tjhz9szh$X~=gR{no6tAO*dTKj@?)Q~1A=EQP$_&cz(2~{FA(ShH6L__>$oy6_+ zOflIxFZT@$7bn@Tlx zAIQ|8J|0UGA%w2?QmzU4@%=nZS8nL?>ecYh(gzt_+T;8LYQI1eTdWgt?rn zd?C-f^Y!%Y+aP|`HFKFD6b*QcsI|W+EhTPT48kQjIHFzQiC>2&WR>PzNi(0L;;018 zL>Z1Si?O&nnLN=obyfYFq0hhO2NFwm5)Rs-lXfD|bM82uR*May!+#{CR4jNv7JTHM zLfDW8<<lowF>*95IoG9DO zsHcS<_OIcki8h{mI#Bpl`K!j-5S`sA=A>F?8?OcmM`4Rw#{}VbnzsQ&);oy=kUO#= zat~sr7fesfRDluVwcF1(K_Df*uLL}y>SR#uv1dMFf%~eh#WU=7&Z9s=4qGU(X0Tl| z&*?qrQ$=2=U@kl+p*JdLkhql0S{}wAe-}1`=rer#Sys}zT!O?$2D~M!>2@7XgTMDn zj$@Sp;v-6%_+BrKU5v_2VET^e!dYX<;GB%KT3>VMEq$YF=ipMCFo)INMB|&Bo&)$w z>qQ4hP_1ibMdT6|2`8OzV&SBg%V+V!O)=B(L=#`jPI$^SGjg?6wcURGu`w*{aj7qX zhM&LcW7eNUU}(V~Awd&(&xz~fe^V=FBwf~8zT`SWE|%rV4o5F}O%~qAQ`Evs>SF5t z5uXv@XE#EKcv+BnS>%%tn)BQOj9IdHzVZtJlrbQ?S0IWopthHU`lOnwjiTX$1oq7@ zkHr)8L`wN*5N`I92! zPlOz_6RTHFC|VoI6m3B4f*tgrl6Q_Lmj%}-sZSZebK-g(UvCu@z*gt3wm#5QxV$I#W`u?A?!WaLKG(gmNrDbb+sA zk#}u2VFK)xPHEyZcT8d`#aaSHJGT7aG&5oqZdGQIRD-p`{Gpo?#w}35K1$w`N0jfv z+z};a!uDz8LR;B$!JJBgPiRjGd~$`kNa*cZ#MiiyMcRlSkOtwLwVCzSqJZ7|Gdha) zm27djO|rx3{EfK^(i6$Puaildm{*-?bUHoHr-SdCB^PICXZ!SKIeU?6Kil}OdZHGf zd=e@U(h3KLfzYSeoTpqw1#N}8ZKE3Fg;_CvD*ZlmAUKhCcHN$n3 zC>irE`QRFtivU$wy-m^b0Lpa9VT-{m;n)W;qfbLg$KtWFJoz$Eme1Kpop{i!^!L*~ z_-7XSQW!KU)z98!S<+*^L*JvG0Ci}UD|T?yKvPf0~dL1%rj`Ve5as$X&esj`>+Dk_ZP9icD_gYGOe8NpzG(e{6C8H zc|E(#1wLzyC-UZ)M*>oxGN=rcU!^%va;JC0y&6@IllO{VVK<6ggUAN9+gP>zAr4-k z+fRY?^C6b;S68RbO^xv@?D$f3D|=R=NIgEBB1&-lyn^+QwQ8Eu3s}ShUb>6QwLJV9 zdBpCZT$@VFGOr~fvbiKs-1nFV*G0Wt{o&6PZ#&U@G;X-U0VQh3A>CFa*D~V8TT>p! zaSHX{d!&QG9B07^2M)JF_IG-4+#lR1jE;7hB;;D5+isfv3)gM);MLvME_XL$=t9)whOBb8 zQ+1TPTaFxli=xmsMtD|@n{_q22gf2k1)hOwJNN$6WWuz~W!7n}1DO6xRkpXrJfh0f zgiZGwCA*AoA*6C47)Awd%?hjhBalgHt<^Nk@^=cTld^WyT7myARPUQ!Kh1ADI**lq~-w$Vm$$qS`Ub2@`zR z@4)_in34E^$?v1cC{2;$8Xe+*O2NFWfX-o>An_`~PY7B4WGvVvra`opW4$YiI?~*#ehv-wI_;bkE!WXrB-c; zD`yd^NTM0P$AnVEi0~qv@_?^wvD(w_Cv@RE{(WNM%1~05FLgekd@O03%=lB{q$2** z?ebR|?y9!Gt!mk5f0ts2;OD)Dj^bR-EWbfZ*FT_bGR(#ke=G?AR0^8 zP;a(ArYnz4lIGfFG(igACnka_c#neUhfkCIOp;G*)h6HRTD5mnTGg{S*{Y|wWx;Sf zH)9g)W`%uuqMC-s^pZN9$;8Nh#r_NPto<%F(i`(z&O;b)JpF?4#Nap{CH` z@6sQ4THe+KlI_j3{9S4b_5ME6>-7vaS!F_;HF_MIgYn%&?dSI%5evZa^{@65tDOn4 zuYQ&x>XcjARaOHo?QQw4@EsCTPq4d6<>{%mLbzf&#zupV>5*4JaDu$VNGH2}HKD6YQAXxrdKj9~$O*ShlCydbF%93sy)x)=9+ixXfOx zQ=Zj4egJU9pOO#BCarQM8s*=`z|+!21>JS|vCcs!Q_5HlMy-RqwU&F^KTK=Muzo0M zP+ffbL!M)u2b>&6{eGh&79ki0IQoe3t)Ec0m7@T^_h4G|p)HaN|2l zU^8Q?Mwfalsn_#Esa5wQs#27Ma@KUP>EM#G-&8|I;UO3g6zEJzzcJ8%@|4KCUm64Z zWj18`mNlkM$q!{ppsX*Aj0W1K=pncFFH}H&s+rN?VebQo*oHt{0t;%}U^8m8XQq8( zH%ic#Y(ahzW9En(((rk4e0T-}xD~_iElNhi;9JzCJFk)bVuyXFEJHkmJ^iAPnt6)U z1i346Lrx|+4-h>T9vdl<1n$f>pXch9YiJM*`b&<}Gqh+Wj9#=dM?%?G=9Lc!v_M4h?*6kQmRB^wVL$vDwL(2$bl{8=+dEcll5pdA2I z%p*C>7ufGagkzyNReAWD&QCB@^Cp~d^?3mPbZ!iWqYR74D3XfTIR0SX{HqAy=(F>g zeyb|SE_{s5HB_j$6{qkAXJ$4WW`=b&l%HVMN|Zc%>;S-2Pb~5SDy;i;$qgZ>lc;Y2Dg=+B%cqqRz?(E{bI2iPf!&Mpop9(~RX(-`tWlrd zI&r!O%nG$NVCTZ=Ua}hx1v43bDWWyg)iPNXDXc(gL?~A^VxEOQE-0P=dU4Z3i)tj+ z;B8bulh1OHX?zJn2Wlj=)mg?9y`Vj4d%fIV(8~?#oL__{+ELf=hOojWO)XTZFntAGULAp#?7W9!KIPQsJc#z3TZ zvXt*xqPhahw(T}&2)nAXSSzO-J1M;?OG-D}^w@rKXWb1l@jk0|Ry+giy>+n%)qI(_ zZ(px~e6#%qRzc44N#zNNVp~q)Fv&)2x>@Wg&%ir~kI3i9nsTiA0?&@MkKzXYeu_9CSR2)8^5kWwEEmopMVFDYN-f0U=N-q}c2g%PkS5B&Bo zm4e^EcIK3r!g0bsF++LJ9vJ#JcC{s@>)M;~hu zt0r5v+quqmi{iiDZu?}rJyW*Z3*eF~092sCi`I&i9rrZwqPl<;RtCJql|q_i#n*c6 z`8sDL9%!3k#-0fYxT%!Bg-bgC%$*klq*8H@Hy z$B=z`C{R-ATkDUiTLnG+DBZ;>bvG+jH^F2+`4r7)#9UGG=!8iG=(M+(HtwB{QDn8R zxj=BZS2g&Y$a=r4<*zjO46~XT*rYhA&9ZsKD|KTlgp662Cs?H?r`rAwtu+_pWYr70 zaO|UFGPJH(scK`SHz!uAn&}ygE(p*O5vAArBX==M%gpQOWxz97a$R6;T}rW6NwFe$ z<||dj$~BAtY7|_q3+~B@mFt50gg;HeFunO3h}Qc78L_-vOwrNn{L^XRJ&6B%5%`DG zqDIq68tk&(@R|)y(Vq6gMP@l}3K)^I)qVuNVossS)eMJ^n)2ytaXW~kK_C|81eH41 znAR>Wl=RGNrZd9fzp4yp$lM4NsyqjkI)meqa;3KKE5pN%AzvFXFdTugDg z{ruLCHzKLKDYLnNnq)g8)#$^lgcY~R+uf%UwxjDvWQ{A7PmmF1;D zl|@u@bT-k;S^SQ;#ueC2ZvVQy{>WUg5bIn|cSFDE<-xA;*>}MD<2|}{4u@Oy4||T2 zl0)C)2aqfQ`}_ZdEyR|9%030V2zDR@^rzy@t0>>W3GR5=AL2LplhE$a#~VyH91k}9 zsE&TlU9N#t#;PZPnGamiNIVZVu2GO(bvv_pCZ z@eysabsUL}_aLJrxXGL=rWdQ;7zEBWQ9X|U< z|Nb#2oNExR`TIp?->)IY9&d4{yG&J zy273IMk=hgZ_yR%;G6;Rt#{fMu23zUliI>@>m>*NP{8o8h;hnQ=Jf>8YdOv~quz+q zF7;+iaWH~M;arH2J!#`5{X>}mMa*6Fk}lSm$4@?)MyJxTI=d|MV<0D2Eze{V$S?Ld z<~|H?>gsFM*^I4d)VzZ6@mqCXB^P4IC$pEBi$TYM$WHW;jtJn0qGuJc6Gr8@46B1I zXJaH~{*m+wd?sloIl5893D8P@OIM&JMz~M64}+t=XC5`T;XU(vOR8(?>>G|jObnXu zd=D=(Ui_QL84XH0c%(+OcmDZDYSAdu8G65V2IojQr=sYvAFK#rJ%d!6zCRY9yGzk$ET+7D8ada zF#*1hLQ2Vb3E!p&u0AJ!3L>^AoCRokV7kzh9O!Y!k>hiKflObn%d(y$r~Pm6)C6V7 z6bAIW_)}75o&B4Kg!d__sx9ldBo4g68*78yUh=cCIPpq@xrktRHdgeA5Aay$lRU__ zpmP}Y>EZ@T(`=GFhlJxVCAi|)XtK;-|6FcWO<#CRZdD7f7p`B`*e18KG5qK+i4Hhp zq~IrCfU~{_M#(WpJ*~6HQBcFK$q}{?pCQ4bnF@{rA0A-~jSn$D-2xps%n&-IOw#NK zUJ^8TB<3i2gjMww$o4DteCBM4Eh{VLAd{dVc2NpPrX0+50JMz@3wG)FIy9E3Q!TV| zwaOqHQBH(e7Ct1(OvW>!wL=Kq{Ua9$&uBwQ(nV6;~jXV9ltXMD9UJ}c4#A}WU4o(QTp5#AU@%;KuCI&?qt#kKdl zp55~0A4uGoC6Ii8xG3<2eYee+@e8!ge~0Q6uGF^VVmq#OUFxGUiuj@nI9Q7UR@y3< zN-tgE9BiD;nO(roO68=jH*0;|b{yGQaP0?w!dbqPzS1{Xc&`Ozyqso^$Sbea`d#Oos5o-I!ZH z-&^T!8Z9|^z4>;jQ)^SA+e!yn94LT=fT;V-*#@&lqa5iSa*{YXY7gH-SnI+yeheVh6@G@=w zVUWejDSC~=Tj{FT=F{KG0$9AXQd?N*j#N(9Yh2#StU8{uB9)BYEJeFWy~(PQLvGF= zi#b9(H3ocacUiU#Y(p?AZqxK~^wB~SWYiZT%fVfRQ@z6%n`ob+7{}zV!OyiT(wL<* zQ6t2c1ZbBzvg%aM|g*0n6sh<>h&g&UKU{lHC{QpuzSeCNO&^ReP3?@?9}z5|O^tn2G1`UU53n-;mP|HF<66fS zQdoI9rG-{5n$GvW)HKoC)ZaADyQgV%!k-C3Rg(>u998+A=ythu8yYc97wYMFNJVag zE6WlW!Fx+^Y3XVja??)!EvJ?^O0tEypH4DdU3*fQHzW64;`V=uy4=meGw{#ocsU*pqr4-d%^>8E?sS? z*!ViJ0l(WP&PKI6Uu95nC-7t!E&^B$*Gj&vI~izntaI3AFlod)j|zt8cT=!UY-vPm z^6W=)U};+oo~w*B2_3ap>8UG8@&c<>+k9PPe0xH#pqE&&)A;el3U@lZ&DXir*AcuZ z>f0HpGWu0nG%2kfO|;5}Tij_OaGgWOyKhQ4Tz^RuLL24tud1ZrZM9X#jhcLWsQj~U zm_sEUB8pr*coeXuNj?8;*7LMk&oxrd56yZm!_RxphZYyck_CuWwX?c4Z((dDD@U!+$rRhMd7Iudd1C{9X z?eN@f0qwEOfVdUHeGq8A@mEnvAdE+Qa1!eQMz%9j=C&jbyyek9pm#lE zMErvaawc@>lcbAu7k-+IYsg;M(M2s8>fjL0RAPg(UjZgc1jjM!>lYfgwe~4G*CMAu zM^>Z;zdmA(J!tY@oPIr^Jn2*n;O~B-cZRlbM$~cGyJS$CzhuzHh;%r%%#iY%pVJ|< z&QO=c$d0B zRGO;1ds-F>^og~Udtcc+8yk_COI@31p?=2(FaepIq}aLHh4y>1oI_rBQ@;XwQpkHj^M57_^geH`7cu`*M@md@aC!%kro*Q5ES1JY6s2B)-~& za|ka{jzOHamAD|(g`?^{W z9&N@w=q#J@YaUvg1+P_FOl1zQKVOS(QCa*sf#`xM#&Z`aaD3|we|G2_ratmg-DaY; z<06?fH{8h%^mYo;Yli$JGAYNUQ;N9IdX^%%P6p@Y`;i5X;1*b* z`0~icA0=%=NqyLO3uYYpsxFv!Xq2F|T?y11?0E?FhD7K}MZT~6A0gjTO6ruWHDt0M zpJ}}vE_8-C$iu8%pT_iD%JS$a2) z+I=trHfDL>ZElG9`ecFNUdH=M%P0^X_Q(s7(17<9MDyEj;uwXgXw%u>(o$$QE|PqL zWay^?N#Lq%QMvm1A)kryRb+ydSoV@qUOr zSo_)D-hbu}OSgCB{%7P7L9R6H3|s#_nzqZPefJiY>?1Y`=r6Y46hFCw$HWR%{mmXi zmRPUCGz*oBJDN}lP&1WcI5=4?%52W`OW_GwT#xQoOs0Xj=CP7~pG=~LXoXS5AoA5= z{ekIWz znZHVl6o>u%7V<`F9L`U}_rXwq6`P@!J}R6Y(ul?;+bTrTShJNd7!8<~Kczz2hpD)4 zK=6eNAhgdjd6rJq%7AfIN-Ir_;MXsk<0B`d8t+tpWq?&5lDJVFpy`mw4t>OK zsK+w!EvEkb7HqgU8eLmJYT_+gbUF*Uu!BGm5#I@{?;{mQ+I_w4zBj#RiK^^7E?<7$ z`(n#D?~D2#vS>f^_4eNEeKFE>LO%_8DvwK>$azeHNgiQ4jPt&NC|c!wv-eBhS75z> zD|eIg&EBbr8kO_WBRZZ2pKBSb@9FmS+Vl@8!VWcA_JrZ>}qK$v6t87Z(lQ9xxf2P#r=Oq&fS=>!foPwrM~W>4zA9=&>R zJv-djQMWAS*e-R7W6ks;6etyX_|VZLddN{{u7({}nz>}vdQkkX3c-Q|?F0oxkpLhE zS4;dS%E{#GBa#A(0Ng>;*5HR(@}(_Jc^!cASgC3wB~^t_hYr3G-lJcm3n zZ%-o(t$voQx2NeKZVJcDTrjwK6o^}IM`S$GLR<}j@;*`@%aAJI8!1M=0?Dd3B;Hxp32ow9T7V zt35>tqgK5O-XiHCB0B@ndh4amo&a7V$N~ANq$*{Scwj{0G`;D7L;=4l&Qc5Y7%!oE zA@nS0-v$CYoxpY(E?~IBT`A2o-Yns$s2(VMzqRRjTIgcbm<>I2M01bzga~3|*NGBQ z<<<|Q7;n%H0Yw)={7*JFxdKIFVHg^vc?n>oi(T=bmKjgIlmLTCXmmi%|4(BAd~~U* z#bnP-L#IW^dX!mA0z4tXR?HalTxLFmF%2u!_i6P$kXrAj)hZ`t;_Q`XQ~wB= zEfpp|;v5X8Mz`_3&zS?LWNoaqGIOn&iUUbC0yTajXLG99_2ILb%~Q8*a?uc+3;Z5N zT&W}6<%-z1G%I)$8WZ!g-{LK}9Pqr?c{ZH_n3iKw&n7Cw*Fxo@8aR|t^pVU+qa#x5 zG#>v*c&sLeRk2TkR|;A;bFBks4CmyQ(fH?cRpV=nGkjKdH>w8<-9{5Wa-uFGrGxa8 zxhvV^RRLos4lHCK_PT0~dkJo^EQ#Hj>s$G6627K;Jghfu!WfpFNc-`aKG&U`30XbX zc`fFx;t&PWT!MP$a%Msy30WP%xwchurVV>J~47Z|@Qn!A#_j*{fI$&#!)0jX{2_H;fp`TDyTZ@YGShbug3=2@r zbAzq`+>B}!{oQ3Nb=XQF+nu&TTZ2>7Gnj=Hu6nr2_NVDwcuy8ab7)*`fjr}|sM=2Q z7~P52Iauh>QqY9ft4mCL0sTPU^Y>#pLMKc*3Z8@R1Sc`eg??*MSJr@-@WgcK&frXC zsCUb{W1_XKk8`tI)PZ1`ZGDI?ERuMZMC~bZXf3sq`#ag<8if$5h>B7nT((DYA6}O zk(qp_B(o-pg=huC8>fg?sp~d*;~Vh!All6qn#&~lSNf~gSFNSM5z9CXHl|-MWCxD) z6P$A_OI?v>><04Xq({2R@lLD@gjZ<4%391biWj|xUmC?YN6*7N5|ZFj_NRQ5RVia+ zeuZy{*xvYt_-y>eVN+yhl~J;J>YMxWdRqX8u$rHuZ;Z zgVXPGhn$7`W>jS1f;|qbFtQ5~XJqZm#TnUm`Hpnx2@YC%w zFuO3)3mCgUQdVR1;Soz1o!Zy3!Bh#gakL*?HFR$jZ~Sm>E80XFy+dr-r0-GRLjmK1 zR|J`TNMM8j`bvFo%rwV~IIU8d4@s%JS?8bSZ9KF+KK*wA;~M)YcuX!U&!rC{@+Kht zHy)11SK9a;5IBf*xUBJvjSlBXZRgUop%#;{~WZyhk3ja1r)Oo;fU?zG-1=$Vu` z`Loc4vWcZA1mB4zo2D%z@Z1ESm>E|L0O?Le+h$RFM8%7bR@`d_p~ON=Qt8*D%jMfe zxztOsz2caX>+{53D#|sB1|*p138VW1F_*oU4ZGL)kGD~Yh|ZUiwV*g+@+Q9Gze3!b zV-2&os{}5&=MYfsnTF3JBDfNtQI~OA5FujSX9*g#E}O>h5k;A)d)K+R?@;%h4Mp7d zursXJfluk1anl0D2+PC|{717$@}$aF0fvyf^B<3i24*5mmY4p}WoG_@e>`%wY8K zN9Fqgqk64spGdOS;J-ny*iM^hPvlWyUc}nc$R%I)_5?3LY9@)sJ6ABIJ;t{C0b?qg zsK}`05v^{mu_nv5D0+{yWl{XmC0y87dQ>X=y<*K86=6{dP`aDK z$TMl@@czV7OJY*yje-xYv~*}aGrPAD-lBtRh=}Ze<~+ud@UQ?#E&pKcY8%QGzDJnF zWs=^*&DUT9WLIj-PypQxIILWqR;4XF5zvXmwuGR|6K;Ewn>V-#QR#$gv5*u$0~5sK zz=WFy3>2qiHf};K8IJ?4#)~WI+N8pcw)gd?Q3t(8R5x1#dP#o#a2;S*#Xp6owm0?I z^YINiDD^XP-tCqXelH-om0kUaY`+4j_&=p$buKJ3*6d3Hjg&F@G6SW03L% zfaj;259K4yhu^5|BhH7CNh4t8HHm}-tjtX$Bw(dxC5(WT0~5`f6s+9XGpyU6*5485 z1H4k}OhgmR2rvCuuaDQMUZ4AX7}@9FtIQ+%yufN{@=W|P%hZeD-m(zqnhWuOv7qkb3-Q3vLi~)Sf#uvAcXpr8>DF(wsOx~ysIG&? zx46P&AKAD>`{oY;1K~tUd^6u89C2>FG?z9Icckdp=iwlw zC@*|`yoH~W52<-G>iHI;eke^4^+UGzki^M4pX0=S%dr*Ksdp-Tar(yZ%pt#DGzd&5mN(bq z%_jN+iM6A~xN4&uf}l(T#>4+E2EPNw-}lP4(Aq@NhSiWGY43Gow+;{QOUPor06`kjzCnaXW(r!iXl_jh*Mg8A=v+JcvcTc)Jp zlaHqFKt&_0 z;>_xFYW-zut-W6|tCZSQMG_N!hpLZ16>ia9rpnpM*MJLCLznT@l=6!ukkL_WOk@a0 zV|FG(*cmftcQmub>~6grBxRXoFm4yqS7ExQe?7n^xlZL3`bHZ%pC#VFh`7*G1$j*6ECLBw|& z-}tsO?Q|LRy&Z7%c<}c+B?7TCwPcN3q@5K`TZy{+=JG z#;bT))?odz4Y!YG*G{vglbe4-hY37V_!~QDc9}V zoQj?JZFjuckoH913k_+#lb&dOk&EkzqJMB1^+aHB9qm;C8I5ldpBvH!UkG@K8ECi> zeG=94)2CF=QL9AMw3FG1gmw_b#5nYZq(6krt3Cc4w6R$Y8koNOkld{E(&i1U?JI9bWT{6RQpxu{mRtA1+v};5EW%f8Bn)4 z@~NrD>4?(5lE7K_8P{%+8Qu#$cAqi#PSybdv9=y(mc(!VF~V%F5p zOId9O92w<1L4g8y!q@$%AHXH~m1H1(;a*vh{7LK>&K!AjSdx2ElY96CJ_4kEk^GY9 z1hXQx2dw4Ssq&=6XG3Dx`vN)bB05x=ziwtGCZN>{LoI*#$cd!ahD%^IpBzVdlpTI> zJNGuZPaILt{z1)8*ApzXfAA}%!`r!*a}D!L%#j*j!Kboo-!BCx8Hd1N#-Gl}*$^qs z(@XOTjx!cX9{eBJ4avudfkWfgNiJ3mpktkQEX_UR=bZVfuu?BM#!GtG2|BN zM@4g7T0K~X=R3w*+%OB7EyvDs@w`(ZbdjIBCyYmQ?4`+f2?=WYX-$djEOSu zzR{Svn+1+K4yOCTU&_#+?La`XoWIM4+7-)`vB4{FfpL2!ajz4PV$eW` zjn6y-&`xZ_dH-R8$s`A?NIM9=P438}ZV}D3i2rXFf2R*Zm(!$!z!A|F5E6RNcmw-;3G z!o^OiU@MpLd#A!s5VN=zD~0qA+Y)sjQ1`j~1vh4FV{LLTs&b~7q0Pl(tS#S4WLUGF{V1+SB{{rTA&uW9^MA^Q zLCsq4W?$KAqtWfG7vo2_D#y^~!~DBhulGo~N_~(GpBXI?yTk%BZ)CEu?4QVBF1LH6 zIE*y4-fZzlWkCv2W!99wMlwoGpM)tyqtXlG!N<>A z3$;4#0QBWgB@I$lr6x#BDfT>NP%4AG9Z~Fsr$4RO5mjvO$BVV>|FmMqRI#3q7b~Zj z9+izJRP{MqtKuBPc59Oz8!#SQVlK}QnIE*VqK`^4XPY>N%ij+JIFl_ad|o6R)>9AL zRl9nRqRI)ms)CMgI-hZ4S+hguD@p}4!uyvqvgzASQDfmgs<0I6V!jSOrZ%&%7~A^f zizbD9AjLl$!#aCh2VqRd9hOgN+bWCv~-;;S742d6f2>L&c@_JO33hTJmTs){xI`DmF!Y^avd;yuJaLMzif{*%Nmq9C8 z=M~%-(S?CJsz7dE0P_a>!MD!FSI9}N;I#`8ut*`a1*!6hT0T4^l5m^i2ul?4067&! zHeCB(osS$Ie95@vhQ~LKua(+_(lI?d(+vedYaJatdmQya^ zM#|x%EL)ib6~-nSozAY0G~ESJ5qT7`Pu$ormkGpuTH9uxFbCS&F2JrVS5C<$VIINh zI{j+Q*D4F}^eZvbbEqjqf!I?*loLvbqKG_JXUtrgV7okYn-8q*?<(flUHY6nBM)Yg z((_Q15t<Aw!0J>2I1b^DbH6+oNqVZ~@~lxud{)$9V+-sC_)0dXNXDpG|SMv7sb-{#Ftl^Up`-`Vfh5g%(8w> zN|-N6n$cTs?nb2|c<=8_bY%!7WGEx98%#+W|InQu`j#+hGbrYSAAXh3>9CIwfv;01vPQx`!S_{ zDt8q=JF~J}aB}UQJqk7M2Q^*|`gBU>-@?22EMstLQRQOO*4&u(UHA!z!E241bF43B zna)s+%Z5Iw#v7WJtt$RWK0BRb-tYm*v57@y2Q z$a;Y=q=S=a;o9X)qxh?M^NctxNS}5Tr1Jb|ZK@T0ro_ESI6Dx9DQQnB9);o+t4D$#n-(IudgUyAPp2_zr!ACqdXLgpafLU|u!oe{g+m3|l@6-@Wx;QG zr#9RyUS3T3Fub=caf_kXl#AbpdgvD?*p3!Wb(o0lfbiY=bpK*jH`brgx&o#R*x_Fi z0YStfzX^gxCPP3cZdjKCFir)G#%l$q&0*ljLM}g8qntL-|4(q5Hq6_@(AG+vFJf;e zQ~H5WDK5WBt(>T4Tb2d%T6C!g^|JY9`(4A@zc5R0%+>4jBDJ5WLM7CiIO4zYmO*A@# zCYo;`(wtk59@@wHqf@dVz=+1bzm;xKYDhg;`inea1)@2L-c;(s`Ntp}?jK>s`7WxX zIRC&5v-V#B0mGetz?~SZGJbZ0(AcR1NPT=Dyup#Sd7gM)+Ua+a)qpfK!~^oW~q z&|T;^666UZvc}8jhCj?~%+(&d7k`FIzPyT)~%w%EgRAd87 z%>2F_^D{o@dJ#|!FR^WS329$a$(w45-P+Z~SqkwjkjHEubJQaqg5AZrJm#s#iSn4w z;}rF1-(_Rm&T&3$EJ!EkO)^+3Tp^({i{W}O7PcW~-SXp-3>RrhF^5-zv$y=n$$w## zcr}6F92vj;+SCKcSkUb50(F>-zc1 z3X(^9u>2+7&F-X~?!}$x9x(Sy_ecv>sxyJ)byqlLxJnWv3tJRH@oe)ZpMG8dc1YgaE-Q@F`7 zt)n-6m(=kUCi0kiOIV1dYDPC99n`M=yP7_6BZ)r_YwCGJGu^i^+b<`}sA)ILoEj>V zmslTG8CeoXl4aD|Fw6XLsLYhaB9bz|aXd;C2+Zr+`fLy`z;c;xOCGZHur~F>bxh21 zTa*|(6R%sWXilhf zQ{N=mAm3I|rN!B>iS;F7LvKY0%D4t3i;LnZJoQ8t^lv1~=g*Nvfhgo0&0J&jeVFwT!LB+mbC(t>Q06Ab0Aji1oDwRaI?g|mC z6c$Cr;O+v(fr8tU1Cf7%U4 zwHuxVkh0kbP_9z;@pu@P!U}`5bdtEQ?t5410kPqU+tKx|R!2CF1Md>0qu0(28NZn) zH2_opVV0;Epo9S!e^W~Ap~N30J9R0k={IvFdwwFj%GsN!dw9+%(dH?VIV)P1H7x%* zYUX>dY2Ox$;6>OI!{K-HL7cSnmqqbaRQ5%`U;t@zs%p)T4X>$hK(JRa_N+l?$vl@wfPXpfSq^II1qRu)sm0FqW5nK= zN1O(cCNR9%wSKG^R}1hb3{WCx!{?Ik8_q|Z$~!awi*wnl0xe_#s#I|$lz2h<$Lx_n zz~3S27}gxrm!VDdOB-OS^Eg4G%ggGR>X$aaWA{rN{L%)=y@0LUsfC4?%hM{^%5`kz zziQ!^NmBBWrJUGH_wwuH*QH(EAs|TGCW2UzIIecq8aG`gnlH+YM?{LbGqJm!fLjnZ zPAez)Iag}j4e(WK@Bs|K9&cGa#qirG*{9ZItG79cx7m_x`84Kju6mo7c$;g!&65jn z^Bd@L&6IVYi}~}-H&f)o-q$3o;8KWUCQo=TJmCQ?@uY?p`xlx?6Jvhan92|se#&*yh0x#d**Pzzt2a;klWvF+Ew!VwX8Ud#EYhP9ik8s_BiTHy9JnWz=) zLSogNV*<3Pf6~H_&~7PQuN$#d*y`I8?*w} zFDcIFzWj>>Bu;8S9o!|_PexMvsXXufPAya*dt^c;yMl>leY#nn6UuURe?g?I07r0^ z4foskCFi^wGOY1ued_32+WB9*ke3LY)9cwio&PN*eU*0AZOq#bU7iKvx{SSS-w zD-*FWU+$(P8b2-Bc(g6Yscj`)QY1jvLO4#5-=>{waxfQ?{at@?%y6 zpPz@>8jL=nO0nG{a6?&EWMOWkHcy4a%-3rP_&{9DDbSgbh549V*G@6^1EmFzFpuNw zf1a2$GlFKK2o+KUf4Eut!d$(Ks;HbBs>(}N)iSKAw||zXik1~f85(D`jAFDbpYN;Y zX5+6{wM;1BNNsMUF%LVWf??I&m#mJKs`Z{(_$Psq0wK$CV`U2b)Yln}$&8=`iSvbg zEEqWiU~dYMGNC9}VG=2{r(h7|hyT_j5i`+0L>~e7HOc{$OV@A{6EM6;W_wpx)vTUx z%>Rk9kb;aH%L4vBQ=lKgi|SF>5$LkOAiB=@BG#|^b&-o<2TnJgl}Jc<6+8F)qY*`~ z&oZtzI2_l{Fs7+%zHt@T8skz`w;Nhk6Wcw__!`;u%vjNMK7->f6{i$td2B@3ypiXt z=@no6shOa?Sb=t6h*T3Ro?%{4N0O%^xpWuLw#ABb<<^S9m-Mx*4x3o9IyYj)V)~!9 zDpow_A^GcD-`G zy!Fc>)yt-{(#Cm9rz^bQOe@WuS(Y0*rW3|xUJkBMpM^2=x?T$dq9NOJ*z->Kq_}rV z_hz7|if^ZG2MM@$`as+}rC*;B+7$jkT3BMc-fs(iGyH+Huq6F@e|qREVoK}WR${;2 zZx1cj8*+8nSyfq`Z`eP%*VihSQCCQ>J(kO;&q%K?vRp=ulU`3ST}A~*t2hMGvuJ64 zAX=7>{x6t@i3MTNT(5d4`|QLIQ}@|bBEaesZ^cB!j^csk3%B0=TeZGcUNjhQ_xrm2 zvxmG?%X<1nkPI*?HG&Ivk6Ob++OH((KDosnCXGM|1t>vW`a9cyNK&7+YYdNQr^b!V z97krE^j;VGU8>Bi^w8;F$X69(2;Q4hv?A1+=X>E(IW@I3`}4z^-M~q0HXG<7hB-uh zA^fl9nIJTsWhD`{H$!6zRLDDF?v)&M%{Q{R))?bdm2M%jW4Z9F37XdZGAEe zr+-^lp4RTe2}b8Y_GO}RB#I$Ce8ze(Tc2Qe2-hvY8@D!`Isc*VQZh({tUOuwpY{c{G%jG zK=>Z3xL{sVyl;4M+1zNS%C`ipig*u(A)ee&1~+Do<>dlGl6w{)vKwRsmD5!YnOopG zGN?E;wFekPt4F~_RAnZolPm_a${B=LpNxcNH9C5S5=r^nd}G`FbJ1IE_xn*~ZTFYy zz7y?rbC$LH%kk5omX;d%gT}Kk6=bGvf8Cs^b?TaLtmax{eC-~kflj=51xu1(S*;Hd zfwUW_TZ1GH9VJ@ZjXbk( zO0DMfqWU7o$zRnq-#E&(#(4g2)f}~Iu;GL8ZXRyIY8L8N_0j=!8O=GiAG(g+)uCS; z$pk`L$ClkZww^YQ^0|0JmJycv8)g`r)HUB|;96zeYJP`9YlX}EbnwecFxyZdI{yth zMvI(b^K$gbK&kWf(riy>CCe_`Q<8(fTfAQg2-XA|ggf(%cWFoKrrBwsE0QDibASc#|{7;ao|>~Xtqt) zww2CpFP@w1^xOxMonDaFdD7APnyqz{KP~9ox-aPXH<9Z+t7oeHti<0*;yx0~ z%XF=Eqo3Gets8mi)gCLI)4Hh~$$^TkPT-|UQQsta7r+P!EFWpnQ4VVzK9qZ#Z&G`4 zInD76winN-$FHftIM%Nm&q%ivZd9p{H}=V9%}{O6h!y4V#AB=|SKW*!xVJ~V=jKV8 ziM(*5&<`mzR~7a1x30UWEDe~JfvV+veMt^>eH{13-@lgt{<1hff7)7{Uy5WP&9W9} zrnxu|8DHX?apKRs@d}Hxafb1Vy5<`%aIG~Csj3haIrZ^XvN8#feu`Kh^v#0aCjKW1 zeIFFQKeMr@d4gUxLwD^`uE_n~#-hz{>y0z;-dR>ucr@zxw%+4881A%po=o@lX=VFC z8d=#FU?wu2>uB9ZXm>a8u9Sn2XrJ>X5wFEMKV?~(F&I+-y*+A z01Ruq#YMds^WfmQfMYMdKF63w%k>557O|E5=2j}p_LQ-ej6a)O$)5`##r^Y%?_P@{R3yKicM>-Cj1Eg*hIY0yoWNj%|Kldzp_YT65dW=5q13m-)GrwU?D~ zDQ_<;=Q5|gY|h7>>2m^xH%?CrO$u)$tjvV)M#9#OwGc(UczV}=Y~ajH0JQX?Nbz(g zZv9({zRCfr;NviTV&To85m4LOJUcCTo_XdA++BBm^0dcOU9{OD?yPVvqZwb(VY~{=Ox!=m{VcSQ4WXpusRtVyS;PJu!XasQ zw9*}sxO#{fcJC2$Emu2j%{dgb)#Y9ZjBkn)vt+g{n6WD6hw{KpZm3wVD*z-+wV&}e zPiejkUm1GmkHW9p?R)U3B_R{1hzCi|e`Co}*?q_=^CQg#`hxsu){ltKh-*sUkPlMG zjCgZIj^aMOv-tGk_N)T$q0RkzsQ+XGBe(s=>|olh{DSh z0aj$(iW#>xp9!X!@i@NFx^S+|yuF&+^e1FCdoShIVcuqQ>wH2@_c%3vy%~i^WyGV? zUltOq#`q0?^@TZlS@!8?XmWd&O%dr?@v@vN8`WSj#@%JJ@dieiqYEJ1W#G!Jfh*GM z3!)7+Z=;MF&XtCZTA4X&jrqnUD6+|@2^}vS2>e4d7O-?3Kcat@(AAlCFYDn~{C>;t zaejOG9pd)_KWl$0`L1VaoAK@HqA^Y2H`0l2^SiY4cx- zPQMs+$_HK&M%1AAU!Ri$+7NZkuy@C?irL zwTlN)ij=tZ1+K{4ES$y0$@`Gah0V;8P}=Z0Fjj>$&Kx&ImLvD78P!(_?SS@*I-Q74xg(y4yb&`d)U~ zhKW%}i?^r28L7#QEXeCEB|q^fUo_7$lNGHWjQK6*v&kkfN$!EY7(C=WvTnd~? z{~?pIh~|SmBW{QbgX8god-g}+zuP=}^uA}#GR2Ck46FL;P6fd~TZqnPmb4z`FAKle zy?#pJv%>ZNVMnh>$BG?<nPV)k{zLXO3YeHs;0gNjvCnwk1tr+> z2AjHd;gwc>iFD zDlsYO44)=)Y;6QDxKgONK(EY=qP$iNxZEBd7QB)5K>yKaVctg`raE)bq^EJm>YGW)*7t#9boKXf~{^R?`;ctL=86c!p9|F`#NrYXNlR%B4f zEn^jFXef%$N9_D?yA&|0R8nqgQjtn3NKN{@Bq^k4JO@Ulr&GR=Z5B0=ow0)K@CmzF z*mS@oiLg73x89>IxI#H(oZ!v^S_#*5vR!0+EP1XaV$sVMhX?G9D}dQ2E)JUFB!4yn zk9>YJV*YYj80<^%u$jgym!bx4I;89MAiI%#*<2-WKGzviMlUOm_{)385;Ds8*Gr(# z@%@Vek$*n=L=hBl$`(ibi*f0_q}{(nFIyh*FQ?>6O0FbvO}l@MUKWh_gW@(&*7U0F z0ot|6`u&8f>WKA6t@oD{M=d(f5h*l&GVRaG{1wgy+gNq{(i~owZDOHfv zx|6R{kvYE54~5SP5}_aRoMyW?&_+;d3AbNeBC5?FIyRpyd^WmJ{4>kzYZ9+D^R;vH zNhSF1QbOib>@iutg86FVRx@!MJ_lewXav3nFULRD1{psVjvHe~qL)PMSzwD3UUtEC z=g4tEYL3l?BXcl~RFg&Lhw5FmeKeoEh+h%EukuUG3G)Ge$TAsvM?W;}sPXt$8Mg|f zyUc0F*{Shi!Jnl;%ufjY*9yaUknxo3Gv5^s5`3aMQ8)g5u8i{Hv>?$N`=#yag3$Q` zSkQ&WNfH~Q<#SL=S}jU({UCY2_=djPU2_0)6?Y0@=$>TX-eUp%p~0B{?KT@kHU*{Jkxu1FHQyMz&uRK*a}R zlIX9#CrR`tI2|Qb=r&42AN)DQt#k~f*{zAORaT*acw?UNV;Npk$(kjw*(D>qHPI!R z8Dqmm(xocPi1h|hGnOvNyY4o@ZdI2Kfp(qcw6?O@FHY%FR_S&($ zAcE)R(k`}`c)N2&7pz1*K*{(;zrZ;NKoKutW(F{Q$zd$Y6dMfaPzlW&l-C0C03pNb zQnmP3s;d9Qr+&$A3%?LQ*<(ZPG17v?5^n4Au#q0B_*gT3&*xH`K?dr!z9wH*pRn5Y zScYnwgaEq`LooHq+|eoDvjx5Ky$kuHzGpQxwF6dlUpK4!8`T|P)t!5sCXQ&}$G(>q zoJZG!1@b-7P*tPoGOM;mQK22yC?*Fy+0(=rpZojYr>2ySnx9V@U*>x@^S$$OVC%>^ zuA%IR!5zK`zF=lZu9EHFrkb0qpWIuYQ{O9Afc$noHvbCw7`!$&l!rTjdceC4bGcgr zFV0CQFL(GbE3aI{BEK=* zOMlGHG+skT){qn}&IYB#cWJ>$eDOU;5?>UD&t1E-umJ7aehY=ZZ2d~P%J@_|nKN{5 z#i^CVCnOkx(0JU4SFq2uEC1@6y969ZUg~p~N8o@9Mm1_%$(nXsiaCso_b__`>`{Df zy*dY*6kw?^H_}ovwZ<=8G4XQM7nRj>*Glz|E7jkL%gw_?gezv$)Fn&~ zB(yqxudE?7;4}#xgsXMq z^cjR-a$@Zs`be0zBtG)T=EMmJB3;G2XBvC6L0!hMzV*o_hK#NW%spvSchOj->kh(9 zWIumkn=dQoUo89)5M~SN2mtT)uK}J1N#{exSCZdI46V8<_$`oM4-}vz2C^>ZPpGJ( zeaLl&UQ`e%E+^D!Pz5fF6)#ro8A3rXHkYtC5{(qArW8w4+KZROiq+{x@s-`hw4qqF z!3^e?{GNP_$>WPti*rS}Ef>ZG>!vtYQgcYnlhiz-IY_E#fS7q3M9b97fX%Jad4s$t zo)Ie+w|!~7mL43W2fZ-UWeC`Usm-+7|KGG$!8gusp%_6HYa{qvy5Vy0Q=7t1aSQ+k zIT{BJa(%50kV#NnZR;c&f)HE9zb*qKwFO5BTKaX9mI~dbHzNIVrU$>GUpo@4+?$pJ zD|B;#z;#izs~?MkRjE?7`?d%N<((V@qG(e;k6bG-6@ViDb}KIvLBIr-b4v9A%XWM| zC}qTCxr$m|ZxDqZDd(1QJq-uAYn1t@=hS$w;Sb!k$f@xyPK}QmeydG=W8H%oG_SiK z-Jf+o7tO36_hwf`7iJr0o@1eoMzy8ND7s$lr`B*wU{r9T49UT*){rR6vP6_JIZOJd z1k=XSsO9{=&M&bj6?_{u-f!lO81El3&Qkf>MCDuWqtoXY?-k*e#ddf~VM22r#X!Q>H}L{-|IJsao4E62v_OQJYU08H1*>+fP&-w&ta5s8R>J>4?$W zDzkgU_@_I}tIkzXeP1x+R|$n@?WdI%L2v{)4ntoVZf4zK`Fq5uu?mHVo_YeH3^1^9 z5qJO|E^LTmbhpYQ#Rc2SmZ0DU0oHEYMNk|exUSo1LSvV;kyPR($wV@tsv-dk#wXK; zMiBb_DJ`OJDl-Pl5v>;YS7p0HD* z_1O@I2aS`w5>3NjaV0Kr6~lhY2!1Ft68tJdO8BH~<3_eMV?(PrRE!K7MqJ^OIz?FP zFEZem$a>E7@NF)y4hM?4XaVc6Z@TEwg*ARqiET9E1(mP>3sgdnzG>02*L{(n+ zgHfUJ(Gu)q1IAZm4DiAZao)|M096`O%c8&GAEpSjhWl3}OM=d9Nmev89fB`yD_(Lv z#Ld=kOXC&tJV%{8a?s@STOuw06ChM6w|T&KW~-7{h6ku(d=gE# zLg__}DDSe$-aV1owvS6bwsAR|1o5zoOmbQuq5Nyec? z{91if`)5kZ{sGP_oSqLoe*EyiqO8CBU8P!7I#?AXAD@pa2^mV@R#;h9N|vm(Kg1Hwu(I^O?CX~- z*PB_y@7Mg&=+|}p5_>_ev0?{xrJ-P1HN0$~l2CZW*TD=$|2^#gk-~MH~gJx7rHc_7xtrnz%+Bv`Z6X|KJA0>6-YW zWUH!Z6_l0flfWwfR2}6DVvGkPq8uY|l4V8D;aSNlaJ4iCv56HC=wH{W1u`^x7Ct^h z?~InC+Hkz8CRU`V+nDe&hXU`q<%?GQ-B^(+k1NVDv*eiX^2|%Fx|mADF`LR^PFbwj ztfUwQqSRGnUS^q<%r>9qo0oF)qF`REC}3t;VkWLMFN%rB3}M!LOfMIw?1ZAumcYO0 zXRRP~*r`Yp0dbEI1y4eCDu>=ZZTp%p(0x5#;){m6(C;#A(Y0~O9U4Gc%4gt(Q8FCx zW|ARBO23V>Q!4TeN``*e&WH6TBOdChC3b94hVY@E*N?)fPG~wj`;%W4ujD*9@&c8xgZf~$#~bDwA4mr=`&wWF=_=A5 z?&Q0%(wo)1l-?+p2u?0bZ;h0$3AZ>=4m%cXL^2dGT3K2|TCB6fE(34{v^5LU%AD z^A_X#dLPPFRV!O(rQ1UG_`Eem-p*C-X+-2SzGJa#;9K>Fo5hmI-5(K1S)ma1&Gob}b zD1!%cK8s{UA!kcI%PmRR&8hh=B0OqdvYg++Q))qZYduqtc}lo*q1?O~1hu!x*Hn%r z>3Zo5R!|XP8=M|x`8HRrZ<1Ap#VJzcg4)j5i7lQG}9O>T_YFeTOjEz zE`>i50?YDe0k~Fa%`svBt}gO|JRBb1?McxMD1)AseI{|#FOQ|tXhFoDhApY8AXYK_60g9O1Q9k z6K?MMX}@Tmf>ZV3@U>6I$oRuIg$)|afcB)`X&v%66`hd!1;y8!9r^;N{*1lJ>HV-} z;_jO2>gv;PiU*R5?R&ffO@v0WJ@bM6kaxT`f4p~rGZ=_0aC*mwGWBKxwuZ)58ikK4 zH5GlJaNo=Yj^-T8|7|pDCVXC0ZQR=&w)XU5!n$tm<;m-JN$8QEKB7uRnu%Pk(04UkbMBPpORVlIZ3<-M{jEM>-;~ zMA1aKP>)(NN*;(K5#idovmWQq{KsXV&fekB9XphA6`NY(Zz#*(33FWfg88~%dN?9C zG4~uh(362_F`|U2#*kb?%on9^n*!{(DO<}YT7$bHAN|ai2;iXQKZmLPx{18=!R%Z9 zya`+m_tJp6=UKsICgzb6%{FE69bnT0JS8@-tkPeJmODI0^cSuSp(tGtSusU_RmX1< zu1u#MqdwPU)0?AfJoS!Qhk|X8N|$m}yNd_6a!4=fgk-=ZhZ=40Ov1gk&>uyt-Xv)3 zGWl>GuV(+JWVm&=gVonX9Z#Z~)cZuTbKJ=OtH!?ttIJ(8ua?dIS@Bzq@1u)bWy9&N zJH0P8xmkcN+2?(V4QK6OS!*XTrbtELC0Mv#2*P_^t>QPeHfP#H7w8KlTJl7QYq$_& z#TermsHF&J(wAzCjlVN@)@e4{Vc@55;?tH{+t}PM#GAxNev>P`4n1>}loq&apOS1; zik5UdkiXLwgh%6_`bBZU7`jTb2CrwwlVL28kc+aE#YTQ%949|BjLEa)izpqgkf87r zXZl=7!#3Dv`kld1PYHis<$A}P%r!J(GF}3&T!1Fok<4zEqWjOA@h`tkLyLQ1pY|A7 z4gQ9F{c_-}($*Zu*hQL!%h4)B->DQ*PtJqP;p5={+SU^8YXViq+xVryhT-H?o>3ru zU;EBw+=b6NwL6YcLHNUT?XKsz(Yr4L2}JX&Jlr!-q~(9MZz>_)Uho{&PkY|mE$9Z3 z0;7!%vHZj8C6q-&4(na|ih=FiIWnU~94s@g;Ut?;gd^^=Pvg{OmG&%3#%I;_U2RRr zk@w^et(QMXM{QsILr$iz)1BrbTmgU6F_!S(|1XscdiQI05o#>XAhO(8V6!}DM7fkG z(PwF?=L2+QS8dlG%gT-x*|djW2*25?@9#Y6w9B9N@_6`dTj(`etExPc!i;#j(F6`& zU_WbrMSE;*I-rr@e32E|kqY<88&IzhrrGclLgv#a^C?87%w)DVgwvoUHf?EXGN*Byyk-*HWXiyYV$6zk z?=(w8yLc<9uz3F6Q4n39j(eiRoyOSk-!Il4?&^GVRQUBTYY(5%9)2!twCX){IQ(|2 zy@w&_e9bPWmUGK%7Z2d(om>0Z9zCW~j?+}T+>Y%D-!_PhtAABw!P(HgGDuDMRU#Cl z^U9Dbm=n!uu)l9V8$rbK*qZck2cv}2yIXmf9x+4;K3MkmNs=y0TAsA(MAL>@EOC0$ zvC^mPX6PftzP1?UKFV#2Cx*4R=FaW z`Z%JFJvdH~xSl24_k=rK_AY@Rgk3}|TjnUTr<=v84sl)byL=CO(6w&jqoXeTY;YR( zBvnyIQ8ecc?|TiGf*1ghgKlg%-+f4IJbLS8?wsLnm-oGOuM2Nwn!Rt)n#ANepHu>6EP%h&-vj*kwHv>^pM9DBry#(R! zr364U=TpukU1HEXLp6ZN3Vot}t(baF-2N%Ho&-l7vh}<;)z))js;y_LHLBVE5knC9 zmyZp>dXg9qm@~`sGtwl8BQXGwD#%>m?bbw{lIw?M{2#I_MF|%Mx2I4)*!F(&Bz4}D z>74+Ug?l^@|1Iy@Php8%7qPR=3biis_1!`O+xC9TNr=roXw0Ur1`D5c?UrJSO$9`8 z!~Ew_e^py}gcFdBCOgjO^!gpmSAYiSooyW(?col)vNH(8uVtYd{r@Zq>n=GZGXxj* zJ3VJ4f~&hdyS?0|>Tip;Jiu-p-U8-#n^MkpF~?#Cj1C(WxQlwv`3-+tImm*+gd-2!*+~RWJ6V-S9!D5`a^~|942&?WGacz`lxZDl;0DGIardKi4X&rm;kiz)SM9|pLfTuFYlyFJ{fM;J9xG+*v()NybXg5o<>Jdqp?-S<$P3H3Q7^mf;EJ&dQvh;)?jj+_?|U3Opv!P zIDOr;c%#F(2OCxPA9&$;HHKk6L>e&$5zG`YU)YiQ1U$FMr2{50(d>-Y+q`v-=F8DI z9&TXb=Qt=*mO0lNPpOJ!$7DoZEpn0&&9^;)N+#w{{4==0!q;xANZF_szB_WS4ywHh zIrk}hwVcmVm$g?>DY5qI;PAbQrNs#3gBCGf5Whq68L<`Ux1rv&3i3Bv-M`J}UexaE zi&poc8$u{hSG(^WFkTqe0oY<9ZtYoSN&%Akt>`y_nTk4Sr0JBmKBvhp%Wt7;i#R=L zZT=ioV<$&PbGBIIWAZ0^Hd-1-yg)$f1G2mb&sgu$o+2cU_MJZo=t4s?K@Z@-qep+w zyQe9`^RB+%-iNaQPGa`!o@R&Vu>D=ZXSb*_FdxCBAldr}1P#jL2{=4XeM1fhF@f#9 zf!yGw#LDZ51ab|(m}JAZW)TiVGC^Dt`+P%=tZ&)s{S*tHN9eqOvExH&BOYB{Hny#= zUwD-P;|`UoHk4q#py^q*74E2OsrJ+bk%}z(^4%{34$L4Csq0nA6Bw?IZax7f!m?*y zd;8Wo3Xk?)q1U=+u5(38h|4beDB%w0%!17y=oqHm;KFnqT!e<(Ww(1Wwa2{P*k)I_ zE8P=Q_f7qtf$-yU{HKMk)Ys;C)@J#m4izpuV7zv}fOxv$h-{H8U{6uU8bOq{1ch%ElMOQ91r zVF{xq4PdRfW#6+dR3Nx}Fs_dJ#9rCZV;sag8dC`%h4nX4yK~eK)!cEa=@;k!!Y<#@jRPXQQsQo)?JC`dDG_>#Wbhj#Uv`a)qWg0eV|;KZm(! zzqtd_6$#=k_^r6PfO}(G+K2I*m%Otx?dH{qv_yQeWP))MnGi!5|G4i=e2CeffTzoc z;3XZHf7`X zd9Msps0rCEoN8RQ@8vX&A>JSrUStnJ%Z$1&5F4a#cN)7HRzL}WufW^4emZWBq6?>E zx#bENIxS|)^StG(SGEc)-zk0kURiHR|`iC*7q%jDxv3KAW3NZlv?!fpk0pD_c_pZrbcFjCqAitGa_p+LO)Nn%Gwt51aYA|W(NBP;q494?AhA7@h_4koYNx0CVkuDE|QHfp=PD<0AA znh(rl`c2D=+ZHEQ!1j#A!LQ38 z@yE!D9&Ui|JB~X<4x?P^D0kIiUaa z=mJhcwM*snU;-1i)`)ufU<8fri)RD7ku*LHS%`Faox^ibmRz@5avkSda;WDz2#vN5 z^H@2_g{#mloFv$2e(yWl!go9eVI9#Z&lv47w|76Vw%9oYk(b$Di z(_Z01Tr!DvFjh6JI5{s>dpRhC8{}h!fz6&=#8s`I$A#STRJgQ}WWUtGOZh`^UDj)^E zksU}>k`>;QZC~T`zPRomdeeaSIrP>rU|!;siXb=bM@-KOIxwwAZ_EZOgm#Ej^hX{4 zrKt6;fbqSbD9DNkKC;9aEq6t8)GO0gzk_2=;X?rj=um}QO^UVuO?ZPGZ5 zf8lA$SzpnouW{DI3#yElzYhec=mQ+-)u%Yx?XOUF-F`^xPhiD7^kb8g0aQGwR~yLl zA~h(4XTVs{7w^Ha8%`CRESE89vRc)%;dvP6soR+;Dz2aWfqCW!l;U=VWh0dqK@@wRK$Z@2BWjK#Me2E$59~UG-6AxYi(i$3ewCF;zp!wFjgeoXB1WYt-~Iz z#Fjye!?yiL!eNWdR~$Cz;pl>Rd8E_{7wjT}XE=(8(BZfvI{l8QYYq`Q9NVH<+hE~G z=7KnwfTo{Jd+zw>xYh4<2L7XO_4^m&jqYC(FJEQxwmH)(zm?8aqT_!82{ow!D?% zn4Iw!|43QdQx~Jn_ARhPA%}q}+G927PXHW8Bh(t=W$VuYGrUK%g@;!~CP!!0Mw)Wq z)wXN)58=sDkLNG{hqreDkE%NN|C7v+3@|W*1c;hyR8%lt(9jAF+JrC@R6-^|61*hX z)ED7Kw%CH$r&yQAZX_acv(biVlqSBVu1ZXB)ol?7jBdYrX6CUcWCn#$WSzUdykDjjPB6W}+TZCN!XML-=PH zJhE^A=~zwf)1u9FGovmr&(73GMGmL=Ba1L#Nfa)Pbcv(iXzl2y7_@3UQ@=?vHDM#$ z`7I7q*PzM}ifM+Zt~_}hR@aEn>zXF(;IU6ec{fod>Jc3$mkCsb%e2vAbDv z*!9C%INW!N+WvjBx_c7G-z(h+*DD9D<6CC;_7Gmk|XeSw98fHflMBu#0FO6v`&c_-R{0Dr&+=orldk>Kb zhdq&{=E_5u{=9RDPB=Apfn+udd9Hiw!T$rq^MkYTwtetFW@i#V3(+|j^yn^T@d#lh zX)?)EV&!e>X%a;;z&A<;n)8_rAF{ZU#Vb?A^$0OQc0FTKHwc~O@RPV3o8ID}uIW9K z_tqroJ(l*KgWh$7vBJ;Nz-1fnnjzU+-o7o_$~1Zxr_)<_7sDF?GSeqK?KAY|iIrxC zdcn^+o8J7ip4Fw^jg=FIIoubNvv(!mw>R=_B7kbVo|S*X_hKdL6^G|B>@(uMIqe?e z`AQ{HZ4?vgekA!ZUrBDDbs99IP^vaRI4t;T)r%8S3jnVjEvpBn^V;bsK6 z!$64EcKX^It^_90>gu=@Pkey$I(;V_hIODEv+rXTcvpN9YY$i_5mpf`5glWSO~}{f zspw)H=QM2&-_Lnj=&;_6;vI~t2`Ot%{_Vc$NzKLd0+l672_zt_XSVlQbWXli=RCeo z8y&XUdh)wSpoz<)s4424R&ASBo(H&St{hqkVSRI*p5+p&(DX*M>KSXJ$4^ux;+ZQN zehzUllGoL;`(73 z;ajY#{V~i}<;x$u$f|AsqdeH^AC_rnXd=o?J9)NuTxMk!W;r^=XSBpwi1CMn;^9sn zvF|&q+JnCOuJG3c5Gq_@Rqc^#bu2tJ`**%(YEEP_y!IZZ$9iYSjZ!n5s-ufBPgbsY zL?(hvhn*dGV&FWQ{Dl$b0KcUDp2oM(vdSwxjj!{~up}E-JkL(Ck-uN@_dEV%&TD?V zKvZ60oEA9+L|b@Ns|Fx4)TQ~+Dm0_?S6R^X;EGg|s&2@Z;oE{!%?8gaHG|-Ktt#5$ z_3c`eW4(={rsFpLAug%>Xh(7VMOF)_ErYm^4%GMdBB!;hfUbGPVQa2fb zVTa%zMarr|Pk_$AWfa53`M&A`x{1K06VM(GUCBMG4VwxY;^BzJ#3F%4DzUvTo3SIf zk%|hjp#^o;+H!9w4;Aqgg|{rTTsU_9qJxJN1svi& zSF6I47PAS4$1q-4vwd}LlyY0+0aIrkbq1tPJ#-ycMzXW4fl{X!wWZF$AT!i<0U~^v zwo2OQY0P6|l)62Q1I2*lhXx1Pf{R^u!QBrsHn_065;Cbz+1z>=9hgrD2NCIO4ym-n zaHCaZzFKd67;_T3e=51p8s@8U)!%E)clzeL5d!P)@a#lnv@%RH2!Sb?9%FyWhz$R&8_&{3K}l?dl=!Syd~JjVHtwE&;55I23IMsy)i0!mBj)JK>SbJALI{p4cztd$l`S z)o4|-29{dY&S=$2YiP7;ITywbW!vz?qEaZ_I5xb}6RYRD&%e|Y6O@jzwaY!R`{c@Y zPwZ=Qp^74R>LSZMll;qluT3%;tm2iP%w<(yH(;}-(Hr8S)5f(ck8 zfWJ}yo|ykdy8fb_Y1LK$$Nk&b6%uiOn{2T0Cg>*m8@}D2`gSkh8qsB&T$NG7JN!tX zph=p^zl-8cbNHZ-i$jIaJiqG~8M9H|$C~6h-O4GUe(IweG~7SAyOz7lPY1<`s8H8*1xF!u^*aTbB>wT8BNXT zeI!P(XPS_5UX^fsPpWV6shM%3A1(iKa_*(pOV4_=a)8XMFUFSZD|6SA0Pf7$jqA!n z`<>pL8hCK^g+B`;f=>@=)r<-F9M4VYX=^Xx^7Iv~&rdCbv(^xZbaIxt6ZmFQvdkR| z$9+`&^sQ4w-!S`+s%2!dgay?QNMdcg3G4x`L&Rb-$Qo`}%b(|<;?I_*s7T9_RAhhF z59#(yOWO?e=CwCk`(m_yJ<6I0ksi08$7LrN+P@jm)AsV2>s6J#Dt63>m+GCsmWx|% zHe=z`UWGMkF1?sx-}`Cmo|RLy5B0iO0m|If0OFUgmASuPW^gpTGg{jmt=$x@ZM#`a z6Ad}qlFa*4!Jj_l?qkEI*Fdr+wZX0IW{Z@sm(9`l>&XP~aX-5@A)MjQ- z#pZ@fkm}QI_idci(eh2IZ}Qn@=IsG>C#VvlI&3d`gUsyFsy$=aWSaae7L5mh9ofG& z>R;pA;CcKV-VUKI;Os3#kJrxHX_g@yc0gA69$6i%Z7IGD^YjdBcPZ8R{@hR$!{y=} zok@iEtND*%39H(JrcoGW7wlt)gMgliQRgngiJ}vB$!TAhlYHIt?`rPZI$28Hg{OHa z!1X{V**yh>-mNFpj(jm0`UqtY1eQL{Hy* zybNBLo)(5x(rM%h-2!y4w?IKLME&VbVKBSca$!N&lfa(tcp6_5cHuNyb+F>B`ZlmY z<@K>LG~nP1KMLqKlO#Ibi6Ygi-9NR`s8OR2xzy(Rq2i{FrKOq09djCYDX>=8aKj3} zNF>xb7VURX7>PLV#}B!g$64|Au_=1e2GNtM`zSM2{RjWD(LgB4(Sglgy?0Y`ey8>t z`6Bxb{E0qD!|t*32}4B_AzBQ*Ji|rjXo}M`De zE;dX2L2)7}bwZwM>m!60d;nwaQN|w>p~T`<8)piyhZ#m_d z%=liJn2Wcv-kd87+bY#Cd9k>TxWTi(%~=AP@p$*hxtN63WS-^_&3ZDT8M4<@4hZ&b zbk=#ovhVioUDUsDD;j59D?2*+T(x)UbUd|19X*=3fg!qm_RN!(Vd5#qHaGE9toW2~ z>mqmI-llzvKE#_7CG}NXm!gZ8Z@pHtv3DW$?ex4<*73&O}Hih`{ssMiva_=nWtTH<^%8vs3N0$8X+CLof!)5<)$`7agqmTT^ioBnB zeDCqMsj=k*{_5FFgJS9SeY|ivyM);1HixdjyWPjoZNbCcw7~I(T}LAFL1y@`rlf<> zukR9J6bb-e648OeQukkWK?5AR zZ|04?20+(`V{Wzei3&=Sfk2K`fVn81jofULX{7`e1;Bp+8TEu(3H!lh+}l2b_D zvUtHrK-F?R6WXj6Sv$%4tWWgV3=zWXF)F2G0Tk4OxUJ;z;*I99tc zo}mj#OpW}IPy5cSj8QLS%zBOsv-0HIy?FfK2b8*?9@+m1+i$+=SAQ}Au-?X*D;}j@ z`Mcn>Ke;x>{+q<-m+kM;5$K~aBD^GVmgM!*`-~a!0tS;oM1>kOh^}}1U4rBAV3`Jt zC?|FBJGJEB1a1xX!{F{q%&E7J7yJhSiFzU}%uv^#m&VVFzY*NX;zg{K^A>-bf6->U zi3)jtDwFRnfl8gV?~R1Me`$>j{h^Ox9~TYJ;CpM?NC9kS*wx(sO#rY_sB0LAjG|Nv z{e>zQUxM!D~oc5ZqHC@4{cuD za23dI(t5oZWO)vie)Ya=&w4$cqk6_ujzI~HGcJd)){7U7K=F1xOij!W-a}BmjeN*N z(WpU)Is&2MY23lQ)`nGK{1f4J(j~=O}tm7nL-usiO6zXRlR2OgI$Ni%v-^nwt1mQ>u$r944)V z*C<9XL}Y%%nAU{B>qZGX|NrUx}(u)1*_xLTT{&udqL$?#q zs|wmg2p4Mc!|`XT59h`Fovr?p7~C21sUXS|Ppj>%7w0Nf$N_i!o?@q>~*Jdzp zvL2*Lb`NO8B{xH zXmTm&$VFKSN0Lk7BfeN)9#b}fEG#MT$HSyUO2ZL~`PTql6=b5VQJH0Cv8?G?EGysf zuav#IwM3@%N*R=u>5FA;&tgdy{oy%^uIpJW$)dsHv)8)5XR#!UUY=I;EQ95_I+Zw9sxy9VRr85Vm7J=j z!@1-M_eXEisNSGNhgX2HcVIOeJ%Fvy{~cUTa>aT-b8$lgN-bbZURF0kY{0)PmbdRwuk3+6ktbIztyQeAMvQ%jGBd?a-0JVh zP}Nj6JG0|1x=js1^(Cr^B>IGhnupl>cqXW>)9>u4v}+IAwNL*SwRgcb;4RQBJLqz( zoV1Ab|45sBYgTXTS{l_)Hl5=4Dz$~*X*$Xmu1b=#XMUp(e}YwB|G2SFJa+i12V$+)MQ|Hs~vz)Md(6;zv33c`zN0t!OAf}Z!K@dv!wtRkB+ zsHs+)Z)ZhAZlx-AzmZ@pm3p%S9$$2j5S!!bZwI8SN_{8(S%;%J<@MS4rF}hTP$PHIn!IU^0>Qcx<%{s;@ou^76=3PQ*^PSILe z8NPV^<-U*VFNrL`v~=Ov%tgb-KHyw*-q;1Mg#*S`x)-K$%_lRv!yH6fa#Q@l*RWLe zu+jQm@{it+a?|%C_tc_&V>pq6Af>I`sJ2$fa0{|-P`&nSH%M>1{|eFLhYL>g5L)pS z&4LW&1p15Yq62J1^lCK|PWTY8nlau~<%J2o_gmW}p^=!598Yvy;r$5>5AduOzIhA>Ave4RD{TlVRqsdIrn3BWCGROWP{@bZx2|O$8;YqVIbV!Oq`7NI9#iu64Oif#xUJ@=#o8sAXkfS7S_R7o7jGIk9K>I6K zFC>i`0qafm^lWt_Kb}t}H(kPyjA!N2GxAlkM3LNdDqRYY+*B^v$xUyZ?NrMzO}bkS zh-WnN@@JP)prc>Bk9^91tK~~;A9*fI%+NDe=xTNTQ@Pd4G_9Lh)Lit&h7mnM(CZdc zEG1oU+qU{3n1yM->5p+n&Lj(!8aUz81m+EKdL7*+;8N(PZ=W7}Y}^3si*54;&YrHm zbGdGGG`ph@VdfR1tbusT>>Rn6A(kW(9zpc{Dr?4; zA+Dl*wWEET(ojD-XH<)Ru;;n7@s$2!0N)GiJl`e3mSe7EmfxNicRa(GsGt1~RXTG2 z?Rmjj&#VZ+U!(DvB%{Nz7cULUw|J?Bp<+XyQWN*%oCoaGe{RMX?DjnM@OJZg!&d4M zKVLn3O@c!Zgve~&{2%`IB+4P(-gv+?)_`MLIg1}6eF-O6p8Ecl zlL-lO*J`LFY4j(1r&Td2o+EWJyaM(lXO`ng1Wyc+I-P3dXze(fA8BxBg!N)1*>Qs_ zBixU;NbVmhLg6G(&Ck#jYsZX3d9*P368gu$vivL?dCM9Y9m~!-8I2T1KUJ{8;gfTbraT9qZYzqp=xIbpKE0^ zpT0>aVZJy8vOZ>Q;PN%k#e~~+k-S5k5-*%e+z5Ujd+c$qVam3tpW>E;>wU9KEO0P# z&NAxncgm>$URMNEm*@aR4a8^qETz4$@8olmN$Qs9a2%P`n{agO^17j(MoG~t8@}LW z2y~Lad+tD99M6$?cxVa#a8P&0{o198&Y&^#d-?0ax^O?t7b+KGd?Gs%mdm_4+8HA+ll)k@a zKVi~+8%?(E?{vK+-8bw*GRqDRVVeJwX&zaGQEG?hdmGi2JDEroq~7#A{tNaPQrHWa z*H8GWP5BplzVm&)i=LOSI>3T}?=F|;u|-^tEE<7xX_#+5yGJY)@E#YO$ZmH z{Rkn?t0B7ap)cv*lFEIL(aOZinfcRYjz}BMF(EM9DQ*s;arA18Obattq~@Q~5ZStu z{Y;d!e0}+TgvA52FA*$=)E~$Q z-9~CzD=<1%{#;_-G;~YgZlOC8zC1Cn*mg@y%$sE6xgoh97Il)keUuBmFYuN;Sfj4_ zqAQ~VJl2B%Yu6ygzB5&CXA+TnfUbYZ!rt?M)6vlMHPbOM z|7w0F(1_2^Q%RcF&72Jf)oC4}yKj|Qj0hLgC@+8PdzCPN06Z}XG!FiDhE>|Kp&LwJnr+T8$p3|Hda3tca=@n>I&5>}w zhWj(5NnuwVrg0IQfd~D{9|-{tOiKiUY!CWka=b^=%UJm~-1y5;w~0=sd|OI^A!?6o zddoGmD(fkL3PZ@FFTh*Tu^;qd6nR!OMJH zFewAzb-X7kr$xQitwNW6&;_z2Ad8;(GFW`EISV~*@8Vj0CFSO(j6jEk4KEOs z2~JaI%sDdMg7l+_klc7 zoJbgk<=^B$DO%r7oCx$a{&A~K@74;Z_rEf8{LjTI91j08=ACeav2FVD9?wg0+vm(d z)B+}xR?kb?fi&RI-l@KiF+0h)O$fIW<&1ow9n^H;17|DT87s>=Tj7IeD|}Q+661$w z_nw~nP{C2Y)4ZPm8{7c#=lR(3ukuVdA{alKn+UfFmzStoyN(5u(QzYUtkpU`*?69z z61xXP#_!=#@Vn_PEe|G!yvXQlHV0^I@CE#v*oz?}G+f?{o{Rx6+-oV05Lq_@**f00d*OTXdVgCYyv_mEOiv^eDirwIktJ4JiL&?KK}~AihTe+4<&$Q+OFM+h8-H?m2Jmg|$R8p&PRF=y2jlj3!MNR;!niH3IUVG7vi&X_sm=)xt$| zY_+ptn6;H71D@M!Iafq8$Kz+}tL_EEJJfDwo%gP218z?}ie}oE(w`|?fA%-exdm|3 zpLli`W$`iNz1dbKaARJnC7zwE;<agQrmg!i)*+9quPB)WEe z7|I2zp<0dC+k%_r03Jm6Fiz_T1^L!M%lXHtH3Z>gS4Z7{RI4au7a`{49R6FzWGGsx z*yszbNl$m! zy~&|xeZ1=f5J4aG*?0vp;qaxcmBGXt=Fwc;&?>v3y7=7ob2XFp!SG7EB5@~voW6SZ z{3<;h#@~<1!OhrhYQ7GY*>Q@BFC=N*vm>qDzEg7t#RA<>3JRKH;r|uT3j)ouQ&rAe zmjoN*eNwx%TWH}1Kw?AWK=;jy8O4Q*2)0^5JLRZ&gbOVv91{hb)CD$(`-!OY35mq& zKepCA_Y%>!R40QA!z;Jyu)9x#^;-_IN>}zD>E#h9790^=|A3ubTkjWZFsXzaS2}u zYIcgF)Z^o2BPIC*|G`U0)i@M-9?#>5Mc~0Ly{cQ(RX^vxb%!_B;Edklc-v^Jtn4J@ zfZ+svABQR}2QA44=nNpV?3P1WvKZn51+;iNf<2fYo1BqPa_04HZ*5%XVh1@m(VO_= z1h_}D6GcH)5tNMym(>FHogR2k0U$)1v@fZc)n2T??x-)n^C`a6dHv0HhKK1xUI#4P zjDoY29jwb9?q|xvP}u0C`)bUoS~es%{^!`^!5SL55F628}<# z{KkKm{4D;ivD2Lmb)b*qwVcfNJ;&=fVl@=7w_I$P_8jpR8jJ$!yZb){9%42vV5^gZ za404$-_DSGimIj&_CpF8meR=84|Bd=mj%uT-P#rl#+RX1$>@J%SJ` zBU&R$(}p`?69B~r&m0}hCx#++do=Y1L%mGeGgZCaH`ShDLKNMe*6OtO(41l_6ILbQ zT=+|g;Y~Y=t#3O&AL6_(dDv;h`9U$~X5o0$?|GFFqf7jp>V(5gfy)=0TO7W)4ukVF z524bjZlVmjaNDahIWEaXWcCA5STi-JS`IXMHF|my8|q?uewbxost#7^*K#|O&~sBf z%{h9nHt*DP6U@*S)}oo4zX8rcR;Q{hmX&1PG(Ibw3*Kjl zNJ+;{;~n7~(T6elFq!t8?54-F^VDB*^qfY0bhVKmlS|Z~g2ap6B4f4U+8r;>m0mvk zqR52tKJp>|rJt{Me_;9C7<$I%`tZg4PrMV8^sN@i)Qok9O=hi8OIRBO(p))f;q}0r zT{)|O58Ktz{-u8K8{_AA=``k4Yno`LtF-G=r`P9_`tp0#XMU;M?E2oAdbav#f92}u z=~&9-_nh?dS-JF#e6>w}qs5Ae$xklXCO@6^S8F!U;1+dZ?xO*GgeXIG!>v=TpeAZ9T%+qe%c3OT8ruMg~Z( zMfWDc{WyJhfL|6ZyLa)TSwLss8}^{{v9@Ohrl}ZMSsmGl$-$8%KfHN8!@)6ozRJem zan>rP3}#5L=;gYi`sT5mK5PPkX-`RZ%D{xez%=5-pJJzMqbvrOWFBbpw3WkIk5r6%mBNLHwyfRafE z+!>4ixL9^haL@wNh}-Z5CXoIq5cCC#7rsqZt$r6aBq~AeewAH`$=K#*2!s%(nx6S{ zBpOzcThPH)%gV+$Kw=h0+|wA~=hPxtIh_xVK|q03C@g2ZCsq+;j;-@eW+fwu5|iDkFAgTc++coYc6gc=h;B$n%R;g|K({c& zCahhNc(?DZxi=CFxB;MWfo>Y$`9rg2D27xl1Wph2&!13ZZfd?ZOJ9487yw*T- zLB#8IWfFTfF&D+hx{iF`Zo#PPP8M)JG2Yzz0BJv|j&AHWbF2zK`@}46ygTD*oMwf5n!tYsOC4+cklIC;(XU+x*9h^I+Ug|iP z{Z}u3Y%&>wyiuGVyFFoLT-HK8V)Wi6@N-H*ZS=S%upYQH_<*f9RG z7Rdj(YPZ)AMLxx`cep%{i+eP%XOPH_ zKXa~wKM&n26C{7EH++}p)nIm{*%|q}h<^MF|0ao&Kq0g*z`vd74oz6*x@lne%E*aN zLt~ds%)DuGX83~0iBqAgmrcyNX>wM0K;#4xz_Mb;O#w$}7(1Fj`XLQyN zW1Ko7MDHe0WuQ>&iW^HkyJFM9jL&Vj{7i!7YJvej5WCe-j9rTVS)+A%(Q!+y7U8s_W!`jV3q~t5 zFiBW0Pty`w2+sw_Wqo0dFf99ESXSc}*^6OmkLsJp9RDVhHJyq+gUOnjWLV1bV--mz zc!*VIGs@w9HI>2-UkaxV@xI-|Vv0}(y^i_aS=h{kAq%&p^}^*3BxrI~vFfl`L-fMn?EPk|)@z zmwT+Tps%dBe)<`VU)eMVS-{FB%)gl?j?rwFHt{7NCI4d}*&pYxGCQ(v*bK`j50LCd z>RjYRp@Utz+l-*6>5((Za+zsa^<8PguA0>7YR9}UA;Xh<(4%==F7|*qd&uEKm7bRQMpjN<} z#O8;P8P2oqlTFQlFKt)HAHr2#07)wDQ5~HAl)!ECl0{Bgc9Htdj8K1WON`AmxN}(* z6X7u@S~Ko0+#J4fzG?i_q7|5sm(A zi{)APMJsoSHTo&*wp`!j+___{8!h*bt=vbW?nk4!KSmwtUJ@8N&L^YOy|#kN znzqDgjb37&@{C6};falYim7h(;}qmLyfxQ%TkhPrh@bcx3_{cCkvv*MrN*bCcX){{ zuOYfx04Xv6p;#`a$TQxO>X6=_#D;yt8%wJadeR9S)*LFc=a&bY(ymih?yq9`zlzah zUfb7h!;Psn^p`etMF;;nlS)!uYei0a&GN{ZsQbEXgOMK6FZl)j2__`jAfYdRv+RL)FD;1WE)^B$zNCgOr4jqEO*CR{$A*|_a;McVHr`eft}WGE zRGF{dwQ$W{S^-AR#s5#5uNG6K(R|(ecc`4wdGI=~A4DK6q#eLN1%yIP669aBHikM$D(DXc#~&f^CY`abna=yhUj|y&1Pe78TR(^8T-a`cJ8z88?S|W z_Kn}LubX}25DMzk_YIwYNADY@J^RKOz0hya3q84IET(| zCwB5OcgOYG1)SUmB5^st%aN6+kQ`xR9SnNaH%wc^Kq1aH%kYfgu(SDv8E4}c$_&2% z7*}nH;TJd$`5%5^M&4b~(J&04fFvZ~LfsDF8BpiBT7q=~s(Zv5sICynV_;om0q4|U z*z5i!u5f?Y`W$UL3_5!@K<10#$39U@2iuAE`fI%Jo*@WNwhxy; z59yPXzvHth|Dn-D6xo#b@)K0{Gx!ZC3(GO38+IebYn;JB1nwPa^hP!}RuLSD`sfR5 zlib+g9cOZ5a?@~Q|AzW#%l6O5jRo@Ix@^XW^Eb)8^sC1EHeU@FZY(e^(rRDlz>igo zQa3~YUNVjB&vHs|^puT@%^$}eX4l!bnr%$Ec>qBbK*5dT9B}h3dfSa+vl%#;Pn z%CsLGP=kYax9FifVDa~Qo4r42_3I~i09uk51sxSUv`biIn`Jk)Ew$!mym`vpsK5lo z1U(7oSi`+m{*O5-rr=6U9yy1I+{nn43FLRg>bT_%G0O?(lWQN%o`fb z!tw>Yp{rREGV#F{VjT#>t-V?E1m$sE6J9A+QV=)ZYrkt|9mY$H3tQ%XQ8k%e*19^-r|*79bo zq&QkKE_rpFeU%v+FS(maNt$#|yyRY3Fe1WAX4!ZY_CrDSMGxp_#8Y&NNXE3{0xZR<|=9455Ns=No~ z)G({$-k?pVO6#`i)~#OkRiGm_N_#&M=BEe5xUs#-~%`tww{laEa zHv)iasJe<`$TaEm0lXOD0){RP%!&o_gNZ4qC+;CLh;HUM4*BF*%0p5zI}v1^r;02< zLXQXTk=br1%uX{BO8Lq6us40VN9-PL-8vnB8OC_B7_vB+8Vc|@;J6q##vB(7`L?@4 zAb*Cvr0hBkJpqq3&HE-Qm7dPfKIV(2lEF8(Q*Rx@qu>nvXejJG|UklEL!$c8-LP2nq~@E{7?1>3EyyZ_qZC3A`SmTi&G^g%M1f+3j| z`a-0uZ$qC**MNq>5qgI4sTk^2U8{>&LVvYBYWd(|$4AG%>D_fg(i&gv*x-4o zwGQv$+KsbDur17b3LVO~FE|%+-6e#9K{jk35{4 z5y~tTjJbEhj11-@MrOMvyyvAIGmgK9CH$q2Wdv@}QFUfWuTBl=r9t)F*&eLB>-c;2 zxXB0yh3BMlw;9s+X6*WV-CcTAdqy;};GT@ofJ*foyFMWnpQ`L$?heWQC|@gra{-SN zhr$Viy!|H(a)+GwU2GKfQX)897x4Bj5PsJLvG=?#RUgzIB*8qlIwK1+y&1i#;@*I? zd*Op=wJ?5cdFr3+OYG8uomjh}0Mq$!?9LMKk4>=`qC>Un_d&J*bQKsCi2eM_pa1zg z|9RT;%pIBl7ct@yxQLrzB6@{R;b00PqvVRV$2UJ0-xW#5H+#~o=X+M6{Y(9Mg;|0#uP1)Q z&TGkuKpe7q7WfFJUUYtLuTD}w`A+35a9c+p-B=h}@O-d0!7`+jsz=$I@X_y~|UcDwk9kbhK zzg`+h`((VmY2z)w-D$s<92U60w0H{fXlr3Fmq43n(*gMWNHY$U(bz%0)_5j#g7y8q zqkM#jIsAwkQD+=A+*uu}DHd!kZLdqD_0`-|w~aujiFVgc^)QG`3#~ZHfMY z@YnXXND90x8cq=JXqxiU|JAJ;NKR&ct=7LnH}m!T z7HurWlQ(o-EY?Ngc$54qtEkehGBNjRD<)$XjFsjE)ig{uDCGL{@FCFgZ`jvyp{1We zr1u0(Q$Sr) znjW^*ZvQ1($km+G(A2T(mdp}Ahar*T0t|s#UCJNMqsy#!e1n^1yuEA>0!d7!u0%)> zBBtWVOI(%s2SvuUW`s&5uIit%O)zsBvPmA)H#Gd1BQta(s=UazVHYQQJx`mU{<&Uk z5SZI`GFn5(fn+>v$cdHu#*DK{byL5dYHBUnqUxv5?lV=L6xDV+8k#b)Ni_;O3;Y`v zQIWq$fSQ=&H7I?!kjlnJ=zyb5y@|*{8Ze!1iW{-pQR>L`AB#Dv*40GR(qSRL);!p* z(w>SP;;&5Dj;BI&5ioo~^=Y9IIJ95RDC{>N@dIRZO#E2I5drYrwh~+t7_)v>Hsgh= zV?2%oE{Q?dP0s`ZiJcZcVXAs2k%Oa57a4TQkBYxu-36+W-4AcriB23! z9a~j5>R13N%n1P~1>;310U}A!8-i{N7sAmKt0E96S960LI@OY9TPAJ+vs#}lNiYku ze^y)9bG+i5t*4C~LE@M=^=)1x#%}DY+m#<>wu$BIF}>&oBJ zF42e=dlx_CUOcxiT&kyW8dF6R;n+rO+@ffYm9J5MmkCt9#_IfC0ar-#!n(dH(vk=b z_57iQ-5O~?#1_rp?mj@)n+?{Mo}Yd6_1_9?GU;I^p(jV!Tf>0^>9zRNUrRJn2cph~ z!kxOjwPp7K{Y-~>KGNmY&$@No?Z+l|O2wFB+v~IV0kCnKK zId|LC%ulFQ?|21PXRI8w>jSt+&kd?Sj4-=TPne z7u*q1xPQ-}th(f_@%q;Iyy%nyeOKz%^Y7jsWFZHptU9L zU#n+>Oc(8-com6+qYgo#xQt7up-_;ACqqYuAIg?*U2jW)RPhHP4S-7%N|=27Zc|6@JbN zuLbB35WZ_aaR`&lJWPb22||-qG5@+C3#8K8MmjC&L(SA^rpoTa8)a658FF@kKrd#e zqbowvA`?VD1p_>zpRcX{X9*%dkNb?R1X)CMlEdByJ5vwchJ+h_eV<`tv;-ylXC@Ii zUfCmo+h*Z}`>;W|Gh`!#F;=%_&{o0*P%U&pfpnyu*AClFItS9uBJQ6S0j=lH#Gd&h z^M>@~Omh;Zi4-B=_UOv16no0DiSES!Z-3hbU`g|_y%%hbY)xF+wp1T4K~XOr#1taF z$4Q_V3%6%))WzvD1WUHHwTHa{>RZ5Kst%s}UH~m+C*1Y{$tOP1#c`?zvS@2KsJ~zs z@WWa*v6FBVyq)9*WB&Da)Gu>FVve)%qh|It%Xrg3dw(XyF*&MjBTgQjq%^v=T(u72 zRnO{MEjmxPI-xygeR`I!kD%*&p1XqQc*aZ**mg&pU2h%ypLpH!C^d?{)e5&W7X%gO zB6JiSq1#o~3*y(l?@c3M`q#zE*PC5!^JQkwV}``d4Ds(xcFnB!G`v2>D+!*9nHC>O zkqIWdao=Q!mSVfb)>MHVHXmyT%aS;I7CJ&BhSg}Mt@h8fRg|33@sa`|QnaiXj^+k> zB|sx&-m-y4=6Y?$#NHMJWu#KWj7$?ZA*N(cqgS+>MyDO_X1@~Q-f9@fQGU8{;KTnG z&3)Vd*v0{|1Q<2_E0=1Lm>AG|Tn2{i8B;DzS)Z&Q6==3St}|C}LqI1OBNsf0XXU&4 z?dyrevu%9q=(AcrW;=+zBN1b{Oa1u`5HN6Afg!@7HhP<+aG&gq-X=dKQ?Az<<#{!L ze%KWdQ2W zrB?0NElB6*BZr4WGStifGv}Lb8Bn1}1Ni?`3Bh*;4m#{rd)p-i)q%MGfF8>7 z{emUK?I6%&`c${wsMM(UQD3u}`StaFjY^-Ae;7IGFz|NW6xIVloOgW z_`*x{&=>~LE%}k9$`bKCPdreZcpxumI;XPU?d}m%QbeGLPa_MfV{%nxMQW=YyT1JgD;D@u0PlxkT1 z$-HWEUV394E!I{VOTUZV(mqe)-DuQx3x*_#aib>3r(T^T%ZAo5{QZ){B1!ig8Soe> zauRbIZ5mBw!urLUfQn5-e>8@FgUHDR^6TY%{*5=ucRff=!&Bcz*xytQGZCuYlz3Tg z8oRst^+m|wx(?B^nX#$+8l>SEwU2-=Fg=Zc82ix#d9o=ZRk_ptR>aj@`+I9so_vcp zdHIkz(|dQb`JL#G#&J7oUoY*p`bV2wT#3fq{Oi-544?0d$s6&KoSYleuMH|MvQfv7 z)CCd$Bq{J-@r?@Id^kGc=EJPC@yrElItVpIa25mER*XEfX(GClfDAn-ecf z`=vc<5`JGY0dA2;_1KU?hWHNC=}5xuS>Bhj){kUR1zw1n=jK*gn>a>g{Ls3L;!a|& zH!;^uS`_JE*KRVW{Xs5ggy&c>8GgXze$N|7Y9P;8bGjqSd3&@;2%99qLy+LcBnft? zj}4GMB)HL#;6_7&8#M_e;KQ*){gOhKsbydIg+qTucMyxsqEZ#wmMu+v`CfUs9wMZe zqp_x|`E3$f2h}tESnK)<*by*<`m3~$FcMSC<5j27``~;32~PU+uSJD=tk~@eWw-i& zo7r(ORH%$QhrhnfT^v-US+Y`G_JdVC7}EE_y(}~*$u+R~asN)~N!-6jKFER{*R2`B=?|28 zdAsDp-meC}bpm}=le7h8lxc8KwGBZu(sgNOf^#KTjfU$)4>-_jlHoK%-+>t#W<%f4 z6|NMeK(lb=*!J)bE@0>FXY34#30V5{M8MAXvWx+pzEp#Z<=dJr9iFpYPHsVa=;))~ z=ggO!cqhL8X(Fb9LDYwQwG7S9P82I96o6u9V$JF4$29yrb8kKoZLs#AJ@;;)P|w`! z_@<$ZndL%r@)vaB5BWK!y6f}2ZsURU*O{GB{rLPd_r%-k*b`yH^gtDn9QrQRXGd~h z6#mh6jv?5(I+|m%fH^h`7%wZ3rmHV*5K(jhQF-N)5oddFDHEa2@UgGY|5R%Uq%iu zOrCdfli820&(@D5=F#5##Jmxbc{fmym^a)$Qd&_-*m6hIe^6DSu(1ZBnU4CEU4m{+ zhFkOn^1}h*Z+(G+@GS`ABCZ^r#IjYHVbM+lln!Svc%+hUQ-C{z>g!#MmcN_zHVDiX z4A|X=zQIPTzmeY~$J02SpOJ?A4A1h(`db0tCh$#w?LXiU8_QolSSe2q3$%@P#MS+i(T(q^2xpstx`3|21>J*iVocw_$M;K}?aQ?gSt zmY&96Grtgjp8e~)2?9vOV!QllE_t5zcUl{ZHvdkXt&YE6<5|&id~bh}Yu)lXlNYZ8 z9Yt>WmuuDtR3BI!9&Yf74(-js(uFm2fyp*8sAfJTYXDYoP1K1m&ARA>9Vi{vs6UEc z)bB2i5;D1Q;h%6Yg@}T_0$)e|FwqT)Dwp6qZ?rV8M#b$Z0Bg06iO=SwLm!Y88dX+5 zO&xvftjLMizoU1NbK>3}*)Qr(jRn^uFKB+&EvrS$OeN05^=R~jgD&A;x9v`5C-ozR z6ST@`4di9S$wJS$6>zJQ5?&zicV7Fp_%ijXzk2ovb$uH|Wkf`K{smZd*p7Ji-7?Ge zVQ+wR)#|HHf12P)zGEU$)66d;f8JkR!`Uh@cPmpccj_Y-CqSF}Ia)6XH|x?Hg;snF z6pMz4yq+J(Mxo+o2oZ1Q>h&jhpg#meUfB6DTB4AAWUKceq~YCx5J&Rf%xC4NI{F%~ zAERpf@yCz1uJo8I&)5twQcqq#wqhrK68Iq1m zjDGZjb;A903^tHj?sYhqBYv)vxo#{uSiJSpQfruB^Rx`Oq_0L9fthJ9)5Q#npu>)7;g6_88+!6o*vJpjJv_VtfzBa(VHU<699(Ck{6EGBe z)E)ayNRpsFPu}+gkMFJB>AB9ovyQA&#ipjWn4eOUdFuD_6v$>V|DK?_=!obOT}#;@ zcG~ZF!7k0SdZ>$DuT$T%uVIfVrj3>S{Re+P8hQR^c4Unvra02PG>n1KY6K;Fbat>PikY=<7?AjuAA3!4_2*`r~@E^I5-KuEAt zIE$jzKI_ze{nD_rDA6%UvP7>B)~JW5T69H3>bIf(y8x56iQh80crBwFWMh^1y1VA- z{eZTe1)O%f!Tvwz7W+8&(`@C z?u~cT4mOxlj_h^|z{Yv*YR>&=cwJ&{zRhMQ<}!8%8vmWhPh%@zm4BHm8BgPH<$C#nScwQAo<}9uXXF#Fr*XCZGSJib zq!cLi#x&!bn2WxynZ_ZA0c~iN<|T@v{x++W>9tL0Z>vSsOth0U-ugBu)NX68H>g(r zTF7iuL{wT}6A~m2GE)6fCXnn`Jl&0em7x@IqsTr<`7cOa$b^W1LG=#`(8E}hTr`c+ zB4c<(;^q6fgudw13Ei`osVU}vGHAv?t-W6+r>F79Tn6he=6?=xMC9~ftoBLuR~Q^- zOe`kV8k4}zq*Vk)3xf%3;u1XW#IgE(`PB4K+cAx!S5?_ulAN9Xoe6>?yl@Fx9i3ogA23Y0&0cJ7j3N6u00kZ2mAesjHf+t20GyzL(QZBKHk=vc>pL;pxuj;Coo zePWEP+jBA73RTOGns-7`ZRWKJ41F2R47HTSZBtEr#oY@w>^ z(+KwRae7vM7@D1fS~AoAj+zCXa0h-)-n%hU5FG2%?YR&+CDp*~zbO9MFrXL~_L-n~{ROl(XzlFe4V|A)`-THw; z4^wx~gz~RX&L-gtWj6WO+w@Z3BoZn`n)N-T`O`^F8t}?fGwQ3eHED`YC(RF-`{$<1 zq1UzPd_B|PY*Kg8Fcl>ul6JR>H%j%bd~Gj^qcq>GiP*UVc^ zB{a)F7691C=P{KyfAIbt{V1tUm~*_&Ywxqf$@WpZZbrF*`%oQ0c3XWXlU^bnwxg)8 z3onrh@e*)#Dp^r3Ufws(I=SfDTd!DfMuat@*N zesjDI2}C#|EilqVw-1spUm;6Gj|@J5zcEEjKus_Ho8ahP%2VN&P)?zTKO9t(=mo3< zO)PpHCS|&te}Yc_nMiU?#NXDBJ$LNpZ!3QrQQ}l{Z_s4!i3NF3ox4uuy=K@KGe`CO z$?tieybR96I~(94PopK|_a6+ZA&ZcV1r{E65Y@HM!5)n7w$e=+`4xf`Hs$M$Bpa#v zJXVwro({g_$S_v{_~$4)$C|Oq4|3;vb{eL+M*qKDTZ3gsH5}J}{LwU7gbE~&JX*!F z=N=xM!cY0_`{w-aML+SX7Bp$ot=!O%DZ0(!d!)@ST6ak2c-a8)28_7>iHsIS`jfpEZ|lFs^Gb^#q<`%BYco#LA9+pWn?`37Pa!$L;9_+%Ujb6=-iNuZ93WaGCWDLCnbjJxhe)SeL`y@Hj1=h==)U zgvz1PyKhDWFYnS@G~iEVdeVzNuS zfE4srXu6F;vkuVr+Kp^8{)$Wj9pCcC6=Zl1k8eZ5rQcTQ|WZI2G<=4b<%x}iD z_AIS8V&&~N*GZxp4E2@5yOpC?)u!j+))-sI7tW`d|3c~d zO^$GUYIAPbcjyA$6gaD+xPHtQY-pl9@`cpFXnkkgFRK)PpqfuvXl~vYRQGI0>kBjut?o)90vJ-_@}PM$OJ#ws;LRbd^ly@OMt9i-LXS1zkY!q&Q#k7G~bqvK+cs z5z9j(lJoT9-t)A-Jx@hbAhl%C&(EzedRiUZIrZ=W93Vd{eV=qpBb_;40{I9{H{RIb-Y znm$0pHreb^*_9F@+fGV)m}uG55QAk(32wgodwk)-eqpxYd{`cG3vX@Y1kQ&ktQ(Bt zLG`T(yz6%Fl2&11tx~+&cY<8+YYSh7-|iA5K0x+SfSi#11QV}0tzLcA?6sD^y~gr^ z>oh&LA-@uYXD{WrSZbB;q`0GgkK>4MdM-|}$y~7Y_LFH7fKxH3hQX5BVUAc&4n2=@ zBw0kp+dxha*DmBezfDMirq8UN^W7N3*)c%g7iGJD6$=8Q4aW~=S;@HJq_|(Rv@{rb zxFDliwu|z$OG~H7ubRYz!>#)KWUi|RuGZ&h48g1Dn8>W*^{km;i|Y$Ateg;mPnqP& z?#iM#;s=2j>jdRk$Zm~dk~tCqFz7ZCKjvxtI;0m~V-la7!hVTQkc0FYYm@x!l<&{U zx1&5HKc0{KU(Co@{ADgZgL6rSwJADEgjY4HQudmZbCImQX!$x%(*}91@s~DB(9 z`ByvV>lBnRNZe?P@~pFU5C|b_T`-iRVpovvt&gg{QrK>GWvI5L?Q^#Cfm9>FyCmvx z6HWr7lr;t^!N1n?O7V48Tg!W{{%QY2K1qbGu8jFN1y!hA#>Q#wfisz%$q-xHrg#Qr zs#TXuOY&GwoiYa%>{r*R?^q7j7fHJ-*Sm=l?Vp2m0CAY_tArILn#`LIdF z|J*GayNPbk2)Ly?G7cq6aR!jwU{L8avTbE{{6MBz9Tn(lrsvpcGfcAK=*jmy>WiLP z#w61d?8D&v@Q|N7YD%Azi9&exRT&tDn12{Q!)rgok75KI{Y&0tc8X%Q2~z;~ zP*XAPr^YgPS%TamnX#%>#1a6Mpi?xFoMe?ALx{azOl1@<8G|M{RL=X?VxNkgNU)QW zsAR3Ez8ttUvN1AFc^FBp-H0tZ!Cj6`9iE40woS}=;?HN&nMoXnr&0DB*_u2}KaibA z`#jsMf$gl7#vW+Z^~_(HZ6NVrfi!&$xxS|)f}_}@c+DhHj2Kr{@>6Y9Cr7g$>j6Ra zG)fq(8M;r;IduOkL-&M(q1($h*t$D-NIl90P9h9-s!uKlo-dY*ya&O0t^2msD6u;*5;+_!*ad)?PMzra-Z+XzcS2^MW`63k$ zs?Oz~$$6&*6mUM`TNaz_Qt#7vW8gi2kR^a%Gk#&D`gA`teV%HMO47_^qghPs+*>P? zk^tE2`W%pcJ{n_OaSByCCo&Y`9;zAbiE;$#2jt7%+HUa{E$_t2wje(v6qsG0*1xFV z2iH1AD(vRTYKTprPJunxy5Ar$i^;o0$<0m^_X%&Nh zrrVa-DMQB)(rPbJ;@7ot+3%V+M(FTjWu-18WVpIU2-mIq>8aUF!MTjjbiX`D>M{Gd z`EByHrH|zZ-r1w_{eBuTgRocO0L5XC_Tr<*L*#QZ^q*G%kE0Gg%T5x`l?=>DiSZI< z_6&K76V^OTm-YB-c%w=g7G06)Nl<2CPpwx1hhOHxh>@5w%|e&rEknYvJB|OYuov_5 zacb%1-LP%jx)q;<(j$5`eeX%*$Iz*lKhvXi397%BO3HICs-6Ew;HEg|_m^ z<(yxUu0HekBfd}iG^EcmwDg+{X)#r^WudScEyXtF!hHRPw)z$GNVnFWNe6Ww)#Hui ztp86buuX`+$?|W5zqR~uxp)BG(P#ZPp5O(8!1Kbhq`ED>Jv@Py%dRw-K4yBqT# zpvpE`65CbBEWWRo?{L+k92&u@l4(D4#U`1e*T}c^@d?A-l*-^!6e&V~ySL4zt~>T?`=qYJQ`1NGRz{cN z$SArv?`zs&%HTE5dmvk~4%(*M^ExM5c~|4+1p~$8`Cq>~fw{E}cM`F|y%>4Vg9)U~ z(aMPI30lrr^M}u8Bz9Wmo60zbi4OBYh2@#Do@6QNL#pLxhRpn8eF@=Tvah6*SL;s> zkM5zbcrKSqtR9FP`2q)7Ey&8l`Nz}rnC=eS9)37xhE-x6{9U(Z20HE+YM~U}gMYTU zs}?O5Du<@9e3->Mf;<;gKOhXhct^EMO|w9IvLmIXy9tDdBW%8yOINs@G7%oP3F?Tbe$hkL}{@7U24tx6XdV&xtQ#q zoR4>_4dYKgAHV!x=QtnJJ~i1WAxg;%JvQU)>xOoA`y+?Pq|diA+7l~pQ(ZKavE3~8V>aZrc=mFdgopp#>KDaKE@FhK$98naPIao4={T*e zIBKQVw&7wDg#s$m0fjbN+SxQ|8x$9HqJkNSA zi3@}8s20Q^oeuv0({*yFGdvmo&#=czX^L@(wcJ>TnOH`IyQ^IVoLI@KdxEdiR1$U_ zJxql-ePKOqHQ&>+c6L_NX@e_^QAQbDSr`7KCNie5Ekyqir1*#g;OiYTK#|e;Nhp;2Ti*~ zDKCPCRh!>Zl??E643ODNMOnKB=t`aPLsO{zrgNQ`a;bCuzgQJ^eGwbEq8hD2VIX9u<@!Cxt9Gy3OEo8SvGTDTO z`Jy|>e?Pa;Y4TJ1naavbTYKj?1V6i^ObI2aH<9w?#i_T+dMir3mFg`#C}x)w>n%Jc zW|x4^qvg?5NhUK|o}YTtgq7#Hw@69jHn5R|&v#Vm9EqnyqXuz9@Yy&(vD)AtDa7X$ z@KvevNgb{j*5Qg_9mayi%FZrPhf^n;>u~B^a~-Z2*5Qg_9p1~1QbJ*jWq z7S0`GDZD_P>>w*V9Dm9q5{cA4${0_v75#Qt%m4r5DH!T>u64RD)#)MhbsYLfTpWVp zH43U6s%nL5AHgrqdl$^s413K!$?CaLSkrNkJaBf}v($V+=?nHX?C}TusHFNROr_Nf zSh3h1NOYh%aXJtj0`qPI=6G-=6+^103^El>dIwU4<0w$aF{zOH%)jMvlaRi8efGZL zhurd<#@(Zuvl_2tae`eHTD$zA+ik=EC*7?qnZL@DUllQ1Sor)`We4IcIHl_GmN)lu_i-! zsiKZCo}Q`O(tMKXwdgFDg)6O38Is|IA?X#o8VY2XMy}vd#&;<@hY7nzIXj3n%dPD= zl%G%jv33yVy6I%+x@mBB0XiXh_&0OgnEHp^XQ%J7aTl8J%NGE##up~5dy!@p4({$b z*^7?g00$fPLLb^XP5Gr={zsQF{3U13xmGM)w6=~vxnAv=VjoC9&863EUFOxE=F+4w z5Ut<@szb0+pogdg@bywF&_lE$pEt`xtzh%NyW=|37#_GE+OO#QjOT#2qjYh`QR-6a zGEy?P%_c!p1^{V34z{=U&Ug(C&34wcCb;B*u~~=^0PxqmOS|Zo4wNM$-GG*muw+cs z23==|jFTsUrVr>}QAzOTe@p9wz?*po>Px0k@9dIk?v8yzUt+S~A&$G{t0U*McD-BX zSD~_%-F!x}V(?qzw>;M`w{(U4L3?Miskr(bVR~{7L>DlOBNcL&BAc_zJzLMH0XQ3; z&I&Lk66LIC7o)+V_rpHn{SW}f`s4B7t3PqP9MZCOZ}G@$*4!Sd05pv3a)7OmkQd?3 z@G;=Jkb#YCeQxT#gAopq$htqSR)|trKt^j5ZO%q&4m5eZM!c2T10_t?E}k&M zuf$z4HR4L7vrWZ>tvcK0hEKuzQr0~*%V{2!7=7q|7+e3^BLA!7#$Q`Fo(MNqHmA?O zOJC=_6Kf8}2}Trr{$r|D3V-q7duItzdh5h7`)hiq zuYuGZr|0JWi<U*p**<3oCQ(@Var-(PvjeJa!t zT-4C#Y}>q~_>AeD-rUaVL>Y?h_vTj15lW)E+ndi%)xnFJgSA{11->aa(%;th#qnUY zL=ivJ^oZWrg?J@Vy*If0j)y|+W3rh@=N^&XS5MyvLE6So*rt@I{twuevorqRk&2xhwz<)~=y zce8(#Q^XdJ2aXH;$wF6$eOeSeO+R|p`vwYf98=xrKd$vnD0HCL|tgc}Z4hN^jj(g8umXl1aTJrUY|X-9v%qId*tFsz(NDCdcX@ zuPwC~!Chx;he4$?dtTCgZBM|r#5!L{fnrzAMi#DhD3Mo>*HKfI}qRsb^T1YeQHOzTMIc_jnWvWR%3EsFkUFjcq3<0^i*Kh9g8@h4!nG`g84<{r1;ME}!O zt?T(VC)v&4L|dJ5+7y4$VML*5Gc6szCDB$-=20T6^=DTz=4rf*@5sJuhEmxdeL26* zeq4zOLk)xwvz?anR-)ml#F}F>k96qxhf?Nq7oCy1g09)A}=EnJoWaVNu^K za-H?%qQS>CqS_i^U+?x;Sg66rH34z_ZR{O9ZR%%9{) zdWv$E_0yH1+C^$yJFaG^Dz!`B4!v$8RA2sv5vqFOt#t1-9q%2X)i!Jv4kc(Ny_aua zXN_v2Q!AheNDn?emk)(~nnp82qxp-2w%(+s=Y-=f;e1s5JUd#(H}~O7dVDn}Zku)# zr@8<5RLw|;JHdu2TLq37FlfBS5a<~rgdd~fp52bhOt|UV?a}bcvuJWU=9CxHBaZa*c)9X#G%)Yldn(f2hVU4b@mgYEOwn zaqjaIaXX@&Q}>_$oNCwcZ^oNLO*_J^ybi(*p%adjjv?N-jEM(NJ{*#7oP;MP&&1&4 zZ}S8co}*^T)op3t0sez-J?lTmW*unggJ6{;L>j0QL`RCjId1t^zXzRLZFFwNSN;gT z>l%;8xBy!>-D>n=>xQ!m#xyfOhj)lkgv_yEsdR0^YqvBFIYi$#u7emw{{2bE)z`V+ zrsdy@Q}2!US-IcN;0B_C-k`6;66E^XwKxW9+(hQ`K}ez(s3(&V2wPNpPU(`HNlfR9 zqJXOG6Bl>p?%>;CIwzfG0nV?G6{=_qr=+0b$`h`%E_e&wHIRSO@k@o~!^Y1@9=d0AiUcF$1jSY(KtS5A!?-|{TlrG zpX8Zi0>!e@Q1}LfLTJEraUz$ZT33=g;F)&9LYh$J8nuo6P79JZW=5xw~^ z0YvO;73n3PZS!DUi6T~%*yp6w*0SCYhwmbI!j@_A?qL1%Ok-7da392^`qp%-Ybx*< z9@-yB1CV-LzjQV^8L zBgQmZ4G!>_c6xE#3AgE`jrV%Qa9i3GfDYc4Isk=#-F;_maLpOQKkTlG#ti9=OSv*L zh3k;Tb{!Ib4@Tc4>@ZxugFMY{Bt{3`Jtw>?}*Xd~ydg}Ia%+PcK6ZEN9b!gjEE z*^YwF-R*2B-rl2wl#eKBF5lC|yVuept`ES4k2J?w-nZX+Oi=B2~EaFY`K zAtZp!ftvs})MF66u4`9X*DwTtAl5S+|Ey$EPjLJ{&g053son?M*K_!U^Y5*@TCD8w z$+?UqH#rM<8eBEQl}=X9a6Db`)&3kVbK9=528;faxiGc}!L@XH3WIO`*+jaflDnu- zuovS=*OlPhp^nU?BZqzqBb-cX1{b)IF{40j`ITvSEr%e{nd@7FNIg33L9m1psfpGG zA9w3=$NwSmFfQ91Pd2|VF*;)wJSRA~$`V_OU7=8p<~OR^qRY?jc49zbe*O zLJLXrOcg|n#q0}oLsmMt{b&x|7aj!iJ|2?S=cJ2CD>q*w96rN8rd}3 zeST;=X+bjrgVvuFQgN2I?z>h>SdsW5ciGDX_p+WBJc20l<^$0;jni)?iQz0C5guGs z>&I8M__1~4ZO<%V;rgKf<3Ve`1VapU8?V6yxI7DU!jvz(B#==iL;FBDw0SC)R0Tl} zI`)T7p|Ri@$v}*uG}I<)dh%8Oniagf{xpf#Dp*UG;&xH+4C(&k5)xpLPT%g*@+VAI z>9-vuIpIWQCfG~-te#vk;NnmGwjIj1g}cJyi6$c#O?k6ygi0>~V(9mtzGh3+7Ka}tt$)jP?m+t_Jw1Hd|&uWjc82Zp@3Em zqcnf>ztWyQKGqyBvr$7b$8X~dwbAFQ+uWTunt%Y6YD1mb{Cl?R62ptZt2dvPWts1g zdc5{RLp)b{tCe=UdX^ldO_r}KTloy2&~i=x^_nrjkuBJvxval$Fi{x>aL6`jaBwpH zXOdTVxBXs3shvR%PcMgM=w%l8>C+G5Dq?xCDRj8_vGro-I8_Ag;i=LaUj$QsM&MHc8g?`*U^yIoN5~7MXrYcv6A$Y$P6xIlK$uGnZoBZ>2DJmh& z9%kJCG#0@E)CN5h9e;RbiXU_svZ68d-Z;a`ZKa&pkzIBVOf0M|la9v_8h;h)frqAS>LdW}s$rBLr$6moKKe@5^Z1|&x#25LT%2e2fW=Xm#1gFocU&jlv}tScR{+)&6B}w-jrwTDZN1qel;oOdAFA91KCQT z>Y=ATJ!$1)z#gh0%Zv5gzdkk)d}D2j!Ho?zqYMM2($P%F<&)InQxA`}_*AaNui>^! z(NnXDD`KW}^ejAI)0TCvi$nB21id5e8LxO{l%9?DCstWnEy|@}y>d(n-1krl-u1m7 zSK#+`Vg7sAfgPK)8;0`(=xcG;KSoo8w{vD`{Y-*?g<3B34`SX}k_G-AyntyZBu02Y zMz4ksIQ~$MjFi*{j}CyV*xk7BKGHN*H;`Eb^m;(Q&1a`T{*(4OHkzkoKs|wNg68K# zxaTFkc6y-wRJ_oAjduVM5?&=527*(^;}>W}-cKQyv?+4k^^U&_OxAcV+AWJO`xhtZ z`oqU4xH8h(limEkAk!)B(*T%V*p|g9dSHT(p2d%G_Ku5u-Ke!5lrBWI|BsQxl_e3W z2$bS%qsCvMpz>2Vm7}YGsU;VPZsFxd9crJHc{?x51f^e!dL1uic^wD&2NiZsL!Wof z<=tHMUm!g!uj2@OsCWBs>H9gjfmtMFi<4Vs6hORfC9UPgak_EG+>>K5GWiPcvuxSV zZT2qP&3kV8we(qU$u94*0FMOTl3%jJy(Qbc+Jj!*vtC`7SGN<%PB(q>mc86G$t&IO zmG1F6_78fcJJ_;b$DTp2V+a4X4SI$9yu#gH;fr1ag?{UmHuTY-kKP(7m@(M&A@p0l z`rn1;H{%?sae5ta_e;9Hy5BJ`uX~qm^GYx8zQX%byZg5`x4gB3$l2a)AK@G`pGN*~ zFAMeQeEdlflE+zgm@P>x|GLrX9n!FMd45pvwbcGAW*;%3v3xuv8eYiS=J0~-jupL) ze56SB=-{QbcX0+Yn&L!}*;MVu!U28bQ{N@Nhxz5i8Lblyat#xg`NIKBtYw9Ro~9~vS%=(@f}8n=)Ap&$I^QWrR#@02d;L6+NzzR#Y}oOLDtHt_Em{=Ln=kFx~z{0s2`kV5MB9t7ksX(3Xo_sPsok4^`qGPj_CT6l~c=i2aGi6zdSQ^# z`Jj`bLRo}H)Ysi$GrrX+cZrk zFn>73m!=T=G1pmM;_nS+t)j6|1%07lhq^*-`_9~POn+yE&Ix|(d|*|jZV%C@C(w(d z6DtZ6Yl{*~i-S^jCP1(Zl_2v7rRSxWrO(%l)6M$N_m_+_JhOR4*^%<%?B-9nBkx?Q zKN(kTiJ3y#cpogsEh^AoFf*@nru=Cj>MY(IjA-r7PRuNHMmuOLdp54554UdR35N=%w2xKkZ^bLb4WlmD-r^D-4(S#MaW`7z*mTDwP#-VFTpnubMw3D+73>O?sO zKRS&$SqhN_b^;uUg@kuZj2=pkFNv-SdQSGSUUaJ~VDD4jktc(haoEa$wzmfhUVWQ5wRwmYvJM^Pk6czX6@@7oR^_L=`dN5+7T+~^ zO;K=UJ|d5b$O1EhAFe-&nfIfY&e<`P17;xW?sV28WVLRa?C(r*)Yqijakx}}@1J_tj|iXkD*kh7@SpRO9sm5J ztOt~43dOaocXsmnZ2YWDXx#YPgISIL#f&%Rz0Q;3!`2SH2QxqD{B=D0^S1^QpPWn; ziM3_RmTtY@9xKXR=%f259H%{{{oU<7f2M2iQfsets6Bg3wP)*3ED5@um8>WZHzc4V zI-L-qofT0%pVnWF+)}b)PG`kbebrepSz9boF{86$nx3p|Uhqv+NA39p(71CsD%R{0S=_?4+@dfFZnxZ` z5J@~1lUmH9Up5&K#S88&lX+t|+#-9=VAr3Kh3^WcLEF^u8+~nHuyy|IY-8Am*{i)7 ze9_v^OFmJ^hs%lkvU-~J;Mn%njF?gDL2$JiKs|JqYdFB8oVE15S2J5OLyr)o03}6d zt3DZk#l)_+DfRF9dH!>ql>&q;e?{bPi;y@Y z6(DgH@lnuDjK~Zek8?NBJ7CD~(~{gfit(poAP)Z2f!8X9%$xFz+yJg17UkNHU4bxo zoj%X3I*y)5I%XZ(;GQb~`71ji|fu}t^HetD$U zzdn-l=1_#Hjb9HPP;*c;A16Z9HRPwfo2MYz_K(?1!^6kdSH_d`@qkvbV14BReip8; zT*%L&^_7b-oq~#8%(+~-IJg2hNmfjz@Z{i9p8c_Qh-8>4_+H}l<3k1Hq6AJMRb%bH zn!Me%O|G_0aM2$C%ALVN>=I^;R`3D*{NDXL1 za%ohuv*f(eM8h2kyV^mH->x1?9$-50$r)wrXUw*ZhRyLNWhY|mL4}D}i@({cM7e@< z+G!f8QE3`I@pWk$g-tBt#8wkU2~$x_SP+V^l@V6kJ*o%0fcMn%m5h2+3197{7}!;` zUPZBb(Qv0%DM{h6eVCH*ZL(&9>qAMR`oV(6b-`7f1=KRO_%i4$~5(W!fegsJ3Wo0fL|hp=QUr2|UD?z8KLy8mHf zf2hj~Kmp#b{+HgQ=e*V@!6VcsPmIxdl9;^CKZGSm+(*B1h4pdxL4ps!LKL4BO)iQi zS1>;jZ_=#NXGWM^CYr}_N$~^GT>pQ)$}azBbHz1JnpK>fRjiLE@aL@LXG*-v z4lG687kSB96Ov1_RXlbd`31>H+^@QmKtra^S)RC8_fsV1bR{E;oL*w0>Q3%HBMTC! za~N+cv&4EqRCF2-YecxIGK}9zlGLD1nFVWhDD58o*`o~35i*?aEr}N^<8J-g3w-Y2 z_aRE@%er=@>Vdhh6GS$s7D=uO2wYZ5iZx#^K&ev8m6|R4f}{fVV4Jd3dl?^)$OrB& zl_YtQso&z2GUc{rWqI!2hS%3v8{JU*rhD#CD9N&N(Wsq)qh53)lw&Jcpn(-!t6URz zyBIb~QW@sVVhy>XxRkehA1|8i+hulVj!qdlE$Qg`K0Z@Av-R%i6Xsxt*Sdpu#!{`h zZP@EgdckY`i9VUMdByp>t$<66Ud8IZv*IH>UCwMooA34}{eA@wF*>jFyh(emJK39b z=(>^Kq}NvzW8IG+X-BZ(kLD0}Ii;(#II$gW3Q)AkUgRijr=!n3M=kWG^#S?PwxUF? zKl+jd+|yqPp!jxKl}V8c2B6*JZkgl35BSu+q7mC0%t`D{zVKtZtV{~rm>avBtm6)# z;HsyXNPL?XTxC$u#dpF5Bvfq^CcNzc|FMfdycX1F3fTJ^ZVL;MZ#Sn0++Ru!tdVig zZTmon*nhr^E7O7yy_}hm9`tXmW7jVGt z8}(7Kb>_i+_bPd)YC9{GpJkOQ6E!VADdl3W2lw5pN?p~uC6r`Q-qZe@Ye0+RB_Z@L zgI60J7s{J>M~Pm39VUgOU5cK?^p(a%B`z7c7(=TX9bTQz7d;D?_IPeLm0Cf0{!#xv zyLxQa{Y4P!bdUHboXEP?)Q`N`A86>;nTE--Q*BK&AA~8fFn#(ac;8aO^o`?*Fn#)g zJ&%g;%hy|4cXI80XG$7Exk`OrfC99+o%lGS(fZ{tGtNV0l8>mX!g*N2PECMr_0 z5Id;5a24OWZJKUJzehbP@*rA?806Cvuq(lA`1cSYY`^vqh=t~dkO#wc6mds@ABrcw z07WbKu~qno%iSt8*3tFgr>_`k3mb91)rvOthLof_SV}}XRWT}P8dk+Yz*N9Eg>9wW znqj#eVJ^)L^TzR`Fg>*v`Zf5?Q_CFhOGY+=FN7|b$4tynaXrX*O_cq43>M%Ri0Z7b zAH~_x#i4(B>EDsoA&!WuVYQtgdPnG7*+UP4Z2n@?lsB&!Azxxp=; zXTCa?F4GWcU{xgZHv2&!$Gfy6eWko*RU>64W!^Gxv3;`)bN8Y9=`E|uDfT5sHgtu( zWfg~Y{qKe+y`Q9CcgDow(@sVOD+#k4m4Km9%uX=k<9P4;wLwWAV@r+a ziO&s<$0eFau=_HTkx3s>JDhGhL!b(#T>)F>2iz{9zsU z13No&3-j4wYnlekABwaJs-lStjioz*Dnu$C3`3E}xaXZ7_m-3%_m?4_SA0=|{nmGL zR_22xLLX*az?B4dECV9LtN9BMNoYQz;njSCKuFosVC~o|+!FABoP6@r_g(l^#n4T%1Gn>Z{Xu1o%)9#E2gv}{NfH6Z47cS zP_PrBv7IW2mq!W9jy7hUMV;wSA9fkZ`9y1;MsiLUy4xcg`}xY?^+Ak3X)o_06HQ_u zeA~4Btc<^I+6LAjnZG{xAsCG!=o>Zm-uo}AnsX?qrCz{%nH!JfAuPwP;F>ao4|^8{ z>*o$F?8S=)FO=VyrUy>LX=pHpBAQC>$x*m1Oc3C-2EXq_YsCSvyl;oc;(z2Qnqjf? zAC!5a!ThD$%L>~Ym(kvgu)T4B;i+2Kq>GL(=k>5jGj8;P zim$!}p(ft-D*iN_d!KNGd>%f1UEwl(%{avSBf+Q{%=i_PGf|4p2%O_KpFst>KdLt` z8fgr(d&Od$Po6mU9$g>MZe`i>|PyKC9<`z+s>Ft z2hSI%Q~_xPDhX4lyD;EEAVA^ryymf}SSgFEh{db4;=Gu5frgP+KO{{`l@>SWisDc@qTa8udh4JoAiIz zML~bpjrJx5*X3s3>>0d%b_iZ+4A0Gs3G1`_kow^pzN#n@d(a#m%fIsmkRSWMI1ziO zsZf->gU$CfxcMwX{w24`I5l{MUR30*Bd(yv{g4}X{Ys4+mJHKTAl=4|yQ^4l4Gxra zA4mwj=BI++O>}m-@~ceQ>W!4pH@#lzv#iS)!JAMA7T=*eP-t#eV>7XQfG(%?WMC!! zJq=G{@SXOP0gt`)2b<8pmJXx57w2CCE|ZsKZ`~!JM(0@dVj)Sp+)nvi551Qkk}rqg z!5_Va2SSy(xaGzQbXvZ|bIXn9NNZIw*jQTMFZ>2)XqB;!%Grp-Au8yiEBpxxGqfte z+JUrsTVKU+>$~tRaUyas$9-lq6V8OiF~agH?~md!+<0buMZvi@1x;T!m&UP;5Jw`E z#8`zy(qji=kBNOc>noDVJtiheZfQe4sokdCoKPIy%O)0)q>27JC)pfQH!bkjJm`0z zSmp1+gYt;r-|vUYsCr12X2FQx_OoA`ChA4}Lh$luIg6_9i*sIV2-ZEEo26?w2W=ZJ zO+nlF?dxM(VTaB(UBhF1%oCn3^sYY=(|}uJ=*~DFj$cfF5B%TMyO_Bgz6IL$NUBUM zowjy+5CTU=if1w1S8yMYFlAWwg0_cgU7JUL$!5DKl({vIE^(bL&I*1#FWegIDvRwX zsLkssVS+1B?np{?n^^@pT)2Wwa_???kKW~e8%`670P$0#dXu7at@}TSIiY>+`AoE* za_P}UdYXS|{RyS5Dc=T%A+b7Y;82ia70`ayz~jLMuQO14h7m}#sS8|7jZG$%y}k|I z_rc(-7S#WrLvwuaam`CIxnHS02hCPNU*JgCs$dUiq1WN^fAF2b!6TK$*&QzWvDfxV zCf~P7qj&QKoVL3qr3oGVnjp_X99SeOzn1Qe2Vj+rV$jG#R7e1yz0vvHcU6I43Syfe z1HF#T$ili-T&ohCsWIrci82T_tfnTysGYh%=xIhF+nJHL5{~x(ohqh3agB(+v`T1|O zhnh#b6*{ETne$lu5LWuB>9I?NWA^^p|A@~UN-BER9)|>~9s>hBLzkY4r`Nmed zIxUjNy>&4H+#6W6!JUe&eyXdnCaf;_4hA(sv`KX-9_;?I!?k(z+JD^k49CdpaEYlM zGMmTX8KRNF?<6gNJ09=9b&vL%HY3dsZ2&i0Yy<9a-Mq6D8bC+vPQa&bGczc7NSYl; zIGw2x#{R}-srole2dyLF8U){dh2G$*+m^(fU|v|A!e5R)-gIXHhu#BVwIQ4ddNil2 z1n2m-4}q1o;fhfj!2y-t#o`6!yn*8kM z(~@n-@pZCDvf zdEsGuVfb}2*{)H1jH+wG=TG&68QYYc>f}8Y|4$S9#%^`JMfKl6_zF#|y)?+vLYp2z zM0u%3R(&B|dctTu+L}IsXPmHK9f!i{whT+1 z7N&+011G!=J{+b#IIL`bn3}}_n(9bAIPxDh+QyP$sogF$v&)~QKs@LSiw|$`kuY`r zuu8riram?-waujxC-N8(%9YBPRb(QR33Si|Ci2j}|Q;!c$`jUx#qHb3rh7gNeL*&fufQsmgK?))5cRvn)hi{eU2@Ulzqx zX3nrOV<>}HBLLKjScz+fmFRiky(R7#R^k~eF)*x-jl)X(r{Ok&HR&j! zAV_LhC9P)chzsltUDbb_>u8y17COPL=0*>G{R}o+X#V|B1s)-0MUv*fixCVyHm-%) zAT-PBpct7A2G&Vay0O+5xQ2tVY*ZrzbvYVzeN&6Bt|N7eEYI#K6pmv_FcKw>mZ_{BgpI$^D|FJ#x@FrJev_;$T1g`L&9`a-nA-p@}otNB!Z^0M%p zK99+uPz{B&Ak$%H)S7qKR(eyATp*_?pO76%=oDorhRpq+POYTj)zqKAus>e@!qEOe z{+t3b$)Q)uP?H_uc1Q4~>3uBcxFIh-soITxxT#ln!kPO+^hBXVya`i!k;-AkWbPon zb)rrcdtlu=@X7XYSPwVm=MWB=Cm{ZV{2RGZ9OI;|-Yx&*60bn!y3M;qHnU{cz@bD( zK4fKfd$&B|Qs*hGiFeBb_E!Ib>>qFW7x%KmauU4A$(A{1pvzf!vh6fo0=)#E+xE6> zVs?n#l-5$GX$Od~hM8DwYc2@sH2na5AqgG)&=*Mz?u7Gz#7CDunbgM%!cUy7b=kND zDX#^)6cWi>cZ7PKt#NXmP*irZW?T+18$Da1Je0Lcc^&~QcO`KpUAbB6Tcn^Ts~;zw z*7cm}fl)!-KK?xi%-^g1&olDax;>hM)^9pN2Ry)LT7_O% zc$Lp3=ao1mrjIEDzE7fVwb8{pvh=z`{G*+M9||UUM(SL*-fHZ`$) zgj-r1AP_|NZk$iP64rm{(WP?uW#ZsNB%Q9e27KpbS( z$4%#@7Th<#8sV~|DBxVi5WA5DuK_a73<^GK_Qg|>5r;-Nf2>ID+2HWmmgz>99!hvj ztqPB+MZr72Q^SRRUr%mm`#vioPAwX1IcHYBKP&H?S<%i}5~yT#&N4F;!hRL0K7oZ3 zavY66pdwEI5S~_F8mo&5$Yu8io!(WKezDGbx?o*oU&e$epaq2zT{C?pwQ%Bm4gWvnm z(1D{>JcphS_;_1U4h|>p;|K&|7bL6N7vMt5@YAn^pQ;`lU$t?3)i%F+hs+kYjL3Pe zwS5Ev>hV>Njj!s$iCy)be$_pMx@>(jyBQ1O*n^4cJ7~G3=c9C&=orypv`0m;mhrI% z{pve&wpj5yj$d)U<8j8V2$h89_=Bv z_{B`OcM1W84X{D`S<5wl6h6r3o}e_fpg#I0>K7=eYQutBEvUmk-#E)qOh%1YrE3hD z$fWmD#j=rDuWJ^B2xvu!fNFz$gms`*zYFf~96Y2~=ABb1)VK}ZzfhyUv(gYxqH=;C zyE9SgFaRo~MTz-S(}>`;^3-64BZ3#x=?)PX{oTb(4cnjU9jLt#_zj70=T^!{bDhWc zm!PqhFikv`%?|vUTGZQ4$L8h%jmyY!+LV1z!wGZS zq%f{;fHs}SI)$ULZ{>h5)VDE$Z19@M;AC)+^a&fw@Vd9A1&c7>Jls0ZE4tFuZO!OT zXzE;$`ytVh$*Oh1ri*g3a75u(@wH^J>tlO@gP+gMy1x)uaa5ro0C2iQCS2XbJYSyu zfHH%ho%arAYD7Zs9N8BJM(-SXIQ^7G8U3$w9z))&7sqYDe&<9(BO=iR#;GLJ3 zcwAL#Ds=cbonnQLMPIbnI_mu2P>s*k3?9aNiDAa(Gx!5+4Eot&2#EQc;zGGg)7DIJ zp>oO-4?cgRylv@O{>8z6a!ZmJeH<3)`uTqYi!_Boctr~?`yX90+!ie2*RNU!oQQ8b zj-4sXDgRnO1=piinf9CLwfz?<&Vku?lxIW2-_^a6H5m*Cqjm^#Wq82s%~6lbBF@63 zb@pUfyF#&cT|xUi>-RsnX>46R*)e#N9fLP{h`}SiBt`u+Jm1Ysgi`~UD=^0K7*BUz z2cMX(0Y4UeevcdYrTjAR6MST&K8`hPII=%}LX59)QSiz$bjf0-n^xn38HS*@y3tC8 z*#X?+jtCgneQ-Du(EC*gcIuR6JMdjIM_91>+m;+dudYgQMLCpjm)#ao2U zjT5_O^^$JlEzdO)Qm)8)sRdD_ys;;>2{T_Mr^1L z8lqhPyKiSd3FTE^^dx^GPo_rly0>(%`nySakxg8Y@>*B4sgg!MILHuF{hof&n)7%j z?&B`+VLU9wieBi(4HyGPZFJ?(m{**NHbG@hRq^y`t6!ATv$RLKyiP{cFjgm-<6iM= zx|Up(ot*mLHlSk%{)W_>kZDzp3rh8CE%y>uj^0bc|7^6Xaap+2*vn(Q#s&JmO%5o~AJWliHMO!zI$e9;u8hLB%-Sye_o)f+guFr0*h(w$d zo(xO!q5bH~9ACu#%~Im^CYr6R`6ez?qD*s1)Q=^OpYnY2pJdxR{^%8VP#|)OH!<6C z3T7e#X?-iQ`jFykO07)FgqiAPq5a~C+M7I7wfCVGt-}99{kUlniop?DUZQG%3asmZ zRR+lzJA8ouAQtcWG{j;vpeXEhpy4pv4dDqsfMm4c3=Zw!9lW;K;?Lq@EiP!ioa#~f zJzI*0w4mt_`pcCcAjjTF!KzMM)>Oan353W+Oio=jEDr~|u)|#Wg$cD`ib@8rB~0vK zyhL5rO8B{;G6o<4Iu2RM!r_z@GBZ{YcxmlT-7jj)Q9p-Kdr?~l&-59&AKUO~Q2n3q1hk3E9ro=wO7oQg(KQiA>3kk9tyPHJLoy{ zYwl_GHS}swDSz~jgjvFT`veI?mOd-z*jKrhGoYOA1N=vQ_2d{TL({)oz=N>-()Oj2 z&Lpz=OGK}7NH=^@qQ0x&-UK#uLr%)*uVf*$jkA%qhW;Gx{>__%jrF{nKZjd+qsORh z86=oThTp$TiO>Vr&Y+PJMAI6a+ID#N4>365%bH-;uXTCHL^obzH3c&%CBF?#Rl~h9 ztR~xeWr$;SoavQe$n}D=M`j0v{_TS|sNJ2%Lrx%GCN1UverNDPx+kW;@ZJ6W46rEp*c$m~m`xR-e+GNZ@Rz{V9}RZKjBBp_$uvr)o#Q;l z;Bm2HjmtMgYkPLnYaqi!MLwreXGMu{P@&Eaf@zXNh`se(^nSqwPE#dyo-#fVQ zN*?4A0HVTQxO(t;gej-sfD(TJv_v0zK3Wr8tR9`Nj`u;?H4oGfP?R5vK`YH1p>m*( z{`=J8e>8;A#&3DL@wE+5t=b;ktTR5fq{lACsq zC67SEK-t zoqWQ;VU)mO5uosdAYxb04zVdG4E;YE7)-1|QDi{OR#s2Z6o~%;r7X+t@xtLHtMY#e z%PIe!ezr5|O^iCSbwtwyS)}~-9meos(_t+du4z1^!&?6Jw+4@F&2F0P%iO5x94q~i zl&itD`B=>m>M-qH(_BRb`Fxa~@DzNT2QM~*_wcS{C5yc)TcDr0wxo*3108c$Q&83)fN@q9u!So`h(a8T=NHa83@IxB^g zSfBgLzzD6qW#)GyCBsr$@Rbr8-JLjX1~164?DwW;v$CQHfpuq%pm1BFx(jPf&~E}0 z1&Ky9r&=n6pel`^~V3dNg`!-7HvgR{|-ox#kv4g4y>rwa9?|u$j zJgHb80_AuIz!QuVKZ|Ukc?uFiK1C%E&_p-q&pEB;gNSgn6 z^H>X4A8lPruTDnDPX2ev_nW)<_}JZk_kh~J_Py;dbL~SkSz@k_8%fD$nUgv7QS&R$N6J%{+Y*4=yydMLKmRap@TCCd4(q&=k_34Tm`6M1Z=8EbX2c?CT7%HpLdo1s6P}vHcodiNo>Qu@hiw0tHvr&57gFB9evkE zq`65oty?2*+H7Qxxk2SHQDf)|_jw`wak$y~qgJx7rZ)Mt=&hAS$yG%&Ml^kxLuK3} z*?r!|Q*@Bk26xg4K(`}zL{ILmxidyIzvYk8xWcQl!pEgABy`yp~d{umEvDcB1M9A4_*_cCLkqK(6Om~)v@vo z=zSBR$jW0)6KBSV#w;k4;2S(ADhvItgvV)?yeTUJ>4N^>O<7PriORf@E+OB3x%ins zZVE0u@Y=(TOufaZk>0iQvRY6zfD515=BK=a4P*KqOHA!OW$T*a1#b8h6!0ieTZ(&f zypy>e=}6>n^hZg}gx|_YxmYSSpky^$5ZQ<-q91u=I-6?Lnkn=uvJqkzEwxG)=39P9 zq862#()tRvsh+Q7M9bGb@Ao4c6Ol)F?~H833g%);*pn0V3{>3ouFg{Lwka^|#yt%` z0XEG5tTK{-5B6Zl$6q0dK+03EJ2Bw*|L5$~LG`!s`%zl>OZ+}$3G4Z$zg``M=&(q> z#eSDjJxEef69Mj-n%Q})!6ms)_XeJD74nvX6hj)$(NdT(*v6fj9ZKN-(3}*fNluNg zDz9+>WQSk4i7&iK81_t>k9;huqZ}D7KGo{~fDcnRA2qPI?t<^1eqbw7cPOWmFCzbGlzPk$Hqhq3OgcCH9Byhtek z^w@YXYM#jb{MI!CSxsMDUKf1fBXlaXWS+>Sxy*Gh!Eg1p!SjgEb}AgT@!}$FjnJg- zox%CKhL(eLq#IDSG8AVfzLqJQZ@$Xp@;z73#^8r(1OF%%q57q!xoV>dI2eG;BK8t9 zv>p8s$ND$|I{54Zzy|TDa|9TP6@rKp#H4!#K#lrPr?cRWJ>Op?5KFkb4g>ZYu(AB#_K>J_rj zy#FkeSBj|g6Y_R?Ep0V@^RzKkqvioRo}cL5qk{(sN>5EiBs3S(Qk&DdCPXB$Vv`j!5>@R! zowtp$=bQ41%id`IPy$c4sNZ_)CcLM%Q%MOf>3Dw7g^Tg~g1P%R+ZQeFjBOxGX7o_I z_(D4+Gi1ALO?1_Y+s&&6C~lK73z%k7&SefQGnh#hMiP{hm)^w$SZSoju%)1c+@8_8 z9|V*~p_T7^?q1-&i2D{0e!Kz)Ufu4;x`-s|(Bf>fqzL13L`rIc@!!xupTeVaE!%?l zqhQpkJwek3MT$}D!IGEgW7Qsf{|Y*_KaT6}H-t`e_v<{X3T;5z%C$_Zc8{4#ry>$m9IR2u!D*JcNSX5&>&iQu)RcPUL^R9y$h>=p44@1Ik|% z^di-}08c-S)h9`*W`|a=sT41 zCiW@eYv*{SJHs;E3vf?Q1J6l-Npj&{uaG8Q^p+g(N_)K0-&w)mRV%Nf9UtoSUS8st zT;Au^b-P-=ALi`#I{rB5ExD>)Iat5f{m!eqe52QJwi^bew|O17Z`bH>-)=3{K4Xm` z+8;JVYzTFzcs_Le5aPk96)P{ zj(DY?yoN&KUuC&c^kC!^Jmh!aFdsi--QJS_OHEU_e4`Q<9eT-DFR<17s8@>be4EK* zR_~V?tC#M%y8KHUfE@fU!Lfg88S7XEshkTi0KYK^?@NGp+fXph4bg1I~V+b0xZII^cZC`TA|Pq#r&4? zJDJ~U{FWh-FQ}Lkye&NijPfTFE`{H;&yo-_?-{Vge=5w%H38y`fxWJp)FKV z;4YE`%mp_Wb5IzMIk^6TIRZ1$e+ge zOBSa^!H+ZnRRmX2cm;^&j0q1(Xue1O%JBVt+<0&ru0=vY*qFvHrX3;0sO2Y1I-!sq zWc)Ty76s24dkZDw+*BJ{F@$R^9)gu;>41x@{*Nxh^QYv$+*ah8333N;Ka>#K+WcqtSC#p znKzT!skc()&Cz9}1$_;_c%M?|rpiRlZ|@ngk=r4Zz*A|(dMi%7S^24{x5)X=^o)2U z8|trM-80Q&I&V>zMSkIpnwy)}zU+i0@hW(|saN?!TS(Bu9ukXLmA^0y4YCe(CXv0` zN5TK{0Oe0wTT7Uhti<}!l-cqBgSYAM*{OHOgEowek*j2i%un%6F+W8^rQ@ciXeH79 z73@l=o@vr6`GjprQ#`OeS$2jap>XRiW|Mx189pxOCc>-3+^URDe-uK|rcD6t&~k?R zmm`AtJvR&|GY84TQry2paoWmB@!U%M(9~`3;hN68tkj_qviI0DoSnQU4SR^aD^KDp z5j;J3+NpcdE0v#?vu*7s?eK1?62_af#k*xT59G|@dexea2;_qVuj7?@0laI~-Hm5xA9#FjyP5z7<{l11k0B(g>!d zJX$nLN^D2eZUT!NXQ9%ZXRs>?V^yA4!7u(eSai9F+M?|dZNGw0(^+863GKALxqBS4 z&GaD>>O{LD=~Qq6^18F%_xH)`ZUck-WqDm*@*BdxH6!)+=W{hRCr{7A*o+~!M_T_B zS@CD&WaOddnrEj^C^k#I4jp-{$FO)xCJ8isD3ip3x*2+l+F@qQ!ElRQf9qwVazv`@ zrTLjgx&Mj`ijBi~-+OLGrTG~0Qkkjm%0U_F=E`She&@Az(zB>OT5?G- zPx@$yV(tyKI5pMcoXjszY3(CB(c9(07_kk$5<=Bpxx$`Mx7~6Q~re}Nb6W*o_wstVxWz0@Gw46$g`2|WU zgQu=JrE$+U|J4=0mEx7cB!h*kpG!$Kwg)RnW}^?6UORfdn#FZ1TgYX&aDVcK($>v+ z$xCP4(Rx*Wb`nlt<^VD466O8L8__@-NM6SCK=P8PUx~g>pFfMghnsbj%ZAVGM03z4 z{8YvwMpNKd#>zxF`j>28hSE<#8Pgrj(d%V;n>+llV%yt(&ya@$iO9B{7hI%tVLa4O zJ3Lr>p9%d^((o@Jzp`kx3y_0fFEx*o8$8D^x%sU^%?xS|EiPRQMDe0&$`wR@Xg-M~_s-5*j+oG?T2vhl zMaNv51$X6BSt!juoug}n;{755EJ(gH*qOT~JuG8LV0$zAl zG+yIBuIiFz!$XlfW%N6P6qUg3)U0B(6y$Dd14sKq!SrvT_TvoUn@2lI_Mu7;I;}cy z=*g;WM->NCe)m{4szcW2?asIddGFD^Y_ek{zQGN|+2y-Z-_-7X3-WMu-xc24 z_MHPLa%>h81xTzr&9S?xPF(0G<+?zuQR}mV;XZGDOR(%h)1_t7e;)0iFbx}`I)Fa` zGm0SS7Av4iV`P@N_QD^7qKoYDBp!WSbD{XZNb=iWl(2GLvO=tVD{pRSh8^@O_$sb4F#Wv{au|rd+Ul|qv zGo#A=uF6|perNE}>_eW+lVT6CcPOhc7LHttbt8_51-ynG;j4NPW$H~nrW=&z`eU2E zsy>KZo!`qTBd=u92EMDO=h3UWox|8>_FVk|Z&Jr~g&cFIDctJ$)Uf1CJ@sHNx^(9g z5a~;v9Ssu*v*2v!aH^xv>@v4f8i zIc5iu_Vf)`al84g;!i=9ipBOE`UPl-zMiH06U_V=dikiVgAYpc8gB*EehyvXy2&7v z>iaTk7RhZuMS~d))%^8_HqhlqxxZScAfyaS3@8(V7&7L9kmfx7_qN*2uKFv(n`o`l z226^A`qHAHBommJR}K2H9cuot8#H^1J4hR<8@vV8Fm}O>+ooYp&*wDbgw$>4x4J8J z|8tTzakufG7m?h+Q4mF%uQ6-gqvpB5Ab~e?oaZ2+-XNi{B>27-cUSPh)^}j_*^S)2 z`LRvdnft~H$(;H=>d_y!zpJ(-n%fV31O>yT>t4F7=|jr2K(raqBj{z6zur&Xa&v~G zy5OI3Q&4EURx^Xd> zur}~Fn!2|ssH12eDQUdY(pQjf)NgIj$RkEWnQB7mCLDbMem9+xWJKmlIDV)UH%Oee z)zsBl>2C2WQ5tIbMQ5c`V6H4u$>6rQsqCRHgu~Qj`K@n9R^JFU{bWD*YW#Ds>*CWB z)xAhqq2)G-xE{Y5#VC|`{f2%*_LU{4wyCBB1WVr)cMys!=LLUOeue$HfF|ZG%aEu@D z0O7*O(57r1upMK!xU+_npkA1Yz4P6*s)<8>*aF!6TRb){$3MpH_C*zu)nk3GB$}d| zyGO8?c?*Jn#e0SL7nE#KajlG^vA@jj(=sLdu3GAA?JWkSXjeu3SG`I2KE{d|254>m z2(RtuJfUw#SI5Z6kKb|pi-$p(wqUz4G(S zECa)ILt5Ug^=g4zt5|nD`1j{^zPv!~)!_=~(M#UiURH5M-E2?^Pn+O z=FupCj@aqhHg&{N5A7sxc5R${kKFB);xfIyV_1n5jjH=F>A&|fLQL$HNAdbUd6zz& zb|=4g#aNsWcu$n!6(qZ9VQ2)jrBLfg!x{((qEzDZX7>dpx^7Yi^2u9#l!PM%1ZwY)-kR}@Eqq0R6HUO)w?zt(?P&^*#nMgSZKXdu? zWv6TCN|5(Ho>JwI1L-4i4?`~P+WqIp#%4#k(fN?g9^{N*`L*_QT ziCWUYL@trRVVzGuI|;uiN{+ugXj552>dM@W;(`kjK%Rps*y_|8dP$7lh<>x&x%9j4ZNv>Yka;El~A z8RsQ=M=DENQl7rW>(uFU>M+Kq&LK=DjH?+sN&b8M_cx7!yqrql60RWUy?ortIrLqJnNY-2 z2k_&3DJa}M29N&Pj2WvnYgL>0BOu|U0}W5ffbl7JiBrGZ`r%F5zH%~^Z6`EaNS=PYG`r5z^{Wb&7@%A^(z$1ThGoWP_)KLL{{>B-2=s@hDa0c`ke38ly zG(5!ARXxPi34c_ny3`D8%9sJ;9W)I!kttk27tG6F8q9giO+lJ|;oI_}RHQ5vEc70R z>K?o{fACs4#7G+%1TWn$3a~WgQd9JlQJzEo6{0kRE_ghOZw03gn};1=$USW8-Y|?G zF~D@z+>!sz?iq3Z^WMbrh_>PlBR6J$c+1xF+xas@!a+PAsVHe_8XbK2B)20fO8knF z%|Qg`aZVqBB90cG-q})Irx2Sr@u_8`xx2LraUofxyq6plJ__$6HgI|_LZR|w4>)_; z(3_96!MZpYiF9i8wa10r$jco?F2)%@f;O?<+~|u%sJEh!V8N< z!46V6ge#`6%3rPh+9O3sX$Npy(F!v9w0PazO?pZDXp zkz8)>h)!V=ple$@N2sEIpdzSU2%B9NErifH?r`1g{L{+chcJ0nbS1)Qg$Ly;-iZ)u z{e$nFy_4t$ZwM2YZngzq3MQ?y&V^`n_kq}Mb@JBHhCI-XuWC8auv;i|_fTgQvSh1K zS177VutB5hYJTwfUAfTvO=oJpqn}~Lta3HdjSm4U)58hH0-7?-Xk$Yag|^sW8z7UQ5*-LhK*FE4XlJRqR5E}{FgOIbUM{6u zZ0)XXaclddyZ)56fUzn~fHFZSM5Jw~=tiaXBH0=(m7tM%zt1`MPG%snwEK3upZ8r` zCik9m?)mea=RD^*&w2jr(OoygvK50a?Sd||h!{|p#dYMpSP4k#YYN6j8o~UgI$IQjuge!aM3ly z`fdPLMVZ^R>S59Zi2eXt?aD=obSrDDNgPQ2C>9`-kfh;LLv}Zi8XnRpe2sIz;wWca zt}VxAd{X{e)2RchHG@0U8GE>9fQ5L+lmlb!q2eXkhOPWtgyj-~>nY{_Dsw+PV&*R6 z$y-L+w; zfnm``wq_Ea?ZA@Di>rF-^BZ?B$t$ktMm$Aao|2KqlPz}kI`xc@ip`U#g_&i*0rSLI z+;4?tJZnaQg~u{U<@{U@NCX^f{si+jdrrEki`pgre=#3{|DBK1*T+z{A`s>**2n(- z*9Tzz>z2shZE=W|<{68lJ7sa4xgMZRP^iC7R-#sS2K#t2g?;>Q;}`yJ@c+B+P5*P?KlrTif6rfz|Ev>NEYQai_`98* zaJYXa^2=>;s$k*2@BGx2JU?-C>Xq_%=cl~onRAqU=ciKcJdggU4e0E}G9LW9&-TQ0 ziW5_PKPRT9loL}uC#D^KGfU()oS5pp6Vp^VG1Uh(k(m`p9-2OydT2@^_`o~${Dl2x zU+1ScKIHsFl*xY2NN0C`I*&%L=HE^H`!fGhy4MFi{9B!;#kJj8o~K2|?473#>jiKE z^f(%9aW3|zS;TX{kW;a-wS@!rLn6kLCFzMfkUDy(A&2Syq=Ttaz5nuIdWxXN>4$0K zG`#rlTYvv$cnAI$-k^~dXP*WC{f8uee>lDSv6LI)Vf9~y(n9Ud3Z?(6)NWco)GqHd ztnQ^KXX5wY=KkROK(X3dz|BVb{lWJ1`-5NC|AVo$9Nn9{S|!q&=zGlI;$0DkJ?_;2 zH})gD5bI~YgIGV>k63@xX=42e>B2HW{XV3fM^Y8aiiAFSWs=YD|Y zZof4DXCJa34CC&qKY7|0lk&97X!P^^o5{b${Og@P{4-DQ!+(jS{l)%E@a0Qi@|*|J ziZQRB*6Y7SJ*N0C!S!mdz7Uu7c~%QI;<@My5azDgxwo8~L0ni7_sLc+^5VV*uD+ae zR}=3f+N?b0`s}r0pjzYDRoJZ&PLr5g>9I5qX5uK(SBY|ty-n;#!|3p|t)hldJ~vs) zClAhpuulwFD#qx1i4C~hUb~dCU=FqMUYfg9U+u~b<%-+}a1hlVlEV1i0ju_+z2~^M zzM^=ARvS7~GukMYfBKs+>Af ztNHsZ@1o30AQJIgwdXfV`DA;ZhXg2V#LGm_51*^~xR8;@c$u=|JI(*~pySK}?yo`f zM7&HWLc*DS|4E+3uIzqmSG-K@!tRfkiD46eVxE0uf5pkSCo%+j!nUL(T?-{Ar7cH-Tw1-W&b%uyTds8Fq5GjA}TlBSg(i$ zA`ZE+vaqJ+CJvxEpzK4#Vheg`*1@wh6O|kFgSfc!)Q{UtBN5#jb_{?hm&+-3qpeIu zpFTOXH^u9(*XXrNqt_k3O4V%=$T5EK8nZ0F^|0V`%j=m#9@a=6N(%JA`vaLD^Q^-(6<#ta|>Fna*gqikXAGx z)Rnk6KRVMKP4mkbgF>CMV+p^pN{LTq1u>K`R&AI0A#fV@tf9R5bK{|05^xZxOe@6n z^`Bn=9%B z0Hfj2za&l&Yp}eQ6U>}m`-3*p2q+?2z2`ryqASkO3a&LnCF}_7izqe8mt}rlxG^N2 zhP=rorerAvX%%Qz<)Li&k|1EJLj=`-6=s{Q6O(NTzKPZTP09~_#23P`XQ+Fi?1K1W z94MHLKkTVyv`hJtB2-5%Wy9jiCtwv@U6BA^MDqC&zrNbP_5LZ&$}3pTM1#KtkI<;L zQ8{j$OLB0)5VnX2ue>_rTm*fTR_CL+I@JAAD5~ojdhB7^w^odO41^HR(2JLf>YZOV zrdrIE7E4l6@WYWAkBlNY>;$BB93e~V(pY9IeZhcR+-c{dvxN7msaysJRDJY`xWiN) z^17W%85$B1#xH_n>Hx|t7|okRDYM1d;ce1W3+9vN+;H`}AW zxB1u2zXbn2btvi^$G?gEyODq1ngSn%w&EYV#%Y_0wVmg`6(44J8e247{AJ^BAy`(M zqG#o4S7Bcld@)VGs%Zmgl;jS){U^=8^RAL%zN8z8`D2_v?eX*_v#i#m$KFjOMmHyG z5c)&_7qzf+(-d)Es}T#xfGFaMPL%wLzc^1Z*Bv0=FYg?OLxWV3kz=($B%vGP10Y~N zB*CujhaTZ~YV{P;eq3JdXZb}d828?dn|U;!dsu$AY~nZGC}mk3L{Hq{J~;^ZPFqpTu>Y=q+k4{rURHy1P57VV=Y_N8QN?&uHg$YeP0R-WUJq}N|WjVdl1ui z=@0~LjosMHQ@nAVG{S$F>6hh;nf@abEL2ACp~qY+YiEM$k9^>ZmRM>yx>w?Q_O&cl zHW9R+Pq+>pjK=*WX_NM3uSX<%ZEcZ(S+RuKO>w}|jqM9uB;#&aA8@oStIe`(=^Sogy>9jG3|94A`h1n{GaVM6utwuW zXLk6Gy&jl#hlq|Ib|IYDBCXktP5k0&t}e`M?MntAu@q#@#*H#E)i2a{KLQ!*^-Vj( zvL#o8$d+on9se}PppJigL(823Mdky<${H$5g_Uoc;hCM-^i7sAoq`1Yf z$H-e%M=|ky?LwZ5LkA7}Vjixm;JXVX<=2KiOiI-|*VVUK3Lg!-2N7H`RZkA>Ev{-K zTDdW~s;#)>;uv||ZF^@7> z@+GzGX^oG`pw+M0xPoU%Q-ILGYFtg4t#ZO)=L00GmRdm0PlzHd1{sx@dAUiqkfbp& ztU+xz%5n-jzaE=Oq)=6>0=}N6u(OTy*mF__1DvC*;@EQncwP?kV%s@@);Y9uARkM* z-PozBI{^)GM{7$;kyWQOJsLAkQhlV?%TC?t$)9;caHN zwdG+7n8R#6pXYMl;r6$tS{`M%&eHh%JPH_`uc}AEedi5g;A#r$yu>5U16?|}r`21a zGG0h~J|>zo5jMmXHc5n7V|}BX1{)E$4R5TYHc(Un$9Smmb}}f=nie?mM-U(^1(!%c zRfm*4E`=mnCQTB$NsxD$IBa^QTHy$tPYy*jxp6(O7SXP&IxIzN&47teB6Osv#dQp% zP8d$ncK5glSreKze}IJR-6<6%7UhSX4O^7OEeGC3#|HZ7ozxq4?g>F^IPr48d*wwM zQeb6J(CeCN=e}z}@tyg$Erp$-WgjGtT0Cj+YRc$bxGM?dY#xseQ^;Q;A1s}XS8qF8 z9>2PrT$2jRjJ?Q z@n{Dfati3UCJCAt=&ekzWTAmY_8NNZ0*-B%7ro@^w*na`C*5}`ou-zF1=AA?ra4U< zY*LYEzV9p$NZ03Xjh*2dg^s5bGK_K|u?f2Y{diQo?rKmRWf6OiLz0iSnqB8E^f}#i z_az?Xv=dj3*(!hGtviqL>*bGdH36|7UyCsbON5v!L=FVQ<(YH!aWg~!v2J_{K_3W% zM^WrRAWmtP+Z>rvZ8y9Se^0cZkAX>-*lgfAUP3&M?2-z)&+6+1e9id|#r)JdtO24H zE=~{}Yl6QBHSOH^Ee!4uI-iU`dIT*~(s6I_TI9s!>9%pwDsEhN66yvd-DbKAb&wEpz z+prC^ZZ0rGIE7m_ICk>#djIHm39Lp^-o%}mdS$QEBM)Urj_4@Iy=k&xuc zOd~Y#v#N;yikyfbD}D7=g1N{k3u9a1V5CoUmp;`v7v~F&%3(K9J(=PMnPBg)g}ukU zmhvD@NTY0RdEW^pt)0_QMno(tqXWw5$)2 zLmpU9+hx1nhn4dG^(}>H!pb|mj6&}F>L1XNyrm5j6TnMmM+3pGSBGG!91m9feX3q8- z7>xvaQL$(uuxu9I+^6IgeKn_OO3;!JDR@abEQjPHwttujrxe}G9TQ$gL{uq$&yvAt z-kqS1%;~{s&KE8)^$dTsNA`%cU^Miv)eA<`%8IAXo%p95DKT1h(zV`TG!n8hy|yPv zah{!XfO86mgjTs5{KHOV4mh#aR^GdAnky&8a2Om>9;b-&($ju2p)Jwd7G=dlZ2}SF z>d--X5poGnDK3|ty1U;?5SU3Z&=3gCHZt|fYnw|Z+NjrGFvWRT-N3>zsxRk%Q@-3e ze_&$ays)$MtpSj=Y&Y+&hjjm@DKr%_7@RoW3eopX(#O4ou^|MI9onSWnJ|6DNfpf( z!8=5ot$pmJ%}h&?x@6=FIwDE>@W65FDvT?nlZb7kFHCQkuXRC5msTVQ&J~}4slPAc zi;kd(_;(1zsY-_L+P_vinG~@q9>;N6N}QaX&gAQpadNH^>(YvyAGX1QU43k@n(b5f zjWeG)jqg+Rryy3JgUK$z_5=)`bwH!vJO zjuNcuIFwiz!$H5%jA1t;)%$kn$jkg6^WA^nCoJF*VF7W`*vkSQKdoGhavrnSTiO~R zk_fB->Fi>w;yX*+ zLpW0jcPMk#rDjlv9;Z*e*8$C^_3+hS_B|4+)?c4^fKD;H-o zM!aigWL=5t7uf41pw9Vn4ZU9?6fPj*p+7OoX&47Wh;S~2r)54}`WeYC6MNQYzNCg# zHcj^){;5!1NGM%_>z{Q^^vimHQ*%VIl%|rp!CZ zl|Mw++RxjIx3Rd&A_U3yzd(@eu=?gA^$o-FtY=5?O&VDi{5%30xh`9GnxzHe&?MU? zbi3lof-2meRWeP-c$4Txqh;k%FxNHdpPzTAwjkU2&K8$JXnfaL@lUe$ya+9|bjAq6 zHnG98dU=vHT$an@&GKH&d?0ycUU8f<1AUbl&1{Y@@UP9db-NRI?tFIH-R5WBF>Y8cW~bc%={K(){l*2lHMt;X^j>G@Q)*f6!0m3_{7f?W|GLSP%CqA7yvN1vUT3|V zq0T3<&VpWHws@WsX|}kV&7mhHqQ?&@mM z{6@rz5f?l`J+c|I!#Tfu2;P$Tx^)lQ{zYNuhrBWXr#ftAIUhNh1E>B|DG}{ptslUxszz3h;AZ^+q21yoQU(p2UEWg8I*j=T*J!)-E-*n3KK=sfeW$qH)dj|U znzJ=@pvJj%i9jHLu11(9!??=+jPuQIxsu2R7@IQm&HA}pPa~u*3!&&~3O~mvaN!_I z78RZIg9L_@Nb=I-+o7h`Ac^Iot{&l*_o<%9S-|z4{)8YbYddKiF8oPz*XjI;x865^ z#oRpYciQK2G-~qRp689hmU;2(WiejCy7N4I?{_x3C9<{tfm*Kqv=S@b62X)buYHj^ zO1FMfw>ggz#@4b6!~9$jj@f0la0o2}}59wkx5x761;FwNsszTdjA<6(OGUvcQxE!=!=#`=28>-NCE0C z^AoK$vY7;R>q?oh^Hnb+7->z*m`(;FNIebScVTC|E-&k##2@M86J~79sKX4#S~1GI z8=g5^=)6CY4*=YI(9?^Il_KhJ%k?uw$5FJmTffax{dJpJqN_Qhnd7rmGl|8)$i}qK z|Ao)_*2AGDnT?bQXgWygl=u00PUDl_ed8zGd&zi-*1ID5EdRwzaMUS(g6fZN3?tv+ zT}cA}$PubUCgOx^l`tV~!9E)41Ais$FUH?%XKMWY86tl3`gy(hs~%JEcYdAolP5r5 zyrTFyfY0Sb4eJ027#yFV-H;B*y+JlSVunpXFeU-RCJ>TLqJ>Q;v`R*q6UK7D(fQ-t z{K;;9t;)XxRD@dHxWEjmC}o;mmxHWbEXC z=w*DS0;6%DU6~{G3wP&wOl-T`Kf3wY;L**olNrWC%_Zi_G1AsrX+u7iHdRmLV^LsC z|9E(O~QRmcE!d+-65Q~2t}r#Adhi-p&YjippXd|S;(~48qD-SkoHItGxVYX7 z-owvyG+b2?{IczrBJWc?pMTP{Qh9JU;9(Jvcitu_?oYGG|MRL~}$ zQQoRv3i(spPJ7QAg$H>QG2rBak%Y_Sh1jCI`11n)gnOP=kgE%k0Hy+6!B^r_TD%yA zaN4yy;PXeRqIpy={_DgGBVX#m+Segp72*SxuL|8yfOReU=fPUV=}#^II6);6pFtP! zGc$wJ14YE6rm=D~lT5y9nvZ6{jjIv@QC(uVE-@Ss&>5*o`M;`V{Izr?ECu-|zDhZ_ z@GIw$uYX+eq&z~X`D&hgCH{J*6^v1S*69Sb&3H-98T>s$8PPABL9Nr_<)Pw3eJ88$08u*c5cvuvyszlt8~l5V#`2{xI#NJKsDH*hL9Q8hC={DV zwO4mi#~t(${GqgQ^UyAPtPvqZz(barx5}29GIleu&~&`{aT# zR0>WrlY*#pKo1LU-yK%Xf%ZEJM#^c?xOy@_ea68$t#KJ1ExT~6eanM01JlduYB_f? zI)3k9OkSNWDz;Y3F`0UqoP4kQ(lz61!s&twwFE(P0gzVSYmku>`;KxlG2Wey^Hjlm zi9-%`g64XNue{12-Pvb&GIW6TXXaA^>ab*(&_Yd&Ie!Sf>de(H{j8JjbqL{v@q}!h zM}ThPUT(Mr&M(7^cH#uhTIipzVqdbMnN|2b%tz#6R~*+RA6F&kXPM=>l#PduvoCUi zBC#^L`H-S!c^)#Tcu0(?e6c1W`~&I+$C_j-7!WOxxKrJ_uFY;;^D#bfQohgkqMS+1 zy6CgIs6VwR0Y0U*g2+xXVM_a9UF$0~cYFBjDmoH(b!Tv zqRJQTVyo{=Y?V2d;rSD&SRKUJ4< zd(}^=7F`NqOON!<#|}sDl6{++*eXzUekOAeO?C{2-+hg;PAY?U&!(1sU^T@pQrdr! ztK1?km)}=ILnxA1m_u8{ph7J&vV`jBlAK_kgcXLrNGdsM{1g$0oQVs>5alL6S5fS8 zqI61pmLU4B{>W-rQj+AXv?J{NgVLEn4wn;iL@eQLaWmY9#^3T_Y|FBUVq2esa_U5X zO=RPZsa0H|swk*7wv}Y){I<0GL6Sca^;g(yf25l{V74Y#Pj;?1+4)l_6)Lc1=p zs;ZhP#2~6b-90kuCfY-|-y+kI*%Ees`rb(qkz_~ikQ_Bj>g*SGzD*97P{y|L8DV2v zMva`YY9ec-m>x5bi%OYLL2TzFuPG@srIHd;YE(Uuy?hXMCZ|+ZnNnR~a%y!~NGWD$ zXNiojlsp;V>F2(ZuqqWWvbQ6@>~;Z*e>-%G zbuDKA_V+hykZkI|m7Q*pw*HGe>J|xVTGQ9`EOU#5`!6z67s0q9vV>B-Lm9wO)WMvX zaruzGJY!oq{-blIf>l{lrpmIJ5(%U&oBbyk*F?XnD=lLy8L^!sS@^21iGJ25VYt(l z^*>RDn$>z$io*GBUv@+eQV{uvs-(cJ1ll40sr_xFA|ck>Cc5VLk9%8s=o znxI4VffqS}>`PoK`Q`M6yL+M|WEYkD&GH-srBG8sen<%=?-a`*q;u~z^q|ZZ9iqjn zy3!$Gv!ct{M2)>RJLa%;aR z^RvT;~Eg`H2R0 zsi;3N&s5{ZV7eervA%8qgq%aOxbx>&+R4pe4yT{Kc^-%zW-FO*!&o)*Z{SA7r)H`OQ2IEnf(0olTEf*Nr_~gBR?}*RoAN%t(D}h5o_wq9tmIp@td8{f zt8o;O_%B`}mW7F=?8{v*p8nL7uD+KKYqCR1Pw>OYd@n*C0{5yspEb6FEp+i zAR1D}gWqJWlt~oVQ~ssD8+{x`?kN9=niu>Zy03oJd#f!Y44$cRQCu$$zs zwZG_u8_&{D09{@FMqS>&^eDw{33~b0c=?}5t&f&sB1tl?YLGulWoxjSbrI;P)tV;R zQ`0Z>f)ABhkd8ZZs7ACRPy=D=f-A>S6YFSYsdSM^RUuPL<-8MAA}+}*QDxj5P9njT zBBhg@?9?1tKT3oqITF&stqn)F3(?^!kZfs2=>XNbE$g0vny0m`+pKl_klMCxv)1i{ zo1@y+ZPvPdP&v|e9&N|Ad7Sw+&6$@i#eReI z=^hCsavn^sP23d}ns4?y1rtvuj@^yOPNkcJNJD}VcCsb?RuMtLmOePZ|b1)D(QAbu5*aLR4`{InoH6qt!*VqTlY!9Cb!@w zDTp0x%JLQbisS*{NUyB+W9sr3#ju}dduDFy zE{t^#s5_UyR1yi|ACThXYx-{BM2dN{-yDSU5mweRhe+Xqz7+@Rrb&$;;psJw>!+mx zx25x?B|>23haoV|sUfPVEVpt|e@a(3Rs2PLHkyrZ*A+>JFjtgAvy~BPmGFPGnB4dv8Lji5 zl+nF%*9h|$>zvywjP_3UPKKN#3ikaRN(3MS}$U zq2E#oZqbo;M?1ONMPo*svD;r0xHu~Z`+Uc!$5Hh-7~xRQm2RZAYUf+JCe%`>=@Y6Z z=ggV}{?0gRLXhD2`NUc&KAzyT=o8{~!m?5~aF>A|wO@3!ICkZ2UhgjTJQ z%!L8x7iC$#qnmk&t0ab@rePOMY29b6%=tL`%@zgdY|-kdBOFrafMXYvp4FRfY^~~C z(cDBGJ|on&nvi%E8=U%2;<*FKQ)q)kG@gSv(0GdID@1!Cpd?rBhnw;#&%-OEH}ki{ z%0%y0v}&SFi6~a+JDralI+ZX(?Zj>lJ1-Ny&LU8$l1w2XFu%5x1_cJ9HnagiOZ(VQ z5C_gwL&xhz-Ipy@3=ULzJ$Y(8mWs+}jN(IQ!-odP=L-uf;d0o{Nf`dMCDfGoYMut0 z!05-N;+jIR$XX?>+E3L=+xrp=@|^Q8=t&&=G6q9}W1$UbDL8lUJ*DoGgRC7w+nx(M z?fl^z7>WRvAC4q44!GK_Yp<5-rzWef_G)&vvHtijzDhd7f1h_Arv{dwU^57vW7N?~E$f^!%7QxWYKE7k7hwW8scnmw2j0Fbeqr&#YQTF26FjwaHKXWpnqMr=q z<|Oam}TMk zN+qWZYmy6y6|qm}6olFfnI!G_ktMV3eKkKW1625JW}BteYePH$r{xUfeKF{;d*A=3R>L6&a<= zdyK1EgvY(l3p0c7$*sFGTd6W*t)RQ5eq$&7%SMcDzHVYRx1zScQCunDXFu$`{<0zm z$1?4*NJD+XEpDz95@(NFZEh2qS(nZ6T|o#(Zb4da>F{IQ?5}Z3@l1g~GD}~<>6cYWRDkFt z%o4<#!~apfCIVQqdRLFuHkk}_t^5+U{Q|pObhB0D@+_qg%$`7LVha!?>)6Gq8upg@ z$o!`Iw4bQYvHP-pb(dP-ls>cTV4g0cCuYK{$m&c*rfvVaV;|EcaHiJb&s0U?Dvz>E z;Jny-1B|s(WodQ0VuN@Q;sFBd;S|7xIST+NjnG4{BtBZ=!4 zecP~G-A?E$q2cF1v3AlBXKPVURQE)++f6xH?34t=4vo#rhBwijjBlUd1XPu6mivzp zfKN$D#=|R1w`+D66MJpVSJ)yrfginq&h|oqk28Fr1MJ=n-#&3toW!@mJGXQMJ}KKD zO|XqGyG)`;0$$FKv`}VVNYx-$<_kmuqBQ<#q6&f;l6`cul$|JYkQG1TQO0NM>(z&G zV5bM41c$(YFhAa9OF0_#jjiJ|?Hl};wZ-1bh`zJ@J;|M8tZ!bu zQV1E`q6(Md9**D;ts4ZT`>^Vm>sQAN7*T7bY}xTa!t2TIm2D}nOJQg3|HbFPTG@1* z^9OTFqcONY2S5+{fVuL@0m^6#8#O(r;eRC(Ye6~*=^jjMm-ty>*$-CnC||I;}r*Xz}t)PNovOL$S)=SZ_t zUVT3y{I@HwDLzp*k)?kD3W*n5HzT<7%gF_=8AyI^4iMthB-CvdT+@iK^G!6v8LeKG z@p3pK0H)D8jhj~TL+)#s_3_!pRTHw+>|Vnwlvv3)?k$i!KY4n-&zDzXs87%_)X%UH zqrV&lxaPAC;(BTT8u?*}lM@}oBvfRdkv@xbISLPaTj`I%v80_Q_wKEuwf|2uE zV+O&~4_g_=m9sjmNd;g;zLjBD9meNM2PYZqVMK%UwKa-0uwI|Z$=$i)9u=$*B#`m3 zy@9oB0LV|8LZXfEqOCrL&H?ZqY`FnTAPz#CX zOJp4*4(#1sK}qB1E6ukX%V6*PFThez;up;sCggY@L}YuY;6KLGT0p zrQd<>p8u&U&q?!8SHoQ z{%q|KkI+wsavN^T%c!o2ISp1@%bS5r`GEvmRYC2ul@gNI+Hy3&9Ty)3jjdhs7f;09 zQY1)@S;0}iRo(&(^?C4B&BoRP#@3fiJOZFdQ`K&)SPo7bPezH#Q_sIy{NtM^t8(p? z4dig<`9mPH%U-2kx_N1NE0Ec3$JBc}FD=IcneFy+_1?;h?hjfZbWru+U~f0=2UM{( z($$d6il7=*J0gi9XnsXbOGi*|0O;r+EZW7Z+73F9R20R%H&p!Fi+1R@2P^Vn+E?su z@=>)(JfOBFUp^xWwT*6GvD*lVTc~__6t7Utk|8PGlG5ZW@%bbsFNv)%c2wB%Mlf@G z%kP7k@3g!g%zQ8Nw*YW?eYQ|rf!C~qM&lJim+HAOY!tF+VF3{e4D>-7%ut@~KaXOz z{{o2+<|le~eo<9-Q3a<$jD_;43yIvW%M+ZFfWQzvYs+7iV-qi-yyd%TCtmxwGutyl!PuQSc;iTM$m;<{Vcv?{fR_5Y+s?_t z=GD&0lz8SjgA`IbEw6#ySiJ@_;hwEy($hY&(DPr`wEw5vu({0Y`vS#7Y zBA@9tE*37IdDvscQwFkKJzG_sa1cXw2?XVEs(|c)7tr-&wy1J;&N-PC*wE&9zDsE-bX=EbK110ltpMTN%okJ}g6b97>Kkd`NPi7z z2nz_R5H0}cwu}&fKAwSni-tL{Rxs~zVcsb)H>-k1V~@J3P*#SZZPc7tdGrFFfo0Ez{?l!6Rv!yA_ z1s69J2T@$etuaF@Ahx&`SRD_w%i47<0-f9|QR%@tAhpQIZ!Jlf($az{_*p>^s&V$bX@n&>zEzp+B= zteXPnl5 zK7Yc)`GT zW6gVNBJyLWGL4vcj~3Wnf?S_V8cb2+p&ZhDQ>)Dk=YnV6rnR4kuXspgA~-|wszjPsB_fK_yuS^dIP+a9G_Z-di~C+NQo{E*3U;_W^0pNW&eZ+WMP2vWBgA~j>A8H69Y`g!g- z=Ho5V}Y|{7$c_K&UUpM-t@84>UHwN7F)s1c8fKb*dk4_{?u1t=jwqBNI%=EK8Rc{?#2XCa=V_` zB6DIl$~1(XDX)tD$T&}AYZ|sK8P1R16bDe!59g}?qJ^UE zsvdhP22mNYqu5H72D^yF9R0l@#BBf-_oOi5;#^u(VC8(rv=M#9(hYkQtBu9UvC$tXZZ$DimuL25G2{zTyTmf_E3#jCuB;p$IgIa`u>)~t1j#q;3r6Hf`7#A%>1?Ce5^&l|Z; zi=3%-!9AxGYIok;?iNZtQ&?52k?{&@=@GSb37F%b-m$IAidgQ=%Vb*|DxuxE=k@QQtkyCVok>~bUz3q9eSM~` z6`hmv>D*0nqdC_sEA&|VJ&P44d)iE{JT!asZrQWM4R{SgX=_=4gAg(@gwkAI<#Kst zC4CQh*H=nmgqy)^7zVQ}2#;&xcQuqR9->19<{$=mzFu#+;*kiKMRLoTnCq86N%mXG zV=DruE9zLw<%&ZX@(e+WuglP4@A;!M0YSPYr18LikVmporYX^G;XE5lU&*&8D9nt#hvtyDX>i-%PhXlsb$6@A((1YU5=oP@!fE$AG4jQk7M^t_eDe2as>v^WzgtmSxa)_y4o5)4}2&IGzkW2j2I|LA_JD| z{PDhNVwT*bS!-17Qt6%qXn=qPrDDeK%Nov1espd-E+SO`Yr z4|tGrm679V1;^1wjvw*FY>4^g34Ru*|er7>86nhR7Tp;a<0-j zm60Q9$rtKmsi`|H<5a8a1qWU_8Ob?Ub@vQ){#@OW%1G|CRM@uYk1Hc1(~|#9k~u#r zQ~Hv$tgm^^DYFyT(&&ulesqxr%^iH(5A;@2B=&QWIAq|5rp%8*S>zGj6dvOr=FTbd zEU#EzIbS&htAc(ZCuC=iJmV}f?0kyj9C#)E`J!1(OF$*W5~7gRbo_HXqxS*BrMv-f zmWhn})5a8>+#Qz*=G4~Xto^8{R33L$s=uAiGXClqKil)sgUpsi0k80(>)>9h`?Kqy zO0{_w>tLkRcIG-b-%Czk2d8#vP^Yg03E!>iNM8ppxP{Z#!81Db%ysauWXL-3P@y#q z6;`O+VC?52_~FjtVd#!(vpcQWEUBFuB7rJUFV(7OqHb3$I&TGrolmN2^N-#j)tw#u z--B)Zv+)0w;w{et{=%>J0sn`*&F9sX0?!s+lY)~RR0|57qi;h!%M zOcGYV%I$@}9I;iu!)e7{-s!@BF3CslgNaUoDsm?Xd^j9ga{A=_kk4S2j&2ufojwii zd==R&A8^N=+zg`9j-c(~wB~24=7R)SXjn3=LC^of3ECbkr&^3=#_10uV|eQw-4$MS zwQ0!)$%K43mQ$&#SfQ#oskpdo)%>$*<^MzH^iOH7`csn9bUPWp>ZLS)I;bd(6L$7= z{PmP(j%puD)9DmkpeaqB`rG5=@VA%J;D2gjVL0)W%p$rZ)z0O#&*d^ZF$(HJejtIl zj4;xbHo#Nxrlbmu^Ieh(z~3pRH4ix;q%{n~Hh*9wTaE`RG>3eV&m*+9XA5rPs5fuA zG8^q{t2>mN($$vh7Wv-cUsdrU-@(y~e8)b$$oG}8i&En~$YnGB46K;Ql93QE4#8&} zgwJ?dn5AQ%eVSvZ@7U<4g;O~;QYkG5l=mpnTHXLDM{5~dTBWs2$gJ{$IZAsDwOip~ z@#u$oGj_Ux$QoT%*#m3)UP|Z1o{@GlqnD~ey5h+CWVN0tFGcg2069|KNZ%&%Zwmj$ zxzF*kC0AFgC1Q_N+KSB;(tH@>AfD^O&hl$}5>L|= z-!UT|Qfh&SWYwsxv2l_CPHW=bmH~Amt!Pi|)ep>yZf+bdMmjY}*s1f-L0nsm-zw+J z{{T~8L6{Q1`XB>^i0E;Oe#9$^*G%V2s^~b1sxxDkH8Dr^jj}NLMrlPCmoe4_Lt2O2 zB)*{%Q}Z!?)hOmqgvW9Y7>e^7m9RKla84=x4N-*@%yO(D3=Q{E>aCOy^5_m-$dcZo z8Siv_me^#@(-GALeRq>;I-w4%>U@X<4Fqw4BC=n+d|6L*0}*SLD7uMo7QfIAV-);V ztS=2=-Pg$xM)XnpiG{REjul)*x@RQ3401@q8#IR`RJypje7C%yp>8OBExlJOMV1$k zWY`r)ILS8gG4t4M)*o^FkV=|A&n^>jp*rGZDd2?VfP-+z9hnT|!SXzNao)HAb%nS& zyXeOmUB;$iJmu677lBDeJ#^3js~o4mJ8ob1;Gl5>qVMT90f@16xk;0{c{GvTF|W!{w89(zBy=mOjS9m@FTXNH|woAsvQ-bghx zzQlN3J?`h0BFWJaa8)&OW=(9BQ)rDd@NrN~rNUL&Ijf}p5ej*WTTm6lX|2C?yg2}E zz2dd%9NLLruDMTV<9g57TAxi$Yr?$O&yAZT$y_xy-#^f~=#8Glqj%t1XjkZc&g$*! zM&84zFPc9;=*+p@lQ#{SpO59q#7}Aw()XpfovlWMB4#BLDAjM==eIf+5u-zdhrec7 zjSXcRjZ%!;Uwc8G0JiSqfPF-A0?tEF?Yu8UNKL`9!RYsC_#1@-*Fg>ObBwgx+Jhfa zAx5BKv-9ug;rXS1*Tpnu?Gd7ainlW-2j5V8L_x|LD&0;*59{7KKfvwXQStNPk`0aI z9VpouEB=M1c&Mw1tUyC9f`d_CWP?1-!?Do(lmzE%!?la13x5Kcujmj*#E5kd^F1f; z!2cBwWJv(#Q-|)~=TBU{P1gsX+1D%RX)0 zlxr=Qs_dL5sh1kZ&t(&oO08W*EhXW^wP?&G?(VVutKpAy-PXk1a;#V?0>w?zE3k0s z4+wwI-(+ey2vO-*qp+j|HvrdDgf#D=rh--I53tpEB0|Cpm7ntVV&G^^jbKSPin18NoY(UB;Dnb{N5e zpru->yG0xt75>WD^)f1uzc6b zZlzJ!D8Pw;5~pP=jR)COJ1N zVk$Sv#AmZZO=y!pgr;CKM$N%^NC+9EVY8RLEq7+)tpOXO#%t2l7qP_?5f{lWFkJ4WyJp1jKYU9Yju2#m(lvh?xx zRdLv5ozm^H%=&{cdTXy>USo-X@xTa~;2#UAvGy;2m3!ERdj{SR+uc1L?btB-uGVjg z(4K$kX+d(FR597;;CC2>?-McJD0~ZKYEf!0WNeZb{%%-j1hZEv-Pr?@_!3&Or*IdA zK=wdrgZti%uPUuXdx{!^lUD{2#pv2qIq$nJ_1#No<(_&q^?Rpy`_hL=yp5a0Q*WUn z%%4BrZY*p^@%9w`<9%VfUqAoCOLtJvz3n*b$;)(b{pDqLk$ETGQVH^rd+vW`T4IXKMM;O@_^!9B3wUUe$rzlh@ZK}`_(uFtK{{pt@nJp(yaM_4n z70O-9_X!m~aiZl7yf_RYP1L{M2%I=EhnI-~a}=)Q;Ab_)%YNDLw3tV-#{}vwu_gs# zuLkPQZ&;F*h#Hvt2guolA4}nX8!_j2m!!HpvVGADNY7CB8?Ze{>M1Fuc;qShQ3|fh zBkfI*!(v513#W^h%jvCd@U_izG?QH|^jBOhu3AEdan*A9Blq2gB@_%#8g4<6mXEQP zE9Kd*$uHliO9QmyQ{8T(Zx9?PJ{&Phxw~04EP}}5Fa< zM0yMsKP7E0eT+#=Y!a!0mMu8nxmVoT2WGo4Q}E|ht&D3#7O7b9?E-WSu=Daw1L3oA7$l;cuwcu3hq-1ku{)3q_*lUOW9 z{S*uFGrSz*Dd`P&dc&YYaHomIh0ZT7&GNa`-@eXZjPmaR{vE$bKg+v|pIn{24cA&@ zZ<9W9?j3IJ;Dm!I$NhLBa6Wqo?okb!Ch)bKechyBH1J?WaO|XKnGbaTp68DLc|LRFO=7QW^C3)UjiEBr(N(V;StC+g}zF1!Cn}SiWIcZ^BIP{wr z&{gyWfBT9|xl+AC+L4`<)aZrC`coz|m{$!dj@Q-di~B`>=Z`;7oHjejvXNF?iEd6D zt+d)*1;}YX#7Tj36~EMNijlqoCqyB!Y?zI)%jf2h#*9M%%0%wtBSpRHcD>(z+h3U8 zzR-}=_79R>={%te{Vm%6<6~*#mrXLY{b{QGtNsS<7os=;{1W$YL@5TyqCqPHd4ODKpJQ0r55yF0|C3=FDaZ zpBL*c6rB_)tihfF;g`{ZZhUE3nPp3bv6cWFi#?ggBzzS_Gk1lpEPkA! z)ts7Df!MB~Xchg3rJA%RD>(ls_ocJNv#Qda$g(miw@#s1vW%Nqn&p>V|GEi( z4$rjbnyi3_!o#O!Wn+U((9|_@7PZundNB(no>aV=c{*aP-;jb>=T|2Y3wpS`Qv{K{ z@M90xcp>;CPEkNFK_hE6_$0W{Hz1V+E$sXY!EL~x$mreHi^#tair*kkkS1sJC^fPf zr5RnxA;~k&V1uO@$GtQ?Y~FQx_i5?L_u*6+dov^YJvN<@v{z`CgR9p2R=fVf+5>uq zojWVpjKEBcO@D8x&Re#OMFXx9InalLZPxcv!1l_tB-p&|MEFVJTx3s6Y?bp;BpcCx zrQ=U@6L|rq!ZifH-nh7dTzDHte)r4|B*rum$zW*)qBbQ6omAXiKgV#fBFpwklUCZ+u6A9V>((mCkkF zRWHJwm@6gQRE2SuZLO78jL~t5li6}C+b%KXoT2+V^w&h*NsG0eJcnrs;YYF;?zktdNVAk{?85XMk>0nqYD4O?`k za>Qj8Zg@m{iYKq(bM2M2G6nll=eiJ~$e3e;TpfDVy0JnctA?E~(*r9@S zVp3Hb8VOwR9tPr4jA4&Xa>=~+yf_-wc* z?@Ww1Hwkrj`j2IDxI59p=t}A?J$)kO`}DbTC-#i=BLoFuH(jGq97h>uAj&LuY$szkCjKSM)OZ^(WJ5xkNvJ%C5kkM@d&un z3@Fo)FEI|T{7*9zIS8oxHWT@?p}|VrCeIw7_^Yak4rO1{*PxsWcFbSuR7|Fia?8mU zGEPRlUtQipDb#9nTK00#3I*d?n?%;Tc$zF~Ol5|bPghU5X896cA|No1AOak<%+K|; zEg4{hhx8id1BNP5R? zoDdKY38h%;Acu532ys9y^D6-;G!mTaG_NH((qt~gK|2+8Ofj2-D-@>UMUAeha1lsv zBo5T^m-&BQf%DrhNF1o+67cP~7X(U*c2JJpB(><1{S-Z-ingT|oj3Q4TDzoHV(z51 zJ}#vk8%t62AfuOV%pYJ%9Ltf-MIkOKxUbtGA2~uok zqY#Jz_L`wO;%03IuApAv->aloIL1sI{|}c6Y7e?GJjpvo+HHq<*n?{yp6~1s)NzzS z$wg8hGL+h1@=ruh%E8aQIIiAFY?DF!vC5WkW>LL-9Ut+4g3#9VnF}_dF0xEm5>9!I zkbPur2W!M2wGEAWVBs|H9pH1n{(;2X5b*S~k0v8|ym_MsFilrjzwY{s9DyvFm52G{$kdEd;z<~6XRMntCYdsb6!)WZ)kj+dTXiitDq*K2gn}Cf)QJa`vclx2 zFUhB&;Ll}!ZS>a_Sk*)m*oh`IBDW#9PO;*UvkYq|kyV4vU6<)v0#Yu!|8nmNXlN}c z2B9>bG7wHjw?&93^`&if#K%&Wlqg$L{ROz(~IQ>R7YT8Wy{!)EE6q?4C&jqPKyN<0p%wE|&m{Z_)8#@2w0H@JUia>{r9H zP(ZWBPsUA^H9lU3dYwtw?$A-%*=37Ci!pIC@g zBv+h}2?bLp1mCg>5i6ll17{^FkBdu_Pm|;c=W3Jj&X<@v&cZeUU9M@Il(Hom1Ry!W z1Y4gkfp8U1%wGCaSpmK0-=EI58pGTJe-EE9X?0TZ9(JB`SHnB+u zP`fD&v;4x9&Q1uEP`mxkIn8{7X7m1rCDVL$bC`*e$;^a=OAnTW<*Cj2;jJhNNuaEQ zV&8%_H(6NzNdVbp%DrC*)`7t5lrGhd&G}kLS^e#(jfM`&+3Ab4b8LjFR2i?kB~@dT z{G&_<-B7U}Eg$D@?)7FmKbz?FJ-J^J-(2|PLpA2C9_Awwo*|BgUx&hTG?Ovihm-j0 zre_;#MLbX$xkKgeko@ve@=@SAFVb+$BO>?M=REU=?!?jG3SL9Z&y6%tm|1ZiljI#F z+o2)5LPLDv2g^$fG9qipmivF=Z+?I)$Oa+{L5q0|otlGU8d`b28hAhPx*vkX<|C@(7IK4+f-!XyMQg$Q0E z?Ubx`ex&w94r!4iyd#a-NGay2e6o8ZwU0D^7b2X4|D>Y4>~mJSCBi8sUVDoYZv4xA z&OAy)x>S8YvzoVt`={Zovo0&*yA?I9fsp`zsJNJ{YT5oDPiOBuc*=Mi$7OH` z&KOXMizL~FA?p~f2~{5?9q&JOri@zAA9Z@xTb9)|Ki`CR>A2pzlrvB_p2RR;E63$q zJDbl-nBIPpy;a7mV#sDO+JbjEe_d$puNMFM>^&vw&^Ib}XCNc`BIAamQUh1;O|gGe zW_050n=_vHD5=Y^0|CD9bA$)!l#j=L189TYArO;RLrMJg0Y;y>G=4NxTXdBV=&e7aUa z$ny?~;vSxY2#wr$sDqB854kDqyjLa?o;=*{-hiVDLXzW87ca+&=n=<2OI=2Bf>Fq* z-co;8JD-uMknt+>X&os+9S%DMEihG=kG8uX{fxhA^U~K5yWJu#%Deau!4oZmee59R zM7z#SOwDD(Sqw!!?(7a}#BV91)oymvOJtv^k&T5thKZJ~M+$Cm3q=1zA-dXRn&w7M z-(Qw@ilu1p76X4~y&&Re^jgavLsoyMvNA54^=uVT(rlF56H94` zi9&C{*)|bWP$it7mTDZVn@i`UCw9dn^zaehM4<6FJ&}O(zYaay_d59ofrqvHYCh5~ z7p}v;0HW*qE8Y5|8(e@L$YSIl3U6Rd%*WBcob4Pb_Tc?!=eM2^@9!HkqSdk1jHma0 z;|bsQC9O&D;xCD3eCh8_$U1fYtx@8^I#gjUD?w-dQT6D>gMIXPAMHunU)@8ZBIRV?Xi9_J%);6!kTL#mz|PdJUvh!vZnjl=IXCU-Qc>$1Is=Y8|zy-s_~^I zBa4>=mVUfAoW1l?<^}H%dWR(p!4$b#g7QB&Otz3*Oh1Ur*k=i0dEFASe=P58RV$8O zNT~Rr6~qZDj^?Z|zZWIl7UQ(I zn--sUTa+)yd!J6u$YgKa4actnJ_bjuyIquZ*Rekl^oPx2SxJsnl7|j1M~$M8lZp1; zuS1U)i3%FavV)_CN-YxoGtLjjOj*L>&m1RMX6P|4WMAjs9;4=Ry`E>>hSwQalr;m_ zk)jz(O}}Od7Ve}Z9$CasusAyp%IDLShYa~E%3UNP`U+NT_@gluY3PjYMj_EMXCUbs z9zrYXF*CH6p`Z{%;`3oM)MSSqXGf!rLtz@3wG)3ocn)S-t2W+fRy}NHAQS~yC1yn@ zy27?CgmY4c3xJ|F)B??_=G)id<4kn=LTz%?f^k=NEZijla}O1mY9{s~CibIePArOn zsdLLWmxBqHSa|r~z2u`z%>~}1cJw(j_}u7YHrkT2aZt?$qUPjmAg@#tk_la#`I5{D zAQ`cS*=1ssNcpj(xNwFFOhY~)<$akTJJ2bd86+ zNbePTD>U7mGJ3&zGXMKWe>r}}Kt>k}2^;|c*5808Fy1-rd8o_T;f%Q2&SX8tLk((K zR<(nVJs{hatnJI~8&82l7Zq1@)qli8qEyOoCRteWNxr*Me|M>TC*;e*x$Bc@qyZuZ z1xu2zlqNOWepr(o@>xeOCDKjm@BUnqsU#445SL~ifPz(Zx$9)Rw@6eUo29X4)mTN3 zP}zLeR$k+QCAsp&c?u}WFP18T=i(Je1u~#veL7BcBv%#-syQ=`N-h`#wc{S3JCh$L zGwzZ)5a)97*kGx7@>Z5d?S{&VqsZTu>S_B6Z+$h^!vDBS>^t)8JeQe@XPVlD9yaV# zkUJ*cUV@nIVKdrxB?JyFu^Ufm!wtbU_q-@%Zv_q>O%=KuIGCZ05Jiwn(Lx||klU@s z#FB#I`e)q@2h4KGnw{O`?Te`>Me#x@ei=ThmROa{DJEiu=`3 zqf_aqs-&N7&X!|>x6@IxP*YXjav5F4^d_fWw6DBrmuF`eZdf2M`))i3JOBFeO-em*M zB&jJ}n%KK7xdLi+spcNeiY-(mPBD`Dqg+@HY&p{y(9@TJw{=u>q)u{+aBUt#cO)~U zwoKM@QRs-!I9NQjRVKLy*(a?~gQ9VJQ|9>3?4N(TIsP5KB-I?B!N{2&BiA5AOc=R? zuzSqDV&j-_43QyVP_-jM)k4Ra2*uG`A;EwYHm)sYui>gQbvyMor?a02_?puuU}JIu z)}J{6MWOXB6PHSbG!u8`H0Urv{jxECyJ?vHfovo2E(bZT98~tiu{$5e({!iNXr?f6 z9g2xlGjbXfj^p)QQ0_?PZlF+9aRkrK>Y#BtmHDfgxWC=#=k_QhoHLs+YzVQGgi4(+ zg(cyX%N36tF>9ZRaRQ!BS*$Fw?B)k-u3IQ>EgdHGy**Czh_F zIN+X;qcN?uNF139Tp?RU{||fb16bu*-u)*ez_E=zCz{si;=~O#8diCQzQs}ZCcp{w z&w)^ygtP?epVkc9T3gaq+b}dlIej>_+o3(VA}bU7$3fEkaaQ>7<$| z>QfsvTGpmD_WVBI>wcbdo|8X7TXa7sT5_I$_x;?@eP92t>%Oi&&H4~5&Mx7p2t?%M zHo{HPC{8&_er^QItqcRtHln|wBd{+FgNdW$(i70kmeW-t*~7uP+IOknK!1A_BCb_@ zf`0_^wxm$b&@;JTMptwrcKxBa$;D}N#&EW=Ww^T z24K>R&(n<8^a;`SOI~HGV-$hG|Gbj#v=MFR7z1;GHZqYk_R1$*z~;=}LSn$qY5Mod zM&1CzWK30Q@N1qk_zUKLC({pZ&PCYHY!VV%B)sN5jOR{{Xqr1PxS;zEdF?waux_)V zHCl)eI^D4mTo+D**%q%POolKn=(dFrrg!Jgkp)-)?t6zo^bM>>8QVqkYzc7RT*J;% z%{L_S?waJrlD(06C$~M9HyXZUPx)2}M9|q-oRXmMcT*B>(?O1kzWO9e!i{>mdbF{n zOPx%B`iUdn`;1EmLOSH@@!4}NKHEynN0=L<(CX;Hrj_YF~B=?fXQQ4zRmRT@^F3( zJd+y?HjhPS<|MFrbnLXq(LO#s92iXxk@AjVj^xudMF8fOkQQ$7Ka0H;oc9_J*Qck> z!-Lk@S1N*##^}~~cSy0FWFB%oJFU&KNzJORb8W0l=5K|eZOZpp$ zf4SeWlM)1@`|mi5`GnNpyq8P6awKSBf2nw5I%PLBJ4S8UJXrnr)T;K z*hypxS3HvkA7;)=?lfFpYz)~5D7$G5e1^Rav@h@#tQ{2Aw%_fw@9OM*QRtgv$?)Hu zz?WgGgdUqh&0lW`740tjgrRGy0A2Tl)R9TMJDkPjU@(o~?=WVZD4BG8dF(`&O_Ko;psnf%*GSv%l!k z*W|oGl2pg>D8&#S3;adLoIGFXFCrUB)L-P|wn;axH-8b1qrhLZIn*vuEhGM-sF_yn zgb*XLDwq=$OD4{r@mxmHc2TzijvZ7{bg&~688MC)D6??Wh%rLdfp7ag3>d%5XbXH2 z6jyS7t-M(QP{Mw4RZm}Xlh`zN6K1ikf2K}JXV6NpI z+}kJH1}`aZ?1ug5!ClZFZkP*zhxfyPyyPaBLWBneMD*KvH^{*}^lur%fyQG#8r-99 zOpW-jT9RA&!>+~h#%(yL;uZUyj|$8}<4MKvRiW$b$Ru~dl=e0Fuc5>UDS+}W0U&Do z#rT}ksSWZ9#EGtyhsrp)oB9Fyr|@W@-t0D$hUVIUshG;BnnXhQ!K`#}m} zVYGir%Xb)klkQnW2M6yH9IO@`u)?f9&$t9Oi7NpI2OL^*;DEVd)ms#beyS@UOzt;m zhNZB)ag*^C7P8wwY_~1{!!q0NVYW5TJEO2sliV%Pu-kc=*_eUNsmUc#md2WW8s|5ey|KJRlzb4sUIu?TI%UvgS{aJvIGb(0fDG_ln<3>ZqPh) z!J0@gG!$fLInKla{K_zLoY{AXICcpd{7?NTii%hqScvs_=X!*Pho^vtw}FQjAwLTb zLlbMqVeQAI)Mevl@a^pwXWx=pGS)?xqr}iuHrt5m2cCP8;R&1NNU?do26N29nINqh zIz32R=$$KkTfdt1n{mX5{)Ej6-v%9f~mtLL4xi z3S(lQ-RU8U_snGe#G9=0Nx+`WaTju^?KRFBX-1<0R^`A<;(hLk?GQ_W6%hMIXJXL$ zh+DZR!!ag?aUsmiFE3S&G1n#Uy~p_@TOM=l3g&B9JR3l0TR@I6+XD1nAvZ28?xOD- zz~PBJ97s01al`pQRseV#|B^^Z?**-wEdOFJ!g6$ms<%C!a9HJwP^$Avnuhqgh+;`kTa7(6eo^KnpRR@)i_{H$(H^2$RUg zr4;g$D0>h;2^^t4yffkm?I~a>5k_e&CGdl)O~enHYZK)vFb23vz@|Ai&H`O<&^7^c zp@J!}WxNHMkriK|=bhm6(%6a>8=F{jL2SYoD|xoNMh+U*bf3d`xMAp&!RLo3BjS1u zoigBh=#zPzKG1b?ewhHMB7T|iT{13jh`cfeRVjdp9k7qLZlu4|fpH<~+W#2MMvR9{ z4OJ9jj#E(%!y-&U0l4s7;dzC7U?zfNL=+T3Tg3CaJF@cTg2)4mNgsq#60vdOm1nW! z^Bv0tu0)D3_2l}9dUCm>3cmUVa`K4_fK|dQNee5eG>%g0ViTQuhYA{1Oj)waB^hYF zpk3vS>r62L^SfoK!O_c&0R@(zDph=sxxFT@n6UONdk~BgCG}1*F=8YKQe^Ez2hx*y zLh@Bxb~DwCr6q}z2UbMw$Kl#rki}SPvidtlO`<+u%vz415L>j9 zfogJnxCEDn^qkiO3m~*Rz4MP(*$k@02eJT)6HE~unqCdi_K&&}ps4cISEx@83 z*jUN5helPiA8`Mxc_rmZTgzY7+~WyFH_VaopFL?vSKw}T@yti__Nit(&A6N8Y(6%w zv)NBK?ksRNJDHnr?`7soa7^7@;B>~}>~-{K7UFOn9MA2H4vHH^ZY`Vu%xmJ0ah3A( zUac{9+Jvc}#LNlI38}?HD&;?K0usV8t1rt01gy&(6qtapLtyU_qB^oEdI)naZ;as1 zw;3esRf7F$hbR<|3y{_MaExE$U)oIv1_b%F4;i({D|aKl*^@BpMs=3#)+jL1z%GxH zNkJChbaE?ZA8tMdlRk`3!Wj5r|7;dB^mgOw&eRv9LSY8lLay(0YO^%ZJ?1FWJ`;Tb z`(&AWuLHWuK~LxsJLYu^F#A-Q$l2DD{qZk1qPxhFen&SeHjwTZaz^#WegFW`OUw{G zmxfo%me8g}R5#0osC%gxZi{95*Xgq%?C_Gz`T?)6Mi!xmMG%kWOgQo*AAxHaEAAz1 z!S3ZHVv$J}E{~HTbsQxHyG;PZ1o(rhf}{Qq>;iWtpbmn z7D2ahhp{P}dV~P<@uZ+}Ul`>nF1WYkN=BzyFaJ z)Au>QYXSP;n)2nBS~C-0KAvb&|1Ow`i)uijB#k{p?v#8jcYoOK-!XG4`1LOSEO=Lm zhr_E8832@AS);e@L9yw7N4~<14Evce!B!}6r&Mq4Pb~SjS3mWDS&b zun$2fpEEUl2jpbkv_zq)LBzPg)UY1uf(K4)YB>B-B^a4wS{l`{QQxB&2?7F)^J1$Z zK2EHC5a4YMe(D=G^UztW4dM0{qV$e0f~(=m=$Shl-?&+^*RVfA@!EGX)gP`P3V`1a zRtDizikz|~;Lob6zNFDFh1_5INf& z@$5H&Q^1-NIH8}Ijvc}DEt+E^i|N)8nbXB$!53kgTOg)JH5Jcc%Z47|J$!07)2Z!bj)xxHtI>1FHb8^p9q9i0<1ZJnogvw6FoPYmTuCxlRdSb0c(VQjwqOf zXKhDae)+!5Aafj1Gi8Xu`Wi-pM163vF!OW^s)n>ARfFORLgT zRC^(kGUN2`cm6+Bx#$$u?qu;R6V(e+ngMTqm3OJ)(-Yq9ZV&VU5#U>=r5o?Yf}rGK zseZD!r5pEo%~gaEr5m@U+Ye)cdpovWw*|VFJ%kIj1H~-73uDMYvI`%OSnM{+49E>= zAuam@$Dypez3fRI(++}?cZX6`BY6Opu>(6_HO^GG3;H0tpw*5IDhFgG%)JpcCT}Gq zQy;B!&(R-uLXW(niidE`tq-rLh>Vx~wP=*}G9QXz~_+)xQyk;bOz z!^ASFYPK~uac!0O4cFeIoz8k-fO|*?9Ey4FH3cc#Zj7|9xuE4dhS;!-4 z0(TIGvM=8J9d2TkE3h-tpK~s1lNZ*-!0s5b4nN+ky;wv1d(;u0fjs;ZEfcX^l(#e9 z^6Swv^n&thXp>NX&_$Uh7T1bFb$iKfWJ%j^=;}f7gv8ieF0w&b z(h;+s9<&c_J`{iF;+eEeb>B3XI%?0vuhi@=o)N$D5x=$M+#*g=-8B7q{K|fg>t|Eg zWAz8r{snjE_XN&rC6#?660Z!6|^LcX@nb*k3J75G$n z9q<9SZG_+?t_^tnF(89D5w6@`DRRca4G}h9Xj_m>bU?JN07i0A6k}loqGB-e#X=ZC zf^QF4@b$|K5SwD5FB%} zHcvfy76DCl1T?9{o46jF9_|W(gBHzzmQ`mKDU9jOB1_|PUlZ$XS8NdTv!BPSX*s>K z2S0!JZB-(J0mJVO>6t|e9Tmfu|Dp(P55Wu~l0*gxWIBuoc{H~l6E-DQ|5jN2xYRSp z?ys=z|Hz(*Gm4UZ$K2$$j<>k*qzT?+1B@m#(3{?-cDzbqO@)Ly_o`5`u#|z<%C5T- zTm#_%=N^oOa)n@RO{XA`RqvW95uBvml zCrEwqwz-YK=P2~al-+HTGLT8Pq#4O!9WAQW;`hl>rc4YwBCT8E}#ivR-z%7`jE`1+MjRN2nqwPHNtKsSe?3X)SzatlI25N`xJ@Cd+a z(l)WApo2sQ#q&8Ko2iu4BIbm9UIGFCBt^>|$iJxA{1n*mV;B7QP$3$Wn>kU&&+3OI zyoBLSKhhh82mSQsOrlD`PF#k`C+7xRxiHmyll3&w;c+pZw|_C=!1f_4StD814J7JM zvT%z;uz9OxF;IIsx&pO1yQUdn!IG6Z$)uVVW$A1AIWPIV*4%Yh-cCIF!&G|Ymbi~# zJSS5R-Lz!1O#P~12j4h4zZI_zhL{LCOtf!7&em#-lCu^4AURucA)l8mmJcNRtfeY# z!RBTm5?|DiHH;X;5S>{mAYWX@+4tkkKjwJaGx659xX)kp{dl!ZSS;8+e)vXh172=9 zRQSTiyET_X@hkU{$K9;HPrAS4h`%4T;K_S$jNZTBHGSTiF4^xT`zhSc(D(dD?CgX3bBLtrjoqC+rQXeD^DKT+@>{nP z-jL!zQLsL~v2+A9Z_FW(6WfG6i4W;dljJsW6OJ!%d#nwuLM_xq-dos`5J>xlh?5(@ z0sDnRsiPA1+0B-RXrl4K z&hpkRj8`FZA!2F4RP;$mRURV5xdCG#xaFHjbVgoz35Bld=1)7ToG`R^2$b5w6ZIgW35X`l86N6F0a{%=8m<2C@jP15=QZ7V+-kqO z0H@A@N}28|Tv|DYKOsVaP2dz4+BJ;P*pv_=C7Og%VB_-d^ZSi)vFa#yjySCPE{9R9 zYSl-FSe4xHB>#Z~*P^vN*}6eUu;FE6(wnW5@i2*Zo+>6C%~s^m(J%?+W@2O-jY*&i zNK^~!OP@s*4ER@_G$F~hsNETw@9i_3lprq|6V9rwr98B(5;z>z4)X(r zzx+P=HG%2RUu3^R+ww2g+HpdCk0)RztfU3+6%!xVhz0#xCnMG(4biku=BeHpuuQv? zJjtt^x(DSPMIFW%vNjFnsKdz&S?U!PPhw@xE?~lQ1E2O1rOK~<#iYuJJu5H?WbQ1n z?PKW_{A9!sVV@^w5SlH!D}m!Utvnl zfZ8O;1ONhw(1qTzWgiIK=V14SDxT=)iIBO;9qV|34FS`IvH1@UfuBjnt5ont1cEn--4dP3Qe22YturSp6i_ zPvUxUCe5^y_Hvx*KX~J{bNJJUY^m(HjxF6AIN<}%lvoU}TCV+frrwA!T$|v^zd5eN zVQY}|W!1lNPrOL7cp%|vl^iS5;3efHcRtB~@T13{7Z=zmezfyt^P@ktPR8R$f{C1X zcw))!vS=rdI9?PAiQ@=&qxq3>Avh2Y2(Y9U-c%>vl*F=}GtS+CSjP%9;e7+J61Pxao+$aFx< zA_m?>NQ@<+{725KiDHt=-a5n`!K=?dQTZPlSwSO_v9`~&C40{Hxv zyqGA#Qj%E9!FcntbkWMPnb0-{`U~u9Lu0}Jbx-HOpNFaZ2L61>Xz<5i(sIij z{usdL!2cS3TnPKp-BaB}~eodn}iv3)m=N5vQH!cbcaF7%R=k}w0% zM^9bGQ*007cPc1JRt_WhZfn>rGSKCHdjgYdt7vD^Pk>1hjBJ}T%+i|HD1KBZZO)N7hnPKXjmnllyl4Bk`oKU#+={q4aPAJ=K;K0f{KOa80tnm zB`#JZu!;mylVOma9#=Y2C9+YX5gr#Mk}-`+-&d~22tT$tYq8(f-q4Wx__m{TvgQKz7$RsvIu|Jau#0c}rD zy_oP&GHH;|24^%u9>>xq1XApPu;c}-#v!GOcwd;$Q;9toiY-0}f{ zO1#$C!$p%qB7xM$(jB{iF0zv}cC$o1-uyBk$idf*f-eiC7U8+tly;T|PM%NbO60LM`kC0}4EH!}(b1Bizedd~>nXBJiWVa3GG8 z%jHut5m^qGtxh_>;L1P}$%H?<6?%;2%NA3;Z|Fyu``-zbD0IjLO7+RH#DI@@BnQmBkMQ%!*`=AZ&rI!5<$P;mkQS1cM>EB|64RN#d}spH-Nq|Ll= zx^H@7-V28`F$@G-kaqx2B7UMHrsi3w{dctTdP^uajO(d=StKaG=$0rvpe>LeqdcKX z=IGJ^2Lg=agxc9SwCLII{#szFO-*KOf-N_J*E&u(?oBDe)-98lmLRyDI4 ziZ9-Aw^C8vJyi^h%an9f(v%)C$h~YJlKo&y4cgH#4?rrymU80CJ}hCA-f?`@2k#LJ6GZk>zEQKn)~+Vc=ZUU^ANgbMH zW!5r*eW5ydK|-w)9q8=lDw>xI$x=@u0WFuzajv54Ve!vmJaB%Z4#W>>K%du)IGQmp z#(;jxwJQ^9#u6_dM!7KE)Y+k&vfIvG!U;+>~zK{zYg$w{=Q(dGluvbf8t5Q?r*Ox(Cu9-*6s z7AvtHILU$&=ST%33>%#Hlo98QW$t>!6VxqF&@s!HAo!IDjo(vur8?c`M>LaT=Zn=s z_b&alES+2A2||zvOvnmVYf+;3aeO~o%FwH7(r1OZK;T$S0dy_Ii9c@pPxLa-1lNv$ ziL(G(ayXKgjU5qI^U$>_Jc(Bi(dv85i$zSEOGvQPzMadm^_oeW+eWL6aG%%%wDaE` zoemtUZdi$HH1qA-PvQZ(Mxn_$Lqog1G;|(^&Qxp+W(XPO0piJN5vS@8;?+mF1fuQZ z=ezu421AoudF$o?STqiTzCF!^XaplVbhu8+28lbGt#xFh#WX?}`9qTM}ClPUoR?65*oHM&j0)fhW zs%BTXp{fKW%pp#nLA2!KK+YoCA{3@zeCrk|3i%M*smLNLF^W{Oed$J`DcA>*UMdK&DMiCApoRDNf&z@Fqi$EV(2nFyhLf~gMVEhEroK@|3Xe8+o^|G)PZp1j0q+d zX}jopW(#9NZf8t#vk5>lS_ROgoW#__wVcEz+<2Fo8KH52rY%wiY*W1nJD$MwBULr> zgGk_EtJtt03UHF7f^S4C#Y0Be;pAF#{>e8Yavx|+qYVnsF7u7Fvj4?|9uaZ?sr;HP zyaN#BtybZNT`=lgdq#QE=g@74x$4L9X6R9QyQopXvRhCO2RZ$bV;jmHv5A_Z|s&0XUm;*RP;_tk8CbyAtF3EdG zE;cD=_%KoqQ`>xu?ou#?gnCM-r$oDC9L;x~$vEdQr|PE#>8s_vbNJKB1Rl;2?&~#} z`vS^em*DjneG?a#adl~oKg_~%?Z;z8SfUH8!@8__7-Jni615J8^35)Ef>$ixeAqe} zk7V=xr%JNl5$)t8B%5f<(IQTo#FwSE)p30-cDc}Cvadk0(E6uL`{sEf=_b z8;LhcuZcH*FW&qNPkonvKM%Z;cxX7|pHWS7b4Usq4gF8?;if^F@FJ(e_g#|~Y-vs~ zQD99V0+mbFP>0Ac@n%ZxeJc!e9J*;tyvn4n=SU@jPAH}jv?Ay|skD-VcoS8w*8-VC zQw*j>WfiXR(JhC0#{6*{vq0sIo1-8fN-29#MqaU$a))&? z9>{MF2O+oKiJgKMMmu>qAfI=Loc{e_XX;-@gAu&s$eH?=B$pXm|8mk_$QU{3ovDAh zEoV~9IXNb(i$OGmcyz>Ocq+9?X@MR4#Pu(4zQ>j$i2NRu=JH!q|FWIr;Q(V0r-aVL z1e~dVser@d3bFUBKAfu=e5U^8399~{tp4Sz|11h;XX;;Ob4BO22Pp@YQVQ#~nIHH= z1RP~CNnY?9UH|et%2-2Qemm=5zW&qp@znl2Q~#3E(d%TvvrvqDMRPPq@@~q^wL?1O zZ(jY&3#f2s!rYnqm-$GQiG(6!YM{Xo)bt$%rOTGM={{$+uoI7HW;(dfGGB=s+U@hN8Wx4Zu3@F#Qb zi!=2vUAXM-aahC{^Xv&>4hHk+snox`z02V5O#MqHELF+02LW0)numTgpANQvj?1b~ zPyNfMJEQCI+g1Par=Q^4&(y#C+4iCkwef2dN`J=){8IVQiAopl_;?jUNLT&eXqTrK9inT@cm49>VU;eT^3fcIb&(yzENS&O3R0p!8#VoM` zM760o2r8E$gs8`fMUqj4na|X}ly2kdUv9kF0PalvOF-(ss{Uo{CKD#k)W4J`6idgM z`j_Vh`w-cia5H^+c^zVLMa*GGBQV#LZcFqY0v&FDh!g>E_W>u7CN44@T$xO#RD=%;!XfMQNw9 zfd9tVzx>^6g0(+W|MIuF{^jf5AArG``j@#xKw$;%mt1jAneR@y{^h;zwV6Lt|1z)? z|Ay7S{PrrA?@ay6k)R;xZ*Kj|b5|BD15QoNXn4Ilyy@ftZ_?T9xiwzd2S*V2a^4?8n@(Sf7mLl z9nfwiFAwAI@sh`tJEW&Cxk1KZm*8WqOSz`R)GLPN85%()X{_XN_Gxlx*{PK_H$P&GL9$*H34+0cS)999%wnJ)Fj8{U?SH^wbBKWujH6>ClSNq@+k02y~>yr8YSIIzk)w(&=) zo-AL&^*b28`pmh_Nn++UfZVMRz<70-i1H}y3+i2NqN2J&*C^n)m3wQWRW2=u4V{vz z4v$%3<*9KJ{eAdumy+RBQsSm!nIuulQdz9j<+cXJ0PW6La=m&fDuGMsKB#1_jhqAcF#Ge!kLWt}}z(-Z8Z;0Z+OusBPJwIc4yqDK#vTyIpB=6}CK8 z`20{)6h4mvpS6HYouD&CNhASieB&)Hoi0i58jtg;FrBWFD64$ z2;=G_wFG5M4)9cvmex!!4xhlOXq?^i5CD?JJr}Q5n!*=Y8Ggv;Qr;231Iw@UOD%&& zzQS!KkAyTeH5AFIYorXI(c0z{>WavOgiX8H7-uv%UbO5L0|Z^> zVS!XKj4}m)xO6jLb&vstRvs?Vt^;8znQ`dWSG->XU|fDh6fh1L;SyiISa1Q!dL%{` z-3H25Rt6-i&$4(K@nTC}@-Re+B98+dZ^>Mu@|6^M^z-E;qnxyWji&l}wq|Z>pyREX zc@(cytw<{V_+k0VBOx=j;ypv!vTy7@`a(zCCU_ylEuGq_b~_~|c*eKgK*wvBW8U_@ zsIZ_y+|xDCH&H6+cjh*Rlr&c=$XY~-V%w)t#dDye$`u##gSvgW7NLNUJS;2&+jjE1 zGNiMjgL^3+C`u=y+##fc;X9L1Yc@>2!p1CXd)Njf`_ zvi$mOu1w2zmxWB;TdT?98BB!a){-)D%fb)%9j9dFj=aq9%J2+A>u7JL3aDgi^3^HR zUDMqqrI!p-eJhaDa>~Z8CR`y zl(b+MGhM;R@-jo$f?!|?+C$jNEiaz`wT3(b3i~LNo!T|mM22|g50vXJIhgq<2v`&# zV5Z^4^gSQoB`=A{@jj% zj<*AtZxJX@^BNQ0JPN(L3=d`9-aJ?QikGHSLrVIx!f6Ju%No?u0Kfl`nBCMW3-CC!4syJ#Z#` zvV@`ldGSQGEInI7tMaO})t14p<<&uz%W?Qo*K$4e5?NAEkliT3+FCwR1zTHg0U28E zamlim|1!WGrK9B2?J_gr3LAhRFQ%Ow)jSe^=h~S((Xs!gIed6TYU%Ue(B;qsY${9% zIUbtKwht*3s=IVC(`7j^4TG8z4GdEFQhv`xZfIs*_P?Am3|SZm*8nD1va3#bki(RX zFO0B$sGLz4Vr9s&aooUUVmNX|es(HX?+Cei8N*9~s0qcG2bJ*6vsBRrQN7dwQ^sDz z6cb`8e+6}K84Mwc!3LRoBLvpA>rob1*?W&7_0S-suLdv%fLx4h@ss*8in>}R-tlDH zL<$75ominB=5#Q!1#7)?1-RMl%ef`&MTFVF3r&RK?XBxZ$uaxKmL&PWV93SdzElyN`&th7si;+wds^Yg5N51MABs%s)?#hE)s?yD&VMm>U=#T61-L%*+rP9s;UV zNUH)H~1(FH+1oaVz*xCPq;DWB`98(Zr|+PSe9QT!sNg=!Sd%im<-Pj{11Nr7j zHctsVQIL+x64Dvpza~M>_yq~Fe;>E#C>60QqlyYj3l9aQe>iHYvd1q=1QqNO)EHZD zIsk+qo!ZU9O3OCIJ7ADx2+mbSv8r{asalWKz5}ROGKwdJ)$Pi!2ad|GLEH`$?ecal z>UZQ+Aj_ki3ed5K;L**hrRog&n;>{RWHzt7AwMYAliW5&P#lkUM(v;5>8w#bVrM9C z+@W-fdPEWl=VzJ9)%kRhLW5LUQa5-`h{28)QLBNH3bZKb~1- zb?c-oXs~EU><9-9Rf4iy(K&tQ2`&`Y5pK7CD>F= zofQc)Q#<7nYIuriI|eQ-UeytXoQXJf~b31V?(nut>+Sw9DVYik1{R|s*Yl{%B~ zi39Ua2zI>lVM5@cs)D}d!~AyG~Fg~+DbzODKuNc5y{38e#aFsfWm+@$jgJ$z0 zKn?KPxD#dvEn-x8Lpvua+5g1Jyp%wrsY+16rC*hmJqHjuEBgqqbyWu(oy%F-_sPoc zh>Wp8frz-CAZiCEFU`tc2m~)@{R4vI$WO5Fj_jbFb^{OvtWK(G)Y3jQRzpp#nE)at z&`@6v)p_b7F}kf*rS6zjsqA>CqKg{32%d#6T2zAQexD2+JT#xrB-GKp76_5pe zxaX|GN>HJ0zyx6{e^DYZ9%X_Sb%8y+d=s=@V*)xBXjm+AH}p%~&sm)rl$cwN4~7O2 zc%$f?F~yL{m?7kl;KZ!L;3NP$E-iXFU^trlWmKApg$QfYNe2^k68v#_LLPW@EDzlM z5eJY*Pk{$UOlan^Ha2J%GeJ?A2s5-2ei}^356#r)U-pLr&dmm#TO4r05CxxKHfAWh zsAGofp(ZH^;&ej) zwHeFM_fEGBSaxi$OMeZFumKOr20T!b8W1p?k_}iUOS3Z^fguM@0~K*&p>j50QOBqa zIPku|gwO_Dku9qE=R|v61<49M*<6NtiP3J!yZ!V9zy)>9Q(NbOS|MzxVlc3AjEd(_vyHokC3{h* zY^y6&7BbRBF_9|h5v9rmDDt_&OY^+gsMH)+1r|2CV2)LRO>U(+S%1mbyhB_%OV!EF zlHLd{bllU4?~XP(5X^~mvO}4DVHma1xdL7>=Twwgj&-`2;OqB6kVIsdw|pQ(phD)% z5@UU}0W%GFWk0Q5l`;V%C$37F&(RH3DFZ%?!`Z>O`9p!O6O}%PX&070S3nW9JHxMUVB_@*&P)hk2gH2Cs*SwIP502;jT{wpYeo-A_= zah$T}IhU8^n{c+VR}`T2c`dqgoj}FBy)^< zVCKq}SxnZy8_&b=b=4yvYDgVLdTzOhKcN}*2E0!M__;FYnC+MUC%h#OkIQB4;I@&t ze7$qvyu5vo**rNc=3QP^F%RC=p{#fxYGoZ8R3dQ4EE^O4`DS(_nKyttUwvF-O7>=Ei zHN6lRM8#wqHD-pPR36ll)N$V645fNnNWnOqp;Q;37@QYsjT0D3#n=iBrDIv!OImBI zcV4j2%$cz?L7x-SH9?Zv1J0I<78$&0jFI%U*G>Qv6BSySn zuU=XUKl0A=Ge@1Qe2Dn&&cQ1_x8jFiESiP21RI#p)sw)l9nB5?XI`zC z^#nbv&aR&H^wibFSoEwe$|MIHGIy<4k4Ucmz&TTjywB*B-TW)++*>*n-!sX3t@oIB zc}4c?>wCQ3HKm=47Zju0tXetit5^9uu6k{e_x;wrl|=`F|5<%8`v&G9+g{0XByHN4 zdRDdYKzfpwjP)gLiPFU$kW{{4da1vOH`NVB>zlIaN(pl1^((p_S@YUVU8(m? z29xM~p}2jrSDbC2)M^EH%DKb!Ii1=d;i5Tkx@JT_4uP@XC3*f{7@9rSu<* zpPuxtN4%*^y+hfCHP6J?ip^1K_3`?ObbXcAYpFK(mNLj-eBRFtU=9JXn)<#e`!&S> ziUG#b^@+#;8Q)Skbd%Q}V>v4X;m@xw&Ll_rl7>bN!BYA+fAbeo@snlG#8*z9c|Acr zsgb^^)vRLr)+;&>a<6>h@^CF5AH9~bzNssCbi(_I{94cKd@)>Wug^_nB3$jpt(6`ce>*6<-}m2miBn4$BEz9|O+Ou0Ioy)l?l znV-Een36|b!{87eS?(t9d0+lVR#EeJ(3|3LWQun%hc9+~+VEw{Qtx06Uk*BqSy+)? zSoL4@>S^hP)xoQuST%#AgEj+CteP1)o*g-!lRMVIuVI#;Pr)>aM=zWqDwJNhAS6wf z=puSSo;1zTmD$lNZ`Bnp=bx$Yru<{ETZ$0FN{hTH?|NkPH6R8?_q?}cPTy2A7o5(Dg?tlE3&t+#l+c&l1`RzsTzBRV?4Hj>)u)-_bnSZc;?ya#qe&j8zn7c5s zYUP@#4gRB_9nQ8q6yYbZbpIZh?z72Q@tRjP`P(mlEzGRc=)6d1!T*3?Jtr|>$_8kt z8r*t<20YKRnZn~&{7_sZmTYN>|6wyj1rh?w+e-wp0=ui5_FLG1x`K1$00sVCj&d$pt5=JtqBPNfm zE?yRdtOkjW{XaVPi|qQI_Otu2wHFmVMd7BRW&YczAV>^pyd`jcW04#@(b{jvndFfM zj5SN2Xg%y5^%7lQUsIO3q|^ikhFlCVC1Lbs-o7+~9;_WPpDOR^nHj~oh}Adv%h3uu z_f>i^C-|h}7I!}Wha;q<2K_1j@&Z!9h@eqo#|6tw>=2OH_s%)h?_K=8g75u1``&j? z9{+m}yv%P;MTo$B zz^`M=Snv%3P;aNng-A>>fIl*2jR;?mANlS&pR)=a)L`QnCRJ1+^&vz)iaI_pcVD?0ouiIUc3%%5dl zCR{&sSxT4coh}pBWvRM6OI>nKmv(;khGO-%YUNeIhpjGYYiPW+sO>WBdj6{Cp38Ef zwuuYZ>B3?z07;P<;QRIM9c5kF_O~Ilc&WB&PQ)~1K*xmQi^DUjzBbeQIX*PssF>l>Z|?!6l)_S>Uws~ zJovocQL&WKNDM9ucz*gU?*ImiJb(~VZmLQ|F#d<*+3eGkX7!*?=vAq*^i)2_B;qkr zRD{n5Qj&coSi@IpxXq)6JE?QHxP7W5V3VlFZ;y=i5bYhAWquh$Q*+lN?Qdmz)8}}p zsuNA`1hcz`SsHhCx4Rn>k#YZ%GQTg zf530PEI;v=XWOS~;wzc>Dos4|Tcy^~i8mxgV+m>1IBT%*S@A= z_B&#krNN9E0R;eTMnernGZSbiqt+vwPT?!_$;di8DnvZbmBXLipB@@dZ7Ifp1+hEK ze6doNf%UOtY?R;qke3WgTbHgPDmGdPJe<8;W@la)8Q?uTbfJ z%9C^nSV|0k#qY{v-w|N(PnsgUu{e$56$X{&gj$d4MJR=kA|jR^Af|I$DhMkAU~i8L4868m>S&AIM#)g3}|I;M9kmE2Z@gT?c*hE1@p3A-B_&v$TvkkLJy13LkU^NdxvSK>*FFo`N+*f*db#a6L#xD#*uwznU0`Bj% zuTQ7eLnY76)JK&3se&C5rHq<}6mOJfBl|`6K7F#kU@08ThKk8!Jy);O)s2ymE`B|RmBZhN-juU`d`WPD z^<&y-Av6!3PCi*+EGgzak#6npynRlQw~$D?!|mq;EE?uqmYzSyyR|fv8d_b%|BJmT zZATHPR~N6Iyt)*zJKa86Wb@L?!+wsWnePkz$A0!))+<3oT-ubyHvbr7`CP+izErfmINo&-b{?;uJoC+8 zDC*o_+}8iMTZ$f7f6teS{#Fmf%O~H+aqr}H{4MtXY3RA^0~KT3}eY}C<*ISSf8 zu#F3Co0DG%8_@i2F7-~{%HLvtjhb&)qd!#h9XgsBX}*sOZQD}Y!Uio9njIwI11l>j0s z^BFpt9cjLR3vI(&KNB{f`AjbLPOjx|vHxy0U!+D^9bKlQ|KzBx{{wgB9`Y9&<;|py z`cH5Vc`UP79HwNyx3Drx$Y?o|X+!q%vP|-5gS*=nW5jJY@|~+OMDb)>Ef-do`jvk^ zsmQ^|q(?igJ550{`y^}Zax7cq`^SjmPJT>2>qq0cz9b5?J$r{jnGnaZNZ|85ZU#{jm z)##f#+NGnfa@2OW&69hmr#_gc0skMlmq`wUv$06Cp|4q8;$~x=W@Czf)}Mv5Q5x_1 zb2l415l%bzm$u!_BM%&)O*k9f9QRJ%&);JI<3DB;{T%uWHJ-yddJjk8Yz%UtZ4*5N z4fvcRTj+Q|Bu+n6Et5c%H#z!fZWD0_3IH&yD%>vUYj z)|c$%F%0LkzJ;<%n zox|C97w%OAhkLxpjsQeZ;JY1zFz#1evkRj+V27X zC-ytw|G<9t``@BuMx(jzq08z5nj7=q!@X?#@k}z-wvLfB_*+=XZ2O2V?6eD>fk>=vznygi zXGiVq!}joy9v-j@EA7HyzIBQVo%?FJkZt$rcUfC0q`JYsprD_(aRw=gwavDhm7D?u znOiZTly&Z_2Kt&BaO$D`x9MY9zYjQUDcKKkeBPT>lxsLxt z3)pbDC?eJmlyUQK^#qGD3=!|09OIH{;lV9Odbpm`;i zdM8)&x7dH=2Q-?gMxR#m**fZqG{1}sHX%U+n$O`<@8m`NE%xtJ^9D6)Q1dHvRL@b{ zknt_|(7XRv4kX^eJ&28#<3^^S!A}DtI@@k%w{yngzyzd6_pq*s22itePidRJ8FSJ8 zzrh(L0>65y-+JdHOb0Rl`wT*&dpPYmiQVSEEI?Pt_EK*OIA&<*=N2GDi4kzbq0L}$ zFTL<09*?5vNP1!I=X&_aRTHk$8t(qB9$}`g=BIb^jr=Y4ul_#sa~p^LTQz5Q=%|XL zaGf@BAy_ACK=XB6>YaQye~bM$tNCU%`k{`t=;%p~!sffU5Ui6mp!rrV^-kW&-(vr} z$7s~8M%&eVw~qdrqqdoby6&MreNS$kKEXXL%djoWvD~VG&TSW=gEaX4T+?z@ddxCvN=7Z?XEwNH{9WEzxQwiyvq$(pXZ&c;ox`#Cr+y5p$xiQDal@@e zKaVFSZZz z>w+q(0w}Ydba)5-n|-6de&1PDn&Dy zA5%PfiFc32=3QD=b1C++#Cv3p#mL5X3yO8IJ^Z*guQKqSarr6llB#(1(V9!JAFufL znt2I+ei-=JWJL>}j8{JsUMvq{p0T>ExL^*sPx$=~J=@ck`D63jzfcsv>c_p7;-k3N z_A3cR>n?(%$E1{C6BnSzJZwTZmu{t9C}}} zM>qSD`}Ct`+xn6_-0|{nT8=4p3fd^H?+%7=&6d98R@Z8y>#w{~Ua`jQYEP02jk)!1 z_ik*XuHOxr%yd43?acY$lNJZgy4whky8d zcGe@A2i4!Q^*tGzv3Tm3wZg zv)`WZ(b?`%GCyhRPx$Doc+?>nNLN!LoHG0jkR`yB04G*YT8&tg9P}Edg#=(;=>yUn zakj)j{fyArzi&C1-4A^@*E`F*xHP+V?-Suz=5P9JF`DPJj1e#Yt^f3kZ0Cc^c~kM)O3yM0(epW-$oa2o z@L%^XXJoOV^ceuH1Bu6Ti&^BFK@~RXi=@xqR@%AXLa6^a7$Zs!`6J0+;*nqT=FU4V zEGue%13!tP_Sf!^c5bGJNzN%4u9)xXNOiO5B$uOP49{3CjZMlzsP#G zUqPtb|8ypnRIDM}REfU^++P?&j0H7Hr^|JNx}s}k;kDeAMDz-d!lrD4oSE~N;}CLj zUW(eWe!@2MS46JJ_ZTYEPM^+?FaB#E->A`yny)|k*Z=zYvUQk$^+Yq+EpK?vdvxGH zx18aT^FaPpRF1jiV!&x^)w}S&u?V*6@$>6r7RlIT3(jeooi5aAg42YZ5)qVGSixz9 zoxWYCm7G@E=^J!f#c7qDp1sNfKIOD;@#?yEg&!6XBJYA<{oVpjEt5aS) z&%Joc&SEuxSC4fv=6mp1|5tv{IOCZ#!Fb|#egQJ2iQ-$`B**XkOmHbT(eXPwgG>3z zUZY0&$-YLX`N_6*n?{$@Z0>E{rgJ*oPHo+)Ijy!+TelgU&ahKkx0#&Iw9|>#EmVm4 zUMV7tC`)C_^yW$6eNi(9my~jYlSRl$w#j9l&T4rODabDH?Jci*Cf*usd|CDC0hB1N z;Y%)8)I*|{rtVA-QmgjdTRwUBAL9eRvIm_kIs7F5RZaJ2FQ_PbvUM0uC^h*cp!|7U_9Lru9t;2*z8;56zos9cUd{hi)zJ+#y?xq3B|~Bho>*jI%5@ zwqPNLt%HwilZ9X@z699GgVXox-0p|m=yTn;nK<60*9<+$e?aY8Uh`xt!zX59))>Gk>|9`z8ZqE8Fk0p9 z8Kd19zcRE-)Ga5>>7!Q&m54o0)U9aSj#Q-6VgD;%zO zDNn-r4-$i1=3jWo1s4x{2m7W>ClrF4pWI4!{*Qn9qRcX@(lc!=f{)m$l`d{inr<%6 zzJOi`H0lr#f}vfV8!3=nIMP=~MtapLj5KpFH_~v7`ncnLQ?3Yxy-maZyHg%^_X65Q z_-FT;!gKJIPky#G7F$!b?zX8#?dSE?#^S&fp(gw->a8s^cE#1;v?$N~n3Sf~wf?@h z<>N;xy@USpucDt#*^RwI0V5YdH?p~)kfzlO{7sSP-^BCP_WXh9^L_QT1B+ZoDQ(-I8~SWJwLYrPWO^O> z_uhwuWMLKrfK5%upZYnGZ(dzxOD{CEyI|C=ugBNlL+6=!rJau`8aCGXJa+C+=zWvC zN1wVy2ex_MYbS(i$h$|1M|x4|bN^o4I9&2*dZuR|@EqmihdhgmDH$qe|7rW6-}e{A zMF`oqdNu^`$+H=WC#Ik>Ja>dKZPON7es@8l>!*o8YY$(KM@Y*y0-~Nf0`w8YscRM= z1upq-zLXe}`is2B8kBw9#irm0TTsio$5k{w*4E(J@&kyJ^^LqL>Fp%IwZsvVYy-i>K zcE;oxOlB zDcb-=Ow3>5;f70F7!j-LkO7S-reL;f6~}e~f8t$Tz`q_}u9bDYy6{0N|% z8vG5_gltMyI)!JqOy=2loZ7RsPrt})SGq+If?3{wVU~>p?bVD!fKc*iXc!WvH8WvH z{mcJc8ZB!jlZb!(&o%S5Y|sCj)y{)sX5>;{6FK< zpT8MPe?A@3pUyG#$6i}Ne>9+g{^*l(^k*SU;pmTsaJuNv=jvIW(JS@-}vV|{n3R6f9anU(jR+lkjDc0^SM8Ts(hFpIv;GH0rW>t zJlWu{eQ!X2jsdv-G`+!6uQy~e zc4hG`qCYx}(4TkPK-7W%le>il_94%FJ)}Qhcyw6e})L=9yC>M*2>ukUobW4HaVai_eTpjK+O7&g;e@ zM&myFPc5>qk4ud7{7Hz>!*>P5NFV5b@Y7lbHS@3gn&3%?Pc7rmOC&~BZ!RE4NJY@2 zz?q9DS9U6l8mwLE^w3zfkl^q_^VPzt$Q7c>bG8f#S+BG|XJ*5eIqIF$$6To%b7jVu zD>KJjnLXypoH17}8gr#Kaz#_Lz?%{(2+UJ-4)}gFhHQImssE>lr3B}+?v3T5U4r>> zn^|pxRQ4;j3#HhrO=SC_d9`%!b~B&->65VeZSS~$NHV|{i_w zp<^=gvQ<}MSU-gY@sqT4#xVc_0bIG2iM4;cw{9rWjFwwY-WU`=`?Z@)?*qOzD zzcy1}(Vzw~0<|wE+B?{XKfTJ)y_o#j1@C9N!XaS9lTcb4%e3?QmOV{$^pW7rkLm_b zI%}NN^xA|cQ(ykwsgYS)@Ikg$92SQ?@-&(JMJPp(f{tl3ic}GCXQYP{oQEo{vqh^>aahPJfi(?vgbOj z|H^#-pBT6Qrq$EfK0EJqd<#LMrFh8R-8Zik7%u9Yq#Og%Z)Jd-M<{0^JulHW$q%kp z=xT*mUzMI$$V8r(H3oKi@AO4Q4c{LV| z^WIM2>-|0H`srT%bb_c>7k3WCmqMs;*!^^SQMO-gtC&8u_3>mRNmXSXVT~a%I{|`2 zY$s{(-*bVT_$U03Dp=_^($0iz?OMRIh=23D{K+2&*Uc=ItB%m=^V zx~Xsc^=&?;R2R(0u@lY*K4k*5N$aML`jzHBIe^Az^YI6>hqJ*dXgVw@x>+$2nv-%> z=POqt(1h|+E>{=%xna^N=%-OKWtb6lG#wpNCnM}vA>Nt%G&bI*w-t={@VMix4%QE= zBE6(#;-(|(g%Hg_8*j%fTff%Byi7^f5~7UDmFt`=$^<1eYQU}AIcnXP61& zudKE!QvLCYy{wSsc;*R02U=8`DW!>_EB>`mB?PFjtR2h0#My zo4(j3^3Y2GABO8st;oa6HSxrf87GFBT?R8`#Rg^sL)!&6$(=f9R>=dBuB&DWbbb*q zwLmbX^a}Cvi)V}nSHRQKWibC)*>~Swy7ne)kq-H!V;aiF_EeGA0^8YYnFKR zLuu&s+In{KJwC70s~<_vE8~2MP7_{zEIp4+xMjj+@H{EE;A=9A^82>w7;ciDH|@^) ziVgFoFYN5Co_l-g9a~qf(oWnwj5D6xaN>8}2_2#3KiiP{o6?Oj4XJ*J-WPb6CQ2SH zIp`Iq>siyabr{PYuRre9A#|`BYwHr6V{fapkgBS5eHpvU`s$|9V-YDx?yQ@>p}xYK zpFp9%Z00nO^>yR!i*JmDL*2koBLj8h+T``-wrLPN|8swqw~8YIrxMdX$zvevoWLv^;Hw+}}E|Ld!B zxrd5pe~|r&b+#9^udY%}f=}C`F}?2=bN>QHv)*l$oflnL)c#R6sy*hb5T3WJl(ou~{aL1JKZS)d z^NQ0S7isPK)|$m$>4oVMx?gaiKmb8*!G&yh6L2oLP(Uz0!IesFV_R@xm3FCJapAPl z%aUF;?al=kPTw$pI>Mhsz>Z-cbRo%m=iXKp-}oV>hn#ZusjQCeL9}mVBlRJF(St8! zKQ}@YDUs`!5VHQaI_^I3=U-9`$;{5);`SMBJAb~ts7?Obw%9WqeEN_8*o_lNQ9Y?N$N6uY{ z#-WrQuVYq%lpX3Xv!v4B#)?Fff4njNrgh9NTOUuF|KqA$XCRf_q}naIcn(7vHxJa} z*%RKG$(`{sL>*lD)Uo%!kQL5~p6MOX*R`c<-@%lU{^+vG2`6BoCSWZSfIROlj(J~W zKd^n*?WJ>H_>Pu@P~r_Yi{88dIM*lU)|agzyy$@|?N)kiLR!#4wryr_ zPWaz@KATmpt5Gyh`~nQ{mX@X)N9Hz^u8F;?#}V*lO|!n$j92BZ{aS|G65dA;ZbmXo z%4%NBG?k@0VwTUpPe z=e){4tgB>edvauc=bmctymN2$+#?jo>xezI0=QbW@?AXvS6a1lXK?|8;`>=nzn#2A zVfK~V%3OGs@`4q}YQg&ReC96EOaG@M%=%Rldv0XB`^R}qL$&{DeVswzV6zN^ z?AI*A%GZ8A`_ZQ0!e+z$+1Z8$wig{l>H(ZDFH`2WHD~L}>R9&j2Jgt~i~Rq=JG@~4 z4mG(eyJm(g42M<|Txz_)Z@OAkhWuSad}Dgm%=E(9>09SO=hA=l^n3VmIT#@B=Vj(A z|C)SrfHY}h*s@KRlxl#2zZTzJ{w7X4OETd|AbAt^%c~dUOVDmLgJxhg;*Dj0f2?ih zUy<(P7{u6L^-t2N%AyZ2ADx30Lg7p!%5?|-7SA@{PDN)25p=Hs8Jq_zM_;|g(1rN= z+r;PCSu@y7g!lAJ{Ty6&W&9g%@cY2_OG0SR05M;I63i?MXE?|+^f7>M?r0vo%G{_UIiHp}O9s^9b4 z;Cr5`0fP%>yG7YG$Zo>8a$;9=`YgZr?=>ud^c045Un`$&GgV_V^_Ie!Di3BV&t&~h zwaA}G@JsB#TU%<>y`&@dipY9vV}z{t9FLOq?_Lp-^{7?A;JMOF3<&t%>nvFH*{9F; z=9Ok{k`1h6i0lD<$>UnSAXIjlw?VR&x2hB^8;W!V`}rG>Uyfy|?P>%-x6Od082?pPpZvy|tq4 z4(>Pk|G>K27S34PCNB8i&gZht>;l3~uBd+hY=koawv+A2ZCkCyM+L%n9brhq!B1}G zL)*IbF5BYySG%;WXZR{_oynIyYw8=?4qLlA+G(@VaXXu3XG3i>ARJBpTOxf<5BeOu z_cKAC3+Xf4KG?S0o_!w3&<@yjcJ?%9_&Ky`Y$rp{XKu{V!&?Dw?tDU0Vc`+q+J zYOJI>x6IBqRClhOsce(4i{C?j>>lm0Hwv@{TdC!Ttd6dKx2Ro&zq!S$&txZjvdr zs^p;t|K7`4izPE9nH=H4Sd;%(Jg9s`B@fNQ$x5`}h_^_6B$hS#pH?Ts@RQ%M%d;Ub z)>UO!52-hp5HZSSzE7?WdL($+vGG`u6O4bdjNKaSbMdE=7bZv2LdV$`y&R#~pLB4Z&|og^idWx0x^q$10eQc{g8 zok#6=nNLZEAfKv<5^Er8uw98fpOi+0nO{F97MVk!(p}V#T{MS)R4$&>k6j$=nlSn> z1AZreKv}x=aAtmGL*~==&LVqfylWXe$NQAN|6im8b+NtL)Hm-N@g@DU9_jiz@i_4% zkET<8ru5=H1Ctv3`x}^P6vO8~spr{l3CSK7 z6#ef6O%Vsq@zUxfQzwX z>{jhau|>@YR)WDvkn7DL+oHu??dsO<(k-oQ3p7@$2~ZN1LR4Cz2Aj6Dy_B?qQV2?& z_xqf4?_?%_T4V@n>w9%i5smbTP|(SmXEt@q$IZAI&T7DH>XDaFjxf$mrMY5m6OpmmbdbM7mfV_( z4|Lt)#KU6J@vJaAg1e0JgI3l&9D`+>kMAY9T4>UTMft_LUR(|52uZj@6(Gy6vzlHv z)``~ze>yC_@GB+XgxS&vIk65D*xG-gvL&+)G<@YJ1`oHEirf141i?3s$|4hmo+u?Ku{&5_<%Rg$h)tW!>EKFWCIvEvf{*tPv%g%?@I;QCW{e>O+2G5Uo z@GO_Z?=woe!+=kyaW0x_mE|U8F(j3wO^| zN*3*5d0qtDRYQ}aJ>2Rj*v>!ELGG3`ScD>LQVD!Spa}NseAUBvs}z=kyNvvU@js!8 zwVdI0J8ewDd`Nn)%?qh|o_HTdKiW{v_nVHBcjs_=dF*^+(r@JHWl`M?JS-W;q`yka z9?3f@Pi-ns*%ca--oA_ELy~+#C2tdhLG-@&L`3;p{_Kp%tmQ`Ryr&>b)H;IeO&Ekd z`0rQiq1_k%zAPEK-7P-q)k2kZtCo(X7NMoqZDPu|EVY;mc6r}*7BuBl9?HlMT`ARF ziQiQoE^x4m(p(>_0}}j+c0vMh^xBL6OIDyi&nsoZ4+J53eCVOn6q#^=odP8wK*_k4;S~|a*L4T_GoS3#5 zR|fh-y9lxmBuXnHH`ov73GJO@&4C|rAW}8YI>&x%4XrWQj*;5xzp2sgzhD*o6>0GC zT`I=ICZ>rYxzHo5Sf7|t5i!GS6X6Zka>(m^8beaE!K$7vmXqPN2x@lBBju?`GPa%< zbd1?PR)w}&v1V2;i}E zVZSTF9nWh9HtpT}q;KO7ATv+ETCRe%{ETpwzb$DkoME17I2>7t6q+%kQlxzb(!V8s`_41;ScI6YP}akkluW9eew+T< zU7F*-YM^{oR8fcjeh-V^F$%bh1v+yH%NTwC%~Y{J!;UJey%221HD1W?==cxtkRkBo z*p1(pi5EllUnao@uRdD#+iTOiI}l{ZaptKzw!P*PiYM90IsC)!PW5qpDB zbK0<-t5$#_a<|2>{a!NSy9?dLDf1D^p8N_M;JRfDsk8V3)#BIT{?VkwubKM2A9&EE z&f+Ce#wAg7R}<5p3!Yf+#}X)hRF1Tc)xQ~uCGkDOuZzFXJHyET_+n|2!|O8<9$JJ> zHu5ixaB>u!Nz6tp@fEv8CKcSnooawk)PRcZ76PS zFUs~PD+>61x%R`S&Szg2)7?)|j$%?yex;cD(XzB6Exz(RAw6)ffLpTCF1zl2?vFN8 z27F$~DV>SHPi7B-zmoQ$@%O5K*ZBLBnS#ImKKxaWY4{uON!w2yO#wDiF$R_>A%zWm zW3sMrrCszfbRpSJB}&NtDvi>1@M4J)0=Kq(_X#6#oq zpg?vutx`!IGZW~vun^2{x3@tOGcWrCS;T_k!ybz zqJ=#`d=hdJinam%=TU!L=D38*hG`*OQp!YKhl_jEky$2oEhB{##)0ep_#QuQ6uG-b zgyU9)dqug&#!g0}0b19)jN_>hQ(09pM-)iWi1s5m0{RpwmvZO$r!sX?M;B+L9*|Vp zL;)>%*96rXHP>g9*`jMo$BKN>P2>&c2=c{mL1R(3Rp$@pM({tKB0WPFX>^JNma0|; zgYu6~k;0*iT&v!}Ea{V;g*Xcs&A#iU~ALaMSLouM=b$jsX1 zs12!tX}cBt`~z$%X&cy*d^`4MciSxaK=e^J5ZVdj!GG;VVzd4;@Lm14H8=U25q_nokz`$7g)ycvZz?bL zk~($fkJ2$3j?SVv=5@}^L_jkpaiRv4b^F~MV+-4?#=HP^3N$<^wtypS4&)1GX+(Hx zqUGM0CtOepiQg-$E^oRRb10?vRtlEqEtQIkrDBazfL|!*c6naZo>MCpR7T@`VbJfh zk1v3fV<2SsY7z_|{%j?Q0kgKMFS0i1HW(7K@bn=w;v>=}V}ntd&hZ{MoswHs&yfx? z6{N{$n9{Yas0ilbaq`z2VS)RvFtE06N;t2NeJ0IM5S0C4YC1?iI&dBsAtRCrf9u&Mi$noDaz zUPZxU>X9@F25XXnk1gI{M=tDUR2Mic=`gM6bgBpl#Zrt}c!gY)Hy3u|{GP`>um=y2 z!9YKy)`0X)(p6fG1a*EaPu4V_P@EU#b%RG5%h ztwy!F6#%q`ztWayRt>8L7uuxg7`J1VD(eSX0@-<3&KBn_h}aj2$h$mmv3ROmkhcs> zxKuCCM0wtHyXFF%(3j_x+57)=CVBMh>=I0BdAxNxC^VfZQVU(yp4<#r>x<`^e*4ug zQLny90F3X*+d`q?M$<=lqqB{9n|PPW*DGEI zc~XZFALeFncCr_{>sn?1PAnvy2JiR=`}~f)4HWbkjn9$8n?OZxaEpEuAiRlPC0%cq zH;>h<@VuZ|t=UZEV!Rsj_EIQff8&$d)UP@30Ppq`6dlQHl{`9thcb`7_*$&}bUx;O z*XR+oua}a|s-*p14Tfe;cZdC}N>^ibxs+k7?86i|I-Ty>-~Kwo*O=D@;K?t5MaOvn zPm4)ADUVz88sw)jZ>{_=ZNj0L24YWsz3G&(?lPWaRTK!aBqB-hwUL6U|H^zsyRr=<=Iq~2*sULT96lE%^Q0t{wn|gCz18s;@BEgX%Y;~{RgM)h*?FB6S2>sYf86$i~x*|sb{Vl5@ ztC-fB)wt4aZHP~|q%Z7|eLdmju>7MBfBqYNSdh1v4v>=A;A}z4p$n*4LkBv%&1%yP z?qgPKEW-%zqzBSVYh_;9Nsv<{iHJ;v(*FrMNM047#^1R|%-VJK?TfY0*xMjM{ ztazIbFvY<)C@|e(tF zoqqsMoq_rQEZ9kwjEs|&&m-6&SRo@Vho)eXl!(lesgVM9QKdG*bWrNVHx)t%dL7+^ zCY*C%?&Z8VqWE1N1Otq&+C{dCH4*;3`86e!2Rv|vpI zk14ovMPE~+$}d=>N0(mtB~{Axwe93dAG!PGDP~`qBuA5>ee`kkW~lmVd(?Vu@04br z1gjxspQL#bB{kZ5Nw;k{F%XoVB#DZaFZ6M)W?L~Nx=0oiPBXL+Act-W> zM)eV+`p>vfWqs8i;m<8S{JH(OS=%*jQH`-qR=-tRfj)?wlXKg!pOYByiUNc*b^UYdMyc$FuIV zBJtagWTl!-D`Oi?UT$kvZ5Ns^p>C#24X``ZwMS+#)7>d%xY$N(yt|`4) z<5_6;VgAoSc;plZVeM}5Otl-mf7KP`O09G;RYFIYrRxrA2UYKi6Ar!?7;_Hx1M_$~ z80D5tj&P~m%goVu3;&p2H|3E{>K;$8dwj6EA5X8#T|gb+va#yMJA?1C zWM}Vh>-LZ8Ktlf;KW^P-?-|u0Pp=xYe`UoEj(SOBVG$!~j>f~X89Qi(0zv%VHbZMl zR1MZX>XBd+5$Ah@;TEI$1c#x+NYG-96g~?}F$Zk67W%M07Gxf6Rb@N)d=kxnBO$&+ zg1<5n4+v&C_652+ObFbFn;JYm{G`j?b$! zKCkizf92xyuS`V78lT4q#L7;P855_Q6h6AK4G3Q>`W zyO?^54W_0c>8=leq@RB~4M~;zI9cEdwNpsik>*9tLDCL0+}#gP|N2%Mq=D#ee?WBq zK^mAuC6-=}FGe%m;i6uz?vM7nH-}vS0e%kT^v)u+JP3Bous(QT}40 zvdb#UwyrFj79zk2Wjc)T%S?CmykxAK0EfdUBOWN#R-MS+VzFEMvXt7*_Z#2_hS3Vd zscnuRvJl)b%8Se}$lR-td6FP=Wv5l!A`Gh%LFNDlT=QG~aoOd6^-QPNN(%veuEw*t z6|`n$3rc?h!FK3C@I523KoAf_tPrf?j3XLuZH|!$DJ1KjR(a4!OyhZ442&w2vh`g? z;uDe*BI`0q0iQ3D1dd+tuKYEt{$TKo$*5MIHOgVGb#Vi!?=|M^Gdb+S-Ly7`ncW>c zVH~l2F@i;j*y&ZL9W3 z@Q@ihz+4*ThafJ4FPh-IC{iD^!aWK8kN;z@bncIPu0l_{RSm%R-T+z1%93*7+C^-q5y5I`wL_lhG^DXf}|kl zvZaEbpyb6@_+HIi^ZJN-PkVLEAT}BAJ`8XnwH!->lsbk5+0qYRc4sES30HqLT#%RYgPERI|JW31m8}&__o(M4|fC)8HowhlS5RWhcAI@eH89MZ2P_7 z=Ik1j2%wXy;ew6<`K$G%l}jw|w;$&w%V@#cTX(0TZY!+HZZ4whB}Ls{altdb;BBiK zY9nCXmu<%Ef_E5hRA#t}7L+V4*lAt2z#BR#;!3cs)W;@=FN4Y>vj6R5_5x;Q4>-#4 zY3;G7y&_uhF80^$L>PSZ^n2b{y>D?-3BLuOAb7p6-s^=3z}bN!g4)!5^|%EoB==Po z+_~_}0Af}i|Nr_t?HTGk{ixtHW5r;Ek1(2QnE9g^1+}(15Ox~P|0*0(LHfX;*xhkB z)FEh;XA4et2nKaz++X!kI2b{jexkZy4*xL?OzQrs8W##%=%CCK)vfqcdd1A$Wys5` zTQ{0s_wP7S<>uOD5h1QVXQp7dK2^I|@^Y9oe?+jm_9XZKN8n_zc8AgYhrvkQzVmc2 z{Qg|(JZ%lWrIAzi$@AtKB=T79>{4EBHM}uo>z!Q6lIp_+TJZY~E4Dj$0t+TQIvC|AtgzsBY!LiDVI=-07@NZHeg6Y~@08MC7z)2#ybcLo zf5E|PLF;Ka`?BMvy8C*ILU;CkIyP#^Vpz5r&gLsxp ze7ej1o+D{ErjF0&G)GBYWoIc0SmA5OYUOC1BN!NR?K$F*u`Z-Z10Xr{uLh#9wIhfy z-UZ-ZgIxfB`Cb36aQeD8SB~#q4xu^wSOidUmQm35Xu*lo?|}#frI4)Pw$lbs;F|MuB`9ekvg3#d!cB0 zwUCJGo*-|rATNqwl?O^dhF}cjJtzHWR_F0lIgdq4Ufoac_2Yd--A=QuOQ3)E27hfN z3IyX`HWDA>*9sk&7UCW_Ry}tH>&TaHhbWBGPmeId0}%HP8UJ6Bbh^<7QL zKH9fkn8G>SM6o9>n7!0XAT6P>LxF;lDC&XU+5W_o)o|kEn1n&(Al3i3XJm>1PNRA4 z_?s9A%@dS^hN$l%7O(n#IUnVsUVCyD!r|sD3aG=WkF%Sidk-8A9gvgp+~3F=KOiUL zfk942bxG{U*-bwgT`;@4)4&Wo8P%0FzbIl#5sp7tL~^<85)_lpD-`Pv{#v2fuY)g} zwVevT_6mMgP|2#4%dEaHzW?pA2NE(dMyg~WnL@5xjw6h5kn451N(yov5#-wKTr58X zas~R3O9?;zS1*ofc+;)$W`&D4M_{-1Lm6>5F%-(UERNR>%UX9>90P*Oq%&7^JP{5U zK^ciMBhfxwFzeI73|RR{Am+SHPqaiNL#p8dn3E1bEq~UqdpvbAmvdf)r*H$D4|V_R zP2K+#FZ9VT%T=RCc%k?a2h%gdFFzb69mgisPbWy7(g#fT%TGA09jn^WNoHteY zp2|;z@~ktW;BSS*cFO+~pArh8vfV!N2~qdVGD|B&1{=l~RgJa0#&~*p1ydp7B&~s7 zdb5;?QfBfCxT~^4Wmoc^t`zU}m(Q5|#b*&XL&K)wy|9(-I8+A|yb z^mF9WoX3rJNSy;*dDQOAbLYfd> zon}&C)uOz5P+4j$$(m=zn){hC_Ew38VO^#6f0JWfVD(xrnLibW-^m-~70<3ZzCiMZ zrDkZY-1pX=eiM&!?^t^t4R*xvF%t9rH@En!UJ#EQFIh!(;=(I78v8Y^;ePZJ9Dh}b z@cQa-$mofz!zxt0Muj1RN`b1|G!;%YAcgoR?r*{e5`*YHD4v zBDkl%ZpjM!zBX6u7b8d2UmTZ*^Q{APxIL6l9c+Flh_S@HjQ*o5qK!YQ?LuyW5Jib_ zzB$5v8*^d|VYP9qq=`+1eK;c(_>QNi4{USF_ggcTN$8AE#|fQr5r1NznL4AcZba?T zC;otr#L=q>L(p(fokvo>^=C<0aiTA!>kUcykKc+mg-BR|m(tJfp2OCo+^SR%xGB$9Nn(8?Yw=7i`m1E&vV zg-?24HkbKy3>Z|MD|@owYUB54nHf7SOKY4gt$_UDEID?;GY~kQW7*Hh=o}laf`b~{ zOY6Yt(wif56QxlJf{mSWYA=#QN$F-Sz>cd&jD{1T4H3KhT?Q(=f&B=D+)3sr?2YZc ze>{T)!Fs#+dHLOF@3;cA>6?J>wYn2vsn|)Pq^oym1zGfSx5+1qhVGR`T0?hJA~A&| z`;KbV=)xPFFtYYrSE%qBSLs|m)pkOcVLyCO2Vp6couuh&GNt(F@g0>g6FM^K@Yv59 z?yK{}3gbUrKw?(iCmhI$(58relJlCot_B{lw*fa1-eiATesy<#_$BtzpH8Q$hZsX@ zr8zkVznUuaw<@A!NYLe!`fhTYw1%W1BRr6JJitB<(JMO1iG;XXuvb$z(WG*ml&8;^ z@EnrKVdt!F`(LD3LWK zZzRr>x6=x(M~KYoF)3fO)QUvCzxML>xH{twT6@e`ulcZ;KooqTq9EK;Fso*Ur82!Q z7POnS&A5Rn^6oO#iDarMA&7a*aD!RDmgAzq3^mG2teM#1x(w-Kn#8M!sUiaDLd|Av zqglDuj5P?UXg)5w0Zxu`&891a8zPiTC~p;3?Rx7aAng!Hx-HOH)=UHt4faOdL+Ywh z!Xn<3s^*rlSCHRuZykFKp5IiM=mBNwM%q7o6Tbq(?NM(lU{WH~&>zwjx+Rs_)jx9# znZgo5No$+h!=P-Oh(yi0M+5;;p@75QQ&uRRQ&Qw-f*yuOL^9R2@V9OMmKOV~UEE^9XC%xfROf?|Mg?S03KqCj@MJ}1ju`Y`|u*jU9 zEf&!NBWhg-i@zY8oi!qhz`gBwF;4g{7B9x?OidX*%lRe#)bC(7qEF6Pru}atrqaD)mI)gImb~~oQ%AC3%8Cr6(!K-!4oSx zXQ6?%@;RssWLzDFmhPHd%Ia{1Ea@@RC5O87PjvY$Ouc=tL_ z%T)dt#ch#jnaW&4W_oC&K+Y1>*fQH0Jb>h)~Ru1J*Bw2xT8Yy>;%&Y5fH_|!_Ju^XrM-Lw9-z5hLn`thCt{$aL) zAlXZj)n;r=qsJV?TDCvflcr5cM6J7`1yRyrVj&X`uXP6w>b!dJej)!>rwm zHj&(fj7HH+o5$U)JtTG<02PgRkNu@feUf}U(~YA21kDM?^qazV0g*J z!zUMyllI5G>T@#zz_f#YZxp$_Q?ScEJIpDV-hrbpQDpM#(`q-b`m`0>tX5KXE^H(- zdn1iKDdS*=1CGp;(<$e~ZSyFNA!iaq^OU;42 zjchMb{hntn^y5_I^;M%;$`AU!xz=~?%;2jl-*PtDMNYAS8!GE}b&m{p8oiHSHMA@$ zcc6q(W!=Hk0fe?l5X?}kS-HuK?S^KnAFHjM7V1TN7l@(VH=(({M=?{d&VdU;h>CgD z4liVKE6Qxf*NHYcsx4xFmhlAF`MwLx!bFV^-)z~|KKuf``}X&khSwD!KRrw1r3|Ca zWH~`ByvS`aW60%q8|%JHA*9UAD{O-U&he3q?a)iTI%5BL23HQ(`K|9+l=jT*XK8q> z=xe+vZhHgqce2DE(OyM`TH&p-mkjD3$|n^+fd{dIvVb-HS+**x%I6(jfFJN{y*ndw zZ@})i$F7{pj#R$|U;chN8Wb&{8)Z$#5X$rf*=Z9m%2fhYGvp2l@$*i22N2tW#To!4 zp3PAsTLyXp#8h6`Gz^{;}e5(3elmbO0aZ_k+@&#a^nb}6!xtcTUd~Xu!4bm ztGvYy1gi>Z*hp0C*J-o!)oYoPyK0Jho#x~ckwywb%jmlKMtK!3!Y872Zj`T@7@S=Q z32MxlT^KBpie~**=utC#a@9G=Wvrqpuz3sG3tj|$@oKeXScFt=5oUO^72W~))Dp4F zJ|?%P7G#u-yO}!sU{z-lF9IT43GJ}Y-63bu?#W5chdb8Cr$6hdyCtDwyV}pQi!;&I zj0)ypq_N#M)eJq6XcA)0%6>Lt6~8AjybD5GMId7N-YY;#q--dQGeeuQHf%3`3o1Yu2t1K47J_A^e8>&9m;ihx=#xNfL#)uG+AhrvZZ(rf$m zx^vi;x`c_?TwLjWNNxehH zJo|vo{?L>Z?Gb;2+k7<DCE3-{O_FC#X|eyb0D=ft z+#u&X7zv6(p?yh>o#nLlqu;%9uS2*HKH)`RIofUzFHhzS;*UnsT3BBn%AeG~-=zJ~ zeCjO3!Zm?De>Cdx@9{^orAw^x`}w2!-Ycy8aJKo7m=nQxHXl;fNU%H}5+fuza!!8r zyPiD{h`o}>9w%#0&8$r9(*I6PtaD5#`e0(;=Bf@0iI_Erf1C+}_2&}l4-`KgctCXt zMH{ClriwV1-k&VHS#D63xk%{GH6IeIE$e!p`H&cM(MxrXb!^dn)S<3rJwVX&p?HYP z^b(`o;GBi}f=vz`^iNl?0pTN+;02rxvul9YK4J^2gmZ|hgT^ul<2A>o2>FA>E!d+X z#Ps*4^a1!9%cdWB65U-URGlO(pw=*0CYH$GX`?rJlT2zAbj*bg(oa3OYp7AF}_uF3jlvTi;LhpXE8P zYKc!r-SfUMYOUa{grHxmF!|8xmpt4~8(I_sBN;V{51DAT7Anum_7@;<|7WMl=dR7N zW~Vt-9_2b!&T!7d9>92l^0>TTF+*76D}zfG*p2_?Qa*?egzJrqAXxE^lb|Z$dD}Oi z6>7ncTcDx+0}XoD8R#EqK>NNA(0<+jz4ll4h&Z4RCDd*<4&u_`D(8V4ke7{CctQke z65LeHqOx9$Xx^3%;BJrk2M*!S3Ymy67j=AyH^M4={_oCWS=S&`VW>}@Bs47{Ag$|s zRz=nXt2k>M&KyP23SM%lzhGp%zLBf%6R>YKq{J<%4%8MFi;tOMCvWS0NapwY!Np!0k1Qi8i? z#ohL{Nx=DVGjtt+c^I#r(+8J$E`f?KgPeOxsMDwH3-|FM;b!}9Kj*iTjVi}Fm!VG< zkMUc@V}!`};))CqQGgsOOHCo&OUMDidEMGD<3PPgo*|Q>syd-`v z{EZ9a_Y(cWh~Mk;#Lj_Ke969_Y%AOtpMi#w#4I6HiRN}D6ff1Dng6c#su^yUc^Yar zjQ?~cN4Q5@boQUd5})F}i!9;&rtwSP{U4_BXa6zSG`=7=4=2=!j_4`V_~0iprt#wM zrl!$SB8(+jb8i@8Di^U5nFXfOuG{OymW^o;3`iDd`K|IS2@&W`3PlT=Gzfm+i!^-> zbgcM(({S}q-gg?_eTHdJBc47JiExA6cDWqT%|i{mLIxKnS!=@VUNS7+imqC31dnMw z(m|YRgpSLDtUHiP7Moe9K0r1V4)U09a_cb_KY&$aZ4+L&NsN%E;MF3=#lJr?8_co= zz4{~9r0=L%QBr7yU-oF#%?w&gxp>Xj9$pzyjua7+5y~pG zk%&TUzvJlk4tBW-;%FR&HiiJ~-5w2y&t|!!nb$xbL z{qaxM_h!{A(_9B=2acx%>Om;}bf{Z^ng;WeqIC2GVChLg+q^`mF@lwTDhB1+6$Qv_ ztE*7h--r;K?Ijs&w!gvbAbCoO_U3{DYCDSMVKG-#&EBzt8A_}1kJM1WtB9wunf%8x z^JgfCq<6votVs2 zp|e9`0q)T^VF~~Fl_H<>BHHyu66siGTTIt5TMUhJ-g^b-NS9^!L2ENP)K-%tAYBkW zb{)REEp>~JXswD!a+`>dZR@XISfNkZzYF3dNQs^7gFNajg}uYMH;9}tHr(OPI8lP% z`}V*Y20uUi{Eo%iW03icoRc=cZ~*$|_wtXp^LqhPEAz|b=2zRRko;#%?xk$zeUtm9 zM;Lei|C`)zid*TyCie$#>&YE)b!u|oo%X>d_apy4aB?;NLO^B9wJO(|F_BG`&GxKy znN^x+RZldwudU&t_UfM~a)UJ^&zkEdvBQx%+lT+6r^9E78dl;j*u@5t179}bdzA8+ zj7O4{gl!t9xfgol(DZwbMP%Qqi4Ufrk7Kh7STpJ`SQ=B3 zz0iL42{p=n9`EIQ8C3iSA~m_M3?bHbxi!U~6W)X8nGK9?OADl^5kh#ik+*95h3l1z z6NxA^n+n!Clq2MZ?Sx)W^JbE)^DiS*Qq-UQT|8j@Gxd;K!C6XP8E^B?#hK=Qd+!&- z!=c~K5lBi0E>i-g#&d$^U_l1n?tGIF61L{;=dN`D=#9w9(Z*U8ba|#EodAV3LF(cL-U-C|01ZoNus|aLPoei7;nv9qFZg20;po&Z2E}Te`V>Q($X;t7l(j0Y_g1+rN1sw%TO|$1 zM+e-GzJ!8RRneA=epFLTtQ%=2%{yxUX6~RF@icn07@&9Ibo7Y*29Hgr#OY|apy#mw zDwRig5d|Xqj*zf7yS3BNli=I4!)2LBz3l>mFT@vD=%kv`=BxEbT`eD_Ba>x0?U@u7 znZ{~<`xv_pS=F~+RNDc$fDWS1mLc!*yptjCYH98Fp2Mn1quG{Buqz*R*(FmQ7f0>y z>py)05HkIPrg;RVzpHz48LYG|IVABG+0La}!)Qu`yXI;^!(7p1YexCRu41Ghl2EIS z*h|J!%N0(cR})?$?~yuynSEpoT?^=YLce&Y2Fn1-uLM6T*Jn(v4IfQP}gUlTrrA|hacoIYed zEaagu2KJu*6>9Lpk?6ESM=y%3Y=3cOC{Rci<*ZBygx2u}c0Zx}H{LBRdE4F-B`l(Q^?Sbt5)Pgc}_VA#Pgv}lvJH%)tbbuY2ZK@!V zaVennrW$!}D&}u{Q-r^Ip)TM_X?!#-=E-iG1YngN(O~R1k12NUN8I)$jFkN=DTc>K z9v>P(7jEIn>Drtk$x@|?c@%~0WMoRbH!F7DlSPYv;IYmt=I^mlPfk}aW%9SS0ahO? zQesg3iGGQ5$=&>l`qQMe9`U-E?vRXv$>q97_H5M`)!+p<<952?=ke%l>ELspCy`0w z8o7~sh8k5S&)!1-KID+d1Fg#4f)t^H1tIucoclc>Ws^X3I1Ujjv?Gn@;F5gMdrt^a z1|Q9~ffnCAQF@#xr9pnTU4iP$KjQai?mRsppuDs`H)3C}O6MG#)pTmr=cRL1*0wSk zL)B`;YLeNserY@%>(q^*1L55!YJ9K$>4t=F4J)qEjwv9ysa1|in$utHQ89F+pv~#E z`aHV;bm`SPoN|qmJ>F?hK3Uv2_1FQQ(pNkBUm`OKuhnBbB)dilxs;dxHIHbb(a~qd zCoY@Lj0(iEYRfr}MjD+UOq%R2a>c~K9W)prhGa*=$coK@O$fSOqSGP|{-N4!LTCH7 z8rN09pT8?xjdptA?i$drTrBmL9UeR5yTAVE_JcFnb#1nqv~G+uOGIQB{L zKVIZxq8bYuK*eL(sf6Ofl}wsAAEuFTHiBbrU*f?cI}e+RJ8}i#vm2h5Z$o`rT*t>B1w`MYF>#SR^AQ{YnRx{;5MvjqSTIFUV6-U2ZeEEhk+W5(qj z%Xf48Dm%suPG}HS2mNQcEzzlQ(y1JWQt=O_KPS>}x#C2-)CIDL=_Vm?CkdC50LQD3U{d{=(ns9LWphaJqw%o}@!g#gK4dRO2FXa_ z`|Qxr<$R+z`S1WQt_U zw^gVPC5sUWjA$0+^jV%{s*nsPCdLrK!Zp8xc;J2W$tKs2e~|6)4_NalyYS!lkTziUxET&{Xq}( zH*_9ue=mYuA~vAd(?Glt;pXu7z?W4MJuwOO656eH6wOU{4wRO|p%$TWH$26G5^FtN z+ahFcOB$IQVz<&&yy%gQaO$~!C>K!A^+U;NL-XQA~|zp}rS zeMX^NhrV#ov{(jpL!6v9wpHP+h7e6UWq*vBeZ#qpAaF&u=?!*&) zG)-S=P186u4B>KwhS4-luS3(|-%V(m3z#Y* zv?9y?l#}XinD7qQU%J8*wSi|(x>DvKyYIBu@lARb3;#lBs`K)f;(DJ$X*9Ne!;I}O zul|iE=}ETzHZZDl)XT8HjqSwc8^oA>XMg9Rns8_Rs#v`#7Y_ut{!?y$&%v6pFrX}5 zfNkyi1ZMryGJIzM{z=6N{)LYFo7qRHKquuy7aTe(3z=UfwH%}~{al_7-RpkNj)&+n zA7|m&c6$lIw?AaZt=R-O9<=X+x?z6>Uu5$ zGF1M@!|atv4JCE)9&!DTjk^{BaNrl`<$A^GbICF?)Vq)iB}?5mj)g!;RKH2kfFt$8Rx#Kp5&(Y zWUcDS^M`apn==~vE~(Pc6fSu~HB{(=R-Zi4eNzqP4{WH)X{aNkp(3ZDV%?A)Qfax! zg{PoTci$BBsf-K>?r2d-kFEZqKOfXzbR?sp*GLt(74P#!5w{i9X1V*O+APy==?yhH z4SDL)XYMObLpQ%qLyje3u?mJ+vLK_O6p<#YMSsyHPD458r#Cd*X{fIM(Dhr30|u*D zMb^k%mb#%IzNUw+=W#@XMLvyQTK${fpLz}9RSR0?dLF?(k!7P_$laP3FS0s`djN$YvvvC-?P*C4begG8!cP%Gu8*+ zJ5WD}$R)Lyx`|o_d{-s)N?BNT%e+~oxdo*tnjFED6-zIDFXsfph8%rFrJW^lh){&x z>r+ECN?#z3sxTqxS8*jR)S^YXkk6WKx_UDrg<_oSPhoGVWl~&RTkK~)!p$4`9m)>- z?Z2#%Nbz2{>1gntKFGzAMz`XxFu?C_t{Jl?NPPGMLP>CIhIM;dSgHN*-=$B2$|13I z&-_fPb!x_e4oKJWpmN)WXSTES3uMeOW{NK|)w`d^j0 z^=ld3(+ILsLo=vtgI+S~THh^e@b~?~b*K4XiAGq1+<)_B1M`D1)%K!=y-63X_S;#X z9OMrBq+&PX3r$_#v%KQ z$7Ig@iD##?uPi}T!Hmo9!%Z}ly#!_PTr)m}_XlxcWFv(@NSuY31QvWnj|{Gw1Dn~?aC+-IrLIB__i{gOTI5^R+h zLN?Xz94D-GwSP=u%Rf<_SeJJtSKl=`{FVRO*W{+2#-*MnI8XM>3*aKHtKrrD9FLs8 zDsUyT2JuV@$24~d;v24h={Y%)B2g7xg+!ZYg1h4R4Yk9Fp$@Z)Y#GjK4&#I9OcKZbSl0UrR-tVG% zuvffJ=%EdDiDC!exYy3R96Sl{73TKfwpVPUB|fL3z5NsH8~MYZK()mMC<71nrvSeC zaRsoCSvEDEbTux4wMNzf;M9D532?48{Z4I1=ALM3J*3&YX-;k|ySi!~7Sh-5J%hb< zl;x=n;81bnYsBPLHZUeU|tp1 zaDhzFf^ZkJ$VSKC>^%Dy@Oh)ne4;&exqGxiQh* zA{H@&SyG4&96@2A2_!M01Ig0|CCM05GBrL;EzexS@U@2&Ys?CdYag+eVWW2?MHVJ^ z)8X2RraZEYW210Hhp=}BYHw$W4$NCgvAmU(#a9)3R*l7w_JYZ+_z&37y0)ZT7*K4B zxq8PMkm^pP^UL>$e3PIhvCDuNoau{Qgx+ItrXO!^GqQs-voocbl$X80dQSG0_7SoZ zVaPr{@sL_L>kM%IA=xJEIFHr#=9rot)|G5S>M7!giiUk-J=!`TU0f=CM5kfB|^&3n|btqKuEMr~BosvL2KZtgYJ{ zKkBJFH+~cg{CLN(V_wcx%$?&e`5JyAXPBqTC_czdVu>%!Oz)`|Wp4<0OMG?1*5WbE zSL7`T@HkbOCvCnJ)3Bxj|84)9a6L)8v}7(@PywWdz7i{ghl@&1zP@+NiLz(Hqo$h#S=EQ2o&x8$W7e+n_f#OpT@dQ}%ySE`INHkI`h&a{S&x zPwd8oQrd|Y6%{o^>{I87e!1W3Faj7hv7oHoC@3V9ORk8W`v;m)6cM*O>i`CW_FqTq z3gWCsvzLFvst`Q)bMylMS%kG4H$@)%SHBm6Cs+CP(M7kXis~)%$Q@Me0M$4QoJ|vx z57{(lz2Bx8vEM`s)Iyg`NZDgJc`<(~Pfu>#pjbnfGq3H#*YhI(eOpr7hc`Q~?ZY=X zPg=)C?-JOjMWw{tWT8Fmdl(wQfC?yhrgG5)74{*a$~Ke^b@P9nO`RzqsnYzT4ejlc zYp$Ni&CW#bP!lPWxR=wXJ=EF2mvH!mID8g_IfkId`4esxCfQ@;iDih~h#s6(zE;7u zp!hY-JF76dg4M0B8}@Leaf+73vZswp{d=iVPUXM3_+6Hl+^2w+)OR4R~>7> zb6J(?x8KfIDce?9Bw}Z*u_=Kf)=i}$FJ6mdZ{ymTL z?9t2g9#`Aoh#Ql2pBJ^!8ehCPh_3r+G-tgp*}09%LhK{)l|gLu{(+wWQQ`T)ZjXZ& z>eIX5el^bY)ixlCpDvmqD**911p;qV`|V$l%T)mopVJ^dr$Ky9ftam9tQQcRzmD84 zDa%x?aJ^NlziR)TV7)8?k!tH}#Lci9?ko4Oao#T{gb`>E@)X&3{66rn`W5Rzm7I^i zBVp_)r4*S#BzS?+o-fz?7J!pO#wkx)^}H80YM{9W9~ly)@41cC)udu-h= z)#5-1B*`Kd)HMQ$a5p{^trzV%W5E9V3O(%jG4b#i&OUa56chfPQ89d3{W=dMWQTkJ z$(1K1k6zAK5tbom30sVq5$aS69J?i-cHDgR6{=;nDtp{0YXxY3S1bdplBE}uIEL$^POtL{h>Hcg*-3($ag*Q7qU#1@yv8`qeVb6#thHr zdC%~v{LQle;iA*YXNq{VyXC1^o_@&_0G4rKcxC|!(F*E06{ucD(w^Zp{LQjozmQ6c zrP7m9{bqUkCQs48E$dQ+9{dWZrMkf>aH?&X(e!G17l%1rY^1W=#brG28Q#F(EPJ`M zu~r~oBW*Ox)8w=+K1G7lMOA?=t|w{F@F)12Wlxpro21fv^0Zl=PV(e_;cgPt7&{fH zzJ;Vc!&~{AWuM8RQioJ}UaIevr)@k%BkBuvp-s1I!V^=IM^$NA;_9ZQmo zVJiKsN`FJrrD!TW=WZ##Cslq0nF42uO8^@!b{9nlc(idr5tp zZbnv8s;vf9<3@p*O7DA;RyU~^raAkpv?OiHi;>>!N(Fwp+pM(Mtdc&N)?)7av^XQP z#bHj154w%$uh}4r(YG zr)rl{3(jkB%b&ZuKGE>x_|2_1E2U?ce=(T9+p(Q0oEp z{$2ixYD{(6D_!1r%~NVAO;`0JQeV(X4Tb*WmMBvtu5eqB)eu!lmne{hsqcI#(EmGE zsB&*J?U~djHes{}&@7yFSXppIi%Dkv$B>00Gr%cTyGVbowtW{l! zs@%S*$sN$;jjCMHfG%JAfx29l-etX-{^~A}=uoTaRZ2Krj!J)qn1@ZOXa6DKR0)}% z)HHUeOjAKZo&Kyn8c3*UMxZ%lgAiLYXFqT@$hvc)a?mXC9vd0Wmxp1|9)K+I+4I2O zB=IJ+t~=HA{@qJ16C={9JrVmaJD9=}WowsvPkP2L$Pm*seYDqoL<(VhCYz&MJ35gX z5&L_pWI!4ym!&s715Uze;Ky>mjh1KR-O<`n3C58IZDL zAw7&5s%k(3RF4{#dQ5?_Gr-g#?jjA70sVfW zsrM}!I*YnWL3`qxK7{JJOOs!>wn@W@rgtcSyO5?M>aF*be(TnG>J5(}OuNYxicQ;n?h@~D==BcmbyS+pjZj#t zUN1NWjyKuzQ6l42PwJwrGfi&MW10kCEcKVmz5N1aK5P&pl(3}65wgu69_6y=3bwRV ztLZrP4(q?@DgSc}+1BHdhA>N|YK^dot+$#g9tC&x4*_oG0B~?P1tLCDMPhcVSvrj1 zK5DE^fu!;8%i3k&4)X%rM+;rfU96ct?uOXX3&%fG-vdo7WzSp92O}PlPnV9~tiD&& zvNKJ`{;N(zc-q8_vXuenD|=1lE2llND2o9$YvJN7=#-6CeYOLw5*7#?mVO|s0VyZ6 z#NrFw((6L!G#A(nD}1AS3^fu^nHn+ePddxTfrm zZ+gsH_$~{2B}Ao^Tj21!=C@ftYGn0Mv)9dgQ%)n?|S!G z|E7xtHth1Vk^$SeOO|xPH-@?gtY1@(hc@q?MbfJ*j*rx%v#C(b`_!9}W!q0k>+&>xl2S~e68@vUcQV>vL@b1!0{#IZFnpHBz zyVHRwrWwq#z=bjfcg!;T!*`FSW2M(krM^oyT^OBoKLF5YybD_;3v_UwCE;qPb9p0ZCQ z91Y~m;P#2Kqf}J~@0Z`$GV2);&sjf|zYNO*!ss-vP=fJ)JGHy`YjY$~NyM*MBR?wf zYHPJnwLvAjiA{WPwXngizF+>vE=wq}e%oZ&5cLAJ3p%PU zn#rr&8cF3`Dnm%g$SD3`S)Z_n+VC0K6vQ-j?>wlDFsnf87+?|x-&8VK1Y<(PR7R=B zmJp6(LM_t>mA(#pZALY5&jPc)L&q05RhrjOcOI%b-Y;tvnbJI~l#AT~+_uFDk{3QQ zx7xxV-kX~|Ng9GVtagbE8zeV;T3}f}{ewfbZUj-c$e+K;PE+3rj6=2db7J(AKuJlA zom#LLdecrO51uCsSjI|BPoAT=8yL>neP!!4i?{Wld3Vn)T)}hgNyad9?zKPi-YKPG zusb0A6g*I82hp%i-=ni+L=FTQgywTN*iZ=(Ly4R0B`j_sSY4;CYP@q02{U+rStnD< zn14%@9r%4jv>%KsI*glM|2H7AE#34A3(&BB$fvjh{`qjO`!?C0!=WDembbogfk05| z6^CnkIHSU%@Wc*_u9DcR!V71&rD~YX9lpHdz2IMN@2kfcXh#OOh)V>j%0~H!UUmz+ zc}C$Q|3xEzHxTK>!k3ImZG6bx=K}RxQtTKz{FwjH6#^=BtX3qsqC-%|up~rQ>ND8W zQ1W-q3b#82&S%Jg=)NdFYw4dMRpc`;0zwYqeEzFT^=C*u^%*h(w{W7|C`(p8L*tVE zjNa5|U~ju{C!e9eLCWZFkSBLISuG02d`DF#V|BV6xRY_z<1RkMq=%g0%!hP{+NRnN zv_wHE0y+qcL$PAouaKU{n4P5%tTqC&cfDzpxQC`SA@0GANdO)sJXRLiNq{_T- z8+v%>Mz_ztnm4Ny@2+AYeSug=kBsI(3mnUi`s8PL^rR|kkCAEs3l&r>3~e7fq?E+0ANZq9d{xSvoI7gDzbrd{yt@wvlqy!cj%)PY;c}<|BXhmn0zEr)ONSO1c z`C+Z8R6F9X_iwpEx-BhZP^ZV@{adC(eXWiZy%HIsKH=zZnMc7C=8tRnl4Z7W0||~w z?$roKt^G>ig$|g~FtX#XVBaCpFW0jI&E*wH<=RW5^ok$RVnqy9S|ggeVqS)S^q^W$ zbA6az^6^(`_k7BdS!oBlD4J^jp}BqSPaC9t@4)uaP^1fP+r-%X@XZT7wz}sDx}ULx zg@ux1VPCu%O4|%=l2e_{7HT*rO5 zky*97PvT47H7dT~#$LJ7hPLvl{8nyJ#>2|V-Ei&QPG~!%*haPcjtb?aooFqFo??eZ zdYfEUVRtPOHO3ZkAZj-tv{V5Cu^xB!m+)p6mj~Dh6OTe;dHm#?Uz4=x`lGZ1Haq(YzWLP zdSz(XT8It>47^t0g`a1;Q4s8}qoRST+XabI*?p9M%#q6bmf8oDtN+6hwF#t%F^&bn zM_@sJ3;&QCsl?u?%dsn7Q~UQQfxt*cvX6aKywF!!cU7>>J*@Zf8}MVk5Wjw3Kv(*% zLrmt_#H<=(J|=G{S1sQq(I?~gMzdn)>UW7jxhNxwRZHg${rQRUo|-h|tjw|G{$z%C zV}TuCQGwPm*U-=b6W30aEwPLHS?0bo$Nj|Wcq_=m_HOsyrVi$Gtm!@+>K3f|>CLjf zy9H~y9jsA`87@`kmV0<$IiacWoF&+GP*BD#di@s%fK){VWx#;+qT?xwiz*N%y${x0 zBB~t0RV5KtthxEYxrK@*C;kpea^Ki$&6r{m**ozVSQG3t5*zrnDqDl^5OiA}L&WH| zjYPd<-$QU1xlK)*n{On(EGaXH67x?|EW9@urdX9E*6%RN>vsg(%=%46c^kp&t#F4i zr}D_Ouq{rsa8wZ5Y*ubrg>nRp3fsg}LAdLaxR-iOU4f2pe2e|UjOk`&w-w&az;{OM zul`h8A@G3Fc!Dk0P9EQ%3hZLrS5^sX9*Ex)^`J%+>N-`#Rp~-BZ4cH$p@q936--=q zGW!Qk7v+rxKwU0yH(`v2m%!cjmC7D(Gl+GpiceNZX@h@)BYpU%@kX2`_oac8Cts4r zyYOCP+kO@8>;RAMuJIo?32q)_xfiSs zf(fpqL9^*30tUy~!ZqCFL^wf;@kl?X3m5k}U2s%bFS}kX6(Zp!5@)HB+$I(0;(CE2 zM~)~{k6;@SkoAScnyKQE*Ci(7A5Y52 zbhkGhcb+srxb)8Zsa;uhn1x9}vXG0M+BK|hl&Q)q6TnlueDW^kop*mUK+lX&ul>yu zm)ke4T6a;DIi;!OHi2j_L2DYqwiOI3PJ^v4HZv!7yb?5&l zWI{$6y%UX^)~KmX+qkHWf(jedBrpj+LQ4yMJGjx%b@j_&wkA zJ>T;^-v{qrS8+3-2yB^OoGIU+Cf-amDeo9@@49~~%)_7{LH5b+5k_0r9u-ho>-Zdc zYJ?pBk_od??gt}e(DZoE zJ^}Y-dG$Q$a+coNw%LN+iF&k86-mTvZ8f^5Wr>BTo*tW6h~{ZDu@J@6!?Ane`zQFG zYK(fDxkr)h#}EMo>x&~XR9af&Ez-e{&=G~Ka60>$fZ3zHJ0}Dfa3q`EMXCjL(Sg1~ zj?f**;S1x;ts-i=o6@m<-yp~HrYw`TtInPWKeyKt@NZAT(xd*=g*6>TPekV<&j_ck zkNir+>b?8z=V7T;dNnjB$TWgX1@Bs-7UT<&kJkTczA*WaG!DsEXzBz0@7(O5KE@7~c)lW+57s=6ym1snNn3a+$AfS5QgZ zd-J<$5e2BQ_k&$*%xWOowtPqfJ>vPe82%`C zm?r<_V>S7uzusieAG4$EAJXJCgH48*m$*0Z&c_+$9@zZ90@$f)vcYPnNX4YoBArxB zWDm(Ms2P9!%{`LU4{DSc{Knr^gwU@dA8t}>@K<_-7}=iz{Xq5GIfoH47+Qi#uwMH8 zmylit{Fks3>rE_(5L{`uvuuDR>95b|$etGYWsg*0x;BFNo|)u~=%_7yQ*qq%@IL&+ zxcC9!#1wVAjgKL&9Jk*5fwt!BtK7()RXZNYBj?Y#s!@@`(EzujKx&7ALf z=)+liwEOK+7xii!bv-<;2$F=#1s2m>j)v$Z22_MO4h=h36}OMY!sh23Gj}d>H+R1o zF4(O14Lm93#qPdv!HY_Hh9{-$>wY_2pg(;Dgsf0b>+a-U7g~9gR5Wt>INHP_O?Ge9Gz@Z4w16BX68Fk(g|9hUJk17o zcjgi0%1kMBF}qe_tO_>B$9=$TZ>t%?Y{S2;5;qYD=K_9i0<{eGN5nbxnAt!VguQ=# z0V32GN!_Uw6RoK%(`&!uDXY$R%=?hdrIX*K;Kz^ylhavClJRnAwol_xtIqFP7|#Y_ zk0$O}OZ^1DDN3HSQ+|QnWo9#|j~HA`-r3LR#J%MzVG8q& zg*BNE=qALyxqL7TpZDW&+UrMS#`77blaG`6p|E~n9Q8wmGB3RzeG{>LNtj!K*1PU` z18D8{`v-Q*N46`T81N~|yKc`_^1YUySQlROdcHHEXK(MPYQsaqj?XUhep4OrFJ}a2 zq>uE!zKS0C_tiO$*ZmXlV5A9~VE1n~DXy)0iT=W)57l=&(EsH-8pYSe@d4;KN6>h= z^GHo8vVhx64VSO?#R9qrG=?v&ezc-#+zWD%#vPPwXBu|}4+uGJ%KLp~&^_?)JmX)v zi=W+jdFAJu$khI0q!!}1GLe=Vegs#XsTNmr2J{agLH9{l|D2 zpP5j~cjDePztXJ$eIbzNB6bvR1>m;jAJrJf)n9o?_EZ;0P(A~Xi*t#~NBE;(fc8UJeS@%OJe7mv;W8}iIRr$MUeu(p^Z9ko*KYyR zyv+*nrzPTi{#obi*PEp2>ztOiteVb~Szor(?5AffwhpG(*jfsxU{lln{vJC z{eRT^hV%8~ZQ-p}t7WioflYtITwu2jruP9F=kyKciuyKbX*#DrXJ78sOSC{StaXRs zo%XmcB04@NFSmI9C<&bAc0R!2WYE~O{U0r?kdW@e-Afv2Bo!gnE}86Z^vh76WOm7X z`aNEqAAyEV0}s>jnSA@lG1r%8`C6v)jGea{`)FHkrP;c!DjV z#k{F4CVJ-CkX%A%M&wwrZ+IY)QxwUcg)`hPNZ=&Uo}+Rvl4S7JLmRJA6+2VWl- z|F=CXmaPBVi}iS=m5vYI%dU!Ev;Y391*K($RWU6DiW5G)qd78>Ry1D+)!qE*V>ud|Vcz$qs@MNK*->PB!9s-hFE^7hUim=9+c~ zAKaNA7-OlKy0nU0^R6pdPn^d7ZOUF<(A0C$Wn+9vdRQD=p|s$h>pr~%_guO#sSobC zu%L~tAp17&rC-^*t>18l1PgT93j$0$@Jj3fN$HPklt}#nN$IJ?sun0~FVB8-i6HB) ziw~alIb}5#w-UeyxxatW!EHWQ1^9k_R>vkZ1UyAX`-WT&5cgy+fU2xyYruW_Y(vkJXF;RWl z$a?FTXj?kQt-7XqyMBP1+!XEN_9Sj5U}qy=reb%P(D92+==i(Tl7MsxZJ8Uyjz|(+s#V@! zemIcn`+@g-7guSi-BJ|Y?R^(dIiOx_X{yttG(N~>fE)~`J1bcWtR?VH1V@>c*xNRF z8-C}9rgHpK;rQ2kmMR(YO7Fs>)$_Z&Z_<=)!#nPeQq*7N-9!>2CG4y<$2Vagf6C;s!pou+;%hOv}?gbdL4ywteJH8$m# zklPR@gifKK-h_vB(WpY+DQ{`CcYELXHvwX$mo&c*dN=c{J;0*OwW9-+VV|`~^-<*3 zaPq0ify;>P|67_8&V;lR4TXh;PsN4RyS#!+P>Rvr`J4Z# zo1Wkb=A}_Vw`>d0Q&UabgK#s=xTG2JTXW;m;NP$WH!clX$9uZ)Xqd*rw;~n2U25M# z6>S?;iFe%cF1#Qll$dR^6H9^uAs_X z#B>)$xZf?IGi}hU*3+z|cC?D;v*bva57X4uc_F9gA0I~-Q={sAgl1!HE`b2 z$es4IGvkQuH0#WI)v4Tuy06o-4KWv<7S=jF8#7MN+Kf~3B5gQ5&+*jjl)U83*!G@t z`5LEk#_p?}e@6XG{}$#Gp$&CLr}J9SSHceW^~-}JlHJca(1HaT`819E1b^h^Jb%U? zd7D_2Ibo+~2cv$=jGj@SU`PEjqh2@%lyq7$BR4xI)#L^K4bA8oYnq{R2^kDMjsBfY zVdxv3*58<+_xM9^>2juR$c`SpZ0REIKb(&H6jRXlf7E)r9O(Sexl@PtFmXB4vt{Ac z^fI@9%k1pmp#?q~Lz zomu;XDs)>ds`49h`k?iWA2auz*~4&v=H2tN4|Km83*Q!FffC$7FLbE5e!8CMUvd2v zdMa5`-{$tD>n~+f=OXTbMb`Jym7Hpf-?LzS`SiryjIW>MFl2Pex)AOZl67HsVT8-J z2re?rRVF$b`N^+gY!*${MP0V)I)X};ChPEBQ#LDESLUuZ8q%gd{3oHIQG~Pb2D~_h za5#f=253XN!Fq$b1Se9`FhBUk0FDali6vK(tS`ZDp^-?JCF{#Xs&fw3gY%QvRWrz3 z%5wrIE%CIG*~4%Ext;ODN*Ip9`|T4S;GYrBAqcSWC?8wAmNJ%q5!8qqz?ylwn#*SR zHW>(6gI0-gdi3J-hj!H`J`Bx&%O;^HxFoh#5!8|Uuj9b5T}Qh)A#Q38lj-nk12+7K zlK#GNHD82miNq)x0ZbE=EXu(o)+OR8y_%IV0A zHa@xY<$342jl12o?pH$~$_Nm}4%c0q9D@K;fKce4V89GA>7X+C5|wg3>Z_NKa~qCS zD12D9aI*R!Md3JNU6~I2tSRILuGR!Asf6Uhiu197)xm^M_Iw<_BRC&h|7WM}2P>h} z?1Hx58@aFC!GiH_+Oj7TB;?&p!dGm<%CC{5R0%UkpcDJSJA$|t#R#O$oFHdUOUE#$ z6Ohdj560K4JB6mTrGY0W;`=Z~&P_0k-s3-(ydshwUQYYT`b&|p?ScNJ77QddWRg`+ zfFF78q=D2;1D60=qtyAVuqp9D;OmZHa=%5~afq*+HThDUnk*drWa7^%Wn#S;4_XI` z3q-FWCrt`p!_gieN)W&9W{&+W_P~7#JtD)5s6D%PX9WUL`{9cv_V7OVVK4JWiEB!o z$|qG>w#0Awz>(<)xs7oyLtQ<3%&G4@puA_9P)nDx9dms7e6RB@IfGlg7g(59r}rp5 z`}w-hIG3%>c|F#-?8%(hB7?tuH>ipSRmEj%a=xBwy1Rdk2UMYX=o`gJqGM=rdYIdE z%h0ALj@rUawi~Np4I05h1=ZwD#!Ki%H +9V^#6UPHZy%yl6`gmUkt?}%-!@V4-4 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�bFRL@w;NF}(6`{FvMTE|jJzS% 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


~ayDo`meWRrR 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 k}Mu$?YBbTGy4wREMwj8q?g8_aEwkB+2_7tIU2T zt}*-)b2+@>Zu|S-DcZ-$Lb`xPyvQhO#;d*U^K&8rLWs%+u@iR6iFM zIga=Oct|*YeEQ=ig-7k}<>*8JjK|~jwt3%@CwbyP8Gruc(QxaSlG4E$uYYhlEGe<- zA#Y%(wbS&RzXm2I%U2sebxZaKm0Y5Ep5>HKOevaLr2Ak|^Ri z9zf7iwJzBKZr`84?ophF=zq|yiRZ$%vA zIU3S`#C!1rQ27fP>C=9IUbT4x+_cw0SvM-iL{MD1-U~Tv>8S9ZK6%>Z-zjC$nYLnB zDd6i;9gZnbTnb?2xSA32M*5tWr@U<~jr@GnB$c>QKvGIN7`A*n#dzE=bkVQFeG*ikZg@D1Fbmg7De=7(;8Aa5lH@G{~7kfQ~Hc+ zvA&|IKv8v!214EO<3wQMpNzln{f^_-Y}#@T|2?iwJ) zZY=}KNaGE)ejqMXx`1|Pc1-81P(k_@Hf|{Hx^3kTiOo6ci-6siv9^F-y$%()MdU+> zhT3!Wmydk;Y;Q+dNUW*0%n_kbKxL*rFL=NvRSpiJs-e9`mB8LSk;YN=fjD)W>7q}B zDU;^iNZ2@@M8B!D3v{ZG@>T_GJH9N6RA||@iM+JQK{>wps;zYFB=0gjpzDC=*PC1l@jcbM50 zIdl)kEkn%>mSou4>?}7wMLhflp`?|MHskBFj-UVz6#$-?Mu|ei^DZ1n= zGkM{l(qUxMvu(26+=N6Itu|O-t=WLWle@){ka#pI5|WHD6AvO+CKN9H1!}1@FN5$4 z*a`oE&2Q`Xr0T7DTemP_!Kk;6t&aY{DFSBHSVPti#LpCQ3?*EoiaUxK=}Pmh2(^DK zMq6eI;=BDos44uZ!=1#GO@Q`{AGF_l?Nwvx&Fl|LZvSmc(N_4viN1zsObiYE>-FEdspU@qv#L-)JOk z&pI^f&t3J)f~ig97;Am7c4!gh{}q|!4GZp;VmVd7M1;WVe8V`pOKsxlI1-^WpGusW z_?)mnaEk}#Y|1%V&IJL?QcUB86(o@gPqOco2EU6_@F;P@89pGrRsAN#ou4g=jDhjC zK!lbHAz2|B_vC!BBC0|-HKJQaxmWkI`7rP+XT}2dC%M+c%FBQLK<9vd9a3E2@=1F; zCShIZx5|&)D^mImy-z1=JsCbHI+zNqoD#dl`X*NX5#3K>YE-BCxC8!M_7DoJU0a_@ zyQ2w9Ovn?>tLBDK(ONCZDI&LQNj<2gY}f}pUyK<}@E?gR@g|Tbp8vFrgz}9^HV1BK zpn$MSUT1)(O*>wcO5`fl??uAxvPc!~1lO&!6KD&XXqLBjr*JJ$tyK+Fk?`eooZh$3 z?Z%@W<}V6#-q`qOXWmy#e)PTQaB|}n3sLgL_x5oO`3wyO%~bQYcY30beR@5<;)0&L zuJNe`8i+5!brV>&=pk;U$^#MCNm_Q^J4+^HP<$^8B^V zZO;9NhP>};Rj=AJjf$8L(g36o_UNQP^fvDh3XEY+OvaytZ~|RYS5IjZc)52HMGdn& zqre_0-;^E0W~@FUT14@oRVWhn|-f4e*-1PjtSfz3={T07%P+U z{V_8T!5B_y5iEr;qYYS7ClRaq+*+P(#W98}K zn)es?;{AruA6Rrkiac}8R#jAJNt1>8X7@55oXka7%Y&W)dQ+4tH#qK|cf1}G7wcYPYnCXfeeC7WsIg@n^CO;a%u z8}{M#?3q!%C|E*s@^6ztB*Uwne{%<2yk&sGXa(e8biVinsk&3*wpQW`0LbEao{_Ks+_zh8J_>jf|3sD}8YKj<4dd^2!Mp68Yy~LT z6ghj)S^wmEohgN!dIvlvc`#6YRIZwl8pc6@pIEjhnN%@w%*1+a<+XRnRf0>pN*q_x z%IeY<-G8O5U#+^KU;k#^4K;CY%QUd|B*cKc1wSAf&3*jx1Mqdqx9Koo-)~hj-=)dK za%$EXmM#Q*eubYrrDqNN;8=g?qvfuri|Z3lkHit%{oh|lN99l4D*cO+@Gt0(k9&`i zkaxGN^{U7EH$w5eN@uF+!KeqQ$aCNGF=bt0w4p22UEq?Rcn4{1byG$Ze-}>`C|>4q zdP$W*vQU5I4`k!qO|S#&>*4^Ro;m*jn=_4YSVC$ikgbZo!vTeSdmSd9=^RlE?j4&n zB@N7Kq8-Jh7d{evI=3rMlzC>lweE*T2b_=MjG^jVG;{59b6+U-1oG6OExJ5dc^euO z(!?@}-u&3e8BSA%+rFjB0tE+d)}2sDv59oI(&Yg!uN4*vvOiVmeK3=@2&Fg`(AjD z+;V8fB|z9x79Uu_G8Q_C-3#ZBj)FU7tD^Q#->hbGMywQa0c!vRxQKeM6-eF!6C&Z< zWtfg8?*3ksDLSfIJce)oMk5tEx!`Ud3ZNzl#*O2L*2}zQDwe%Ng>pgWXyY<8(Ech* zDz`}K9OsRGejd3ud;L=AeOS&~BIk!o2GILG`X;h3!(yEKi!Tm%Nh8xzhXb^mJFB~5 z{~U(Ob7dK?{<)@UxVh$D`I|29EI-9OFM3t_6|gXyIH{pveK{h(INKLg0wr?&+pL|p4LLnk_kLo++nNtK=f|7_iTvPpS{vVi~V z`GA$9`lS+{IQtr@YV`ypF*(}`@=Fo|cYrcro&vlr@qFKM65R?cfRnjRo}z8^vQ+lmC6B3{5gG8U26ze#r54~s_DS_C2I z@*e06CO*al#nf97P4MzDEjt)kmXZK> z3*Q8!MAA;$7w1}F*tq{Jqq=&48b$EoT~55|EV?U!{+Q{&eZD^vA6+Put!~O}zW-1< zzHSU-u=ezc8%B_@hH_Mj@%#a|h*yq^D<%LFes(MJey!f6}?pLh5q!5IO&drLdGq@XdNmbz4 z&-J`RMQ%$SfsME7du$&lrC3jJ$$LEckLbdEUmSj{vgS1Mzh! z1s17e_!%>$tvZRSTP(SBgGFn2(f7oO_0IZCPI;p!8HjiBsqOF3ZyLyns-4C(jXk?P_O`F;R$afzSnrP% z5EqwAaf_1wYlIPEQOC?5{}p4I^(*!bp_RXiS;p9u-F$@Ept&Ow0D_Fd()FMy0U5|8 zcUor?%H`qYHGyC-Bvkqr4GQ-#qGP?C@^AezKV*!|A=DpMo^KDU-$FO4F1;V^Q87s> zRVS5(AXFdM(ej!pfl(V+;LodCi(8yBkAlO5W}moR0Ejcf;hYGD&eI3 zmtw8Vflw(3>P2gU3 zTr}cMAQ{8+aj!vZn_=BDgW7XZNGEw+|ItzPZPmOnoB`8i;!{Pyddk)B!0!+au`Wzu zUDQ%1I40f1`o;^^V5@Ej^;werkInNJNRIHLHeXx4YlDWYW5x2x1IO9y}z+)at+ z8P19s9v8-CYme;y=VsFf`E*QDXY!^XPnhQUd(lwGsyv@> zquDp~hD^PGF^}p=_nc_?6*{Hpw3(d#6o{J=|5=OK`|r<_=n>*L5@0U&4$B0}v+29TPLt zEQ^d2>oF*Ou$6GmH=U_K&ateAK|cgn`AXz`|G$Lc@GkM4gZHUeHo3L0x=q~>TScr>e#Pu)^Y^;dZ6G*uB zDxBV`M?+y4UsHM`xcz`!6thw=kD>Vjc;$2E+dujt#ngt9GDTBQ{Fh*0U5PQ>b9Tv&Rrnxo=?7pjOaJ|DwlIeP^kvUr(LZ1To$6{hs53(4O;gLtY){}0K! zEbrkygp?(hGZ~<5MHh2_IN9AF-v?5oL58gDN{6DRW3V}=h+AQA3V7>KECXDS6)?@` z$|dCf%wkwM{_Z+i^UGxI8MC)hV@;_BKNBC`MDY>>*xb*h7sV)He{eUK)5so&bzsg9 zV8-zNo!TgiQ;!Zja`D`OfAgtFRtl=8nW37&>F9YsZLJ`343t=ns zp=V)|J+JSRjwe=)gWw3jUP{VGtKAb~mT8r0lJenJ65``t5WkZLvMqy4W2E2)51fH% z=*mZA5hXu+>Y^^4sP!|+%m6Jxi9eDzA*J*oTA97-E~#B1>GQRlduM%642JD3GbpU@FcrRBrg`gu(QHI&y%cmHUhN}1~aFi4NI<;^PY%3 zmlI@fBa{aKsbE#06U83;}_HKZh#pAsp3n={6j8xSC|D$`Ue!0b3vzDTV ztQo(@?a$6OfU?Fz0JWL5L^8=pMI4Se3U|Aao@ta`HeS)3rMNd*c@B%{B*x5x)XwCG zLV__SGJ^8gn>yrLaGMe!!7(NfS-|!a`FJ`~kbU+X^^vhaxVjnVVf)y=g1yHPp&kws z7$-h#V{M$=asvrD0Gb?Itt7LmD`g$(uod=*S4b}2tYOT%A;;`b)W576`=q(r_EXH7 zti6J`93{VrJByXL&#@U4ZudqJ*cUz()y;Um$w2(~#N2S(yK)he z#b94aG|@fmqfc{Qcv}$2u+<>xr3THe zYw9gi3WaM!*dT&ks~Fz^YWnKm?C1v2@X_?^rwp}{Fw??tt76ba-@M&?H>5FUO`eP| z*2XSy53V%>O}KofmUh|$`w5FJ9n8UcAH$2Z$JUSQr4q;0j{^~CQKXYh75AIV z8WJ-jI;EiO-CvkyvVzlSv$9^yr&~Q{8#P7EZ5VxSz`>HidWClK*|KfQU$OT@5lD@Sx5n4 z(m6BtSNK83>{l(TiVH(0E%JP9e9@_DEL@|pRhl~o!$L4NXL)z_dY0M;@Nfd zNU7J~_u3{E0}p-~Sn@&XzNw?p$e!fQ{XN6EqGvCH^#k#IKlT|Np#F!VF!rp!CB5&0 zCtjTW=b}A^BXUP4fh)=#Q7QhASU)rs0fGV+pg>oJrkA0wQ;Fh=ls6&SAK<}$PrPvX z7#}DTnD<>b(6b^RpkL%(7Isr(zxM{T{y9EI7gt~tbv27ZthJ<{ummVUpKLCKg55$5 zko}Vs@pWLGM1sF@9TlN0&&!FA{>@A}|4jPl8cloZSIx+RG;%P7RAiU<$MfK>tEohR zME{!*R$`~s1!Kvh7!HjD?=0@e2woBnztx=px@|h0eY+Wd$pMeeg}vnow3%;A0dG4s zdPjvmgS{#Cx=3@o0jf;m{(dtp+IcSrJTq(I)2$pit~jQn7;~qcP7&D8CM4X@zzg?` z;c7sJNB~GCS4~GTH!an$gXZ=PWK?^l-EwWqESQq3l04CDJkXLcK}5*Z*L@P4HP9>e z-n?fWlQIi;Q=TW@C7xWrLoZ@rFW}$PVez12j1oW$7YN6qGawQl9?mz5pugZF?U93bSOSr~e^Z1cuQW@j< z>4#G05rmg^lB7}Wt6Q2GFiIwvi`T@m7bhB)GfX@+jg5=9JiD~Ao_>Qf{2}B#s`}(# zD?@3Q1?Li5g`T(A9_C}duGbLILqOMw8@gE`ew{xXjf4!^0v|5oN%z>sW6Cp5=>#`| zDk@Mh@IpW;s?z%3#uKAOBHOr#u8DQ%k&9`Ed$ep!qD>~)(}D2snmH0}?^pdQbx@Z| zvOjkc2U%vX@S=uM9w=gyvxTH;lL@Is-P}C+;qJ(l3K`E64@AofpF}TC2(X$mib4Q@ z#3X7n{^Et`$%;7ZtoyXnS7)Het!_Jk0ar3muks!+H%NoN%*h;xh($AfsW-n(LHRDJ z2mhIjg%p)s0Rx>c>x8HvPREVN-2p@`U)t&B(X|z(NWe9yCh|>NRjU+m6Gr1)PF$#} z(#2-iB$)2mzby2?&fzrVW-`PvM+YLI>JXN{zYKFhmz5a_I4-BQkW^xxy*H=dgjDG5 zx+iw!iAa9({^55WL-HNHW<^@-S7{lyy}-(`W!4}d!jIhw*w9U2WSX(TyT_dWMfa-; zZvDhGrqNg(WK~~0}(00W8Hy=l2_gN7M&Ke$Z-Y~vwEA4a(HQIX}D!#*5 z99j5{Ikyhjy%$6I>oV3W#t7fYuZAit?+~lzRna5Yo~U?%RC+Rj$yv`_i~tP;3zPCc zGAHsAZ=OuBlC&&sZpH`qqA49yt>-Ab@uNsYRyK{i2M{3%`*;=uD9;D1d=*{a(@rXW zpS}}qAODv7UcP`tpL)#+DJTUoRJUtTvX%EHW=|5Z>jf`1{7l^ZZR+w9C|_A2Xi8QP zvmQ9%)=3>e`otD)3fEW{1{;ab5-!7y>Q}+M)+x2qo59QQv>;WbyhCR)IEYs_QxJq< z1?*jv7oUB<&lUi;{0XtKW{X3mZgoA}j89V|kQagpzt$h?MJ3_mThl+l9`fVbI@eU} zR;MpEwuqt+a`#+p#7hufKPJ8k#m(SpV7T6LqWJ z*^qyP8KAmRZXH3*hLMd&CZgB)wGV&!>U_lOw~T742gQceZNE3*Y3zLOS)+ZM{`R<& z$t+ro{FSR-Wmzz^0J#-x-~>v1(`SD)TOky+hq4fVRWHhI=p~f`7%6F@Z@K1Ctpl9Q zfJ2g95v5OMl)q~h#h6^VxqDuy5j1e{@J%4d^h&Oh7BR9Po38s<^9)G#N%S%nT3NNW z2vtxb40}`D(u+cu@1Fl+<5)EaI>MDcnRA45WXpA$^s9@`Fy2+Lly)+A>F4e&pf7@K zOW&JCCrE-f&tR1N1W7Jj5E9Zq0sV#xM?zj8Mt5A5w7DW*w$=Pgur>x8txvQt&qk!` z-QS@qg<%4_jy)XJ3yXf+a4Pt37*^8KY&jJHWGkAyI%OC{ruUwZTO4G;x&ywPX{-qV zm6bS%!=JWWt;w946gz2tl>r=~_)XHt>@drYVdZrKIcxu$A&H@iUwf4CTj?ukC;xdD zdT`keI#wXqWoOMe+}EtUP2`s{%~;_}6{xfaj(VN}z_!~iyH?~3B&)-|fFrtz79~p2 z6xEEze9M$E$E{s_K+nbVja|SDoWqT71TmJ8zwNSy31?USqkVHiJN!pnnY8@Y=xx=R zvoKz=`uE6jZ!d6C!gaKpQh=&ylSM+KR`EeGZrkceIfe4wRqGpR|7~kj_R5hN=3i?>7}vwWC1nKy(gUvUC+F z=O^ID*J(}xrRT2iIQL_hEpXSWVoF@Dm2I38hk_31Nh2%11r@GXzQ(poP&IVH9};YI z%1?aQqnHWAVz3-WFb<98)FwCWW6w*%?3}!yJTnUF+Wh`o%%Q4^}I_!ehTv#`<-ASalaq5vKxw zeyI#(o5%9 zCc3B%hkXRAIyA(Unz5102~6BDuDB5!2%QS#n}HgP73>?cRO7w&C`Ha`zxo|4i58rj zWiQGVypj{G$ru=$z{E_=bH^1JSJ=$SguJKx3n6FLdBJc`$5Pp7lhjH`un{36D)64K~;rH9Hg* zo-lHMr5qn0m@c$h5E97M;EQYItmS!wLf4y3m*);m-9cq66~u?{uGtVC^EmTuRhn^P zPlbuPdu#(-`ICF&NtUTf@(2AIj%JMB=5=~C^Mv|uEwx&gBlt~V0j%nPElAar3kzAT zpMu+f2P~QLpr;eaM?-Q+6(l6g5`_i28EK%|M109CPcMGl*;E)$ZpK$P(8!$f#i`QQ z+L{gfQ^@llL^BT~ft5}40??ijlZhiDLt{N7;di)4&~N#$h<#B=n5YjdI*&2&Wo7tVsLV)s1EQvet%p? zOS3hM7Y&XaR}6&^m3Gagd$4MD1`${wm`tydYXtt2ycOVknImH7{IW>(lW)z}e%pMy zA7w!2JB*)@a@2-y-(LVgrySYO=sXNz;v~w85-LLyj*t?)w=%CRhw*?ae^3HqN2c&U z2zJ2wi%OdqWAvMK_z>4t-O2@j&bMP&QH_?cbv-(XyA z)^pp(7!z+UUX;E_bbnqkxO0CfHi5ovMxXxSjwlnFyMQxnUC46ApVFpf6TdNmyN#Jf z1nwA#gyMyJ|DrHvf0v_Q{ohz!(oIe}a6DSCuS&XIVSolwUMEy+76SkV+wqJS6VPD5 zwOUnG{f!G)T8S_N3_7qL+9?TukBbdu(uo|iU@7=6gyw<}&jTQ=>b_y)KZ3a5{>z?PR07Zd_WoeAw>|CB)j!GI#UV5nl?$ff68o|r-$I@x% zRwghq$Yqx5sYGF~k_8yYogeu~DzM~cIe*ubC`id+N;jh|F_9Ls{B1FB0;KKka#T^t zw}6-7z(F%28SeZQ|Ld`=fcx9;v4nbKF&vMFbs$M*HDGl0pW6m79`B{Z@ZIn(U`FCW zF+4oFV@Exykj#iSY_N+{%iB8&j=YLK+;o_vwGk7qZZFW~sA~WugNYjz7M>n8@>oFE zfe73sf65Gs!qLWX0bq90Me3xNDFFvG@N|qPzq;y6+fp-T=@>4#bNj2(-B0#cXkQKy zR{CaUR?d9PJ0%+7oxuHTLRL!nwM%-mVvs>|8}&gbQ7NmzCMBe}4gZF)QL2qYzdslP zUe)N+NpR!Mke;bQ`0Cq0RtE#Mbt$AOo$bnHzph>#4%Dl!TNO~vSCPSEb$v8C|K3L6 z-Ld~H;96dH>UB7XPs~gDfMGL{56|3hF$R!BeZT*|=+?QU7DM1lc+?<Ot~$9|U0+yQi%$xH0%(G*Ok>vv$Ysd6E5T zEZQ~ToTizGR4wx`6#8gww3W$sDO;4nCenawTDBcO+DF@qoYT-mxt~^3VEnJ7ks;LV zH*#$Ly=yu8tDsp~|7%T(TxKz6aFe3lZ-1Jba2+ajCf35pM&V+Tr_8aK&XJV0ra75Jowl4miTskzSBgJR1>c zCI5tp-oFO2c<&5M>=H>I#ZDPX=E`k~ACKo2I_5O??%9sUkxD%AyEl0X%&3^KkZswu zNi1X5d9d9dnhaltisRJwjNx%&CzIjX6_nk(3}EG?yAz)^*0tL-9{<;3`H`>{Iqxni zT~_?WFJqIc6f8*e@wlIW%ajgQWWQV$vOg>m%%Nw?d+=+PfJB58JP7h?GNt~|z@^Fe z7L@;n;ac5x0HgBdvWm7*0{Kq9sZ?V7$dVwQ8G#(52=oi9RUK2NCe(RG#-B6K0E^`> zee#CjwjTJRCyiG1U$Zc22~Tqml&qaz023~sbiiGfKedu!mh+ba6wo&;35)}={OC1@ z$`Pac2i{% z!D8m|thycuF&;h^xcW9;`h{fT*@-|H%WJifCyju&FVUlC)*Xs)SR5CnqIh@@1f1ZD z&sV<@(_KmcAeDTZ=$ao&qo+GjaAV5x`R$i6?5i)k@Ivxfzv;-OafGtTFB+lLf}m`r zzyUX&vOdN*AfjDxpZgbc0K_vzkk8@x7!sg>69L#sVy&epP^eU^k8{FZzT~ z%sl+Za8{aB1@2@nK?pYJ(d}ApwtR_#>6unAXEo)$k+&N;ZhdfHwfvh_gtC@;5%hXi zYb6g9yY-JwX%|c;(C1dMs)NBs;5I+J`W?m^$L`3``^SypONXKqGcirGPHjL*=Hogp zYij@@udFywlYO@JAppbAb2@4s94F=cL%b1jK;h@6z0*rPA7ecw&cEk)Eb!9j!ZIl= zL=`!aQ2!5ka3z=nptBAKQja>|uWodD`IA4eV^KQbdCs%z`W{AG|BHe(aKXvU3kfbC z53$vuVl_?W;_R;{);<84fO(#4ZAGW`h^MmtjCw&@IY9qHZx}c?$gN*?{HAodslD%DU2`c`2$G!)Naj@en5gHQ1_638F*KE z=aY6-aKymI3ts93%8a?TgQSnwm8}AfaG)}P|59MRUz3crWdiF)w3tqyW0y2@Jj~gB zML@2&gXVOI!;7h$#wimSFp3;uvyCpiVp#qyJsP35a4#LFf(f>3uYpqF(btSOTFAPu zax!;pGO2Vajck7qW^yFdhoTn_V0vEC`qn#l2uuDwWtX-O{PIvMox#-Cj{X z?X3r}+PY1Cg9-ee)|XK!JKXn3SVXKwIP%>Mh9DAuXK29?gb zKl^0$l6!BfmB0+if+NY&su_<7tP{h=UORqj$pft5LQ(fp=*fEb;toaby$-r0^M5S} zJmy#_P#AhZs`LUKeBqY3Jg`3N=5I=BQG1@#RQ37%J2@2tq=Ed|=+HE=dRIIv& zeWEocqrP@P!>$0J;^ZP)tEF9PojmdGuW)P^aq2lqtvqe|0ut^i}KlEHseR-dqNsf$j#jBZQTb_Qgfz;M1daz3K!}rD0F(zvxRy!X&6Lu{D z;(^M?+))7*eBkPFECXDp*I=g?$|0O;YOZbhw|@civ>pUGV{AdQF>c3y;p$ANxBkzv z7N9B$jKUt)`a_ZogD-#=P8KW zn3Q4G^}WIH?0u4ufeNh}{J1JA zyL)5H=Zg(hGQP#2`G_@kGH9n6mI=g#;4xJ-zBxLzQH1ylkkHaGJfEJqYP+&-)6z&e z@>IIJQQsJzk$X9@$N$!fsDKcTb~LN$%-S5;Ax_-sWPnV?d~R>HwH+*Obr>H6islY? zO)!5n7p9U+s%~{mCHOM-!rrUx_o%K>Jaq?Ufiyfe(>NPW5CUhFK>m@EDV~DR-Yqp% zR3Hd|ww(<`@4hRr^o)oc0*c{+0!12h$0ywr60HN;X|susY&WlKB8ew+)(>r$!V!Hy z3WRF8nN;>3%w{6;A-Piz9PkOx5K6uO5UDDAEH3fDM?Cq z9lp9>?E_qMbr$BYfu>PeHCu~DCj~M#h)d6+&|A_KEAZ7k7xS@GW#z}!G z@=6tx&-!%|tAEHsQ@-2rSYp`lRUS|W0Oqi4fD1kRYP~=Z(?RLxrHGwF(?IV$YMD&{ z6J5^*>TW>#cl~RX>VuJ|aYWXtA(=)Y!R-%-)P3FY08Hud&7WZLpnWVOmaeY2gA!ac zd=)(Z*|X)9mRi{8JS66ZEhiQ3eXLpN_zn41KO)}+0uCTSRCU)FSOh~YEx{KbOGJ-d z4<|X`vsXjEL0ZK8n>|PBi{HGx9m;!!Pv;>?icY~1!s111LMtMHWv+BLo))S3O( zSv4DTNiW+^dZk?*?Z6HjjGKT*9rXR8Gc##m?tr`CXzI9k0U!Cg(s5Am(^ zQi-MdUs0d5RhRB7iEbvAJ`4eL0%H`kE-WnK4RJCP$jQfyp%UA!Yb7%o#a^T;4prV^ zqy!u0%XyaZb-6!bNxg$5A0*Txf3zZ0s+l=REyo5%tcI{`=|z5jlmC6aB3@JnOs`#E z8Lf#bCiY-RifdIM(+{ACq|Zc?Df{PYKB&>2i`q!qHxN(QFXr`61%4#a-J1c1t`u)6 zA-&P4jlolK#Nk$P$aQo<4g_Bo9I;36Cl7GWO&E840Af!-3x41i3!m>xks8|7eqjAQ zzU*Ej%1T*44i_$o?dQklL1wjw?3G-ubo`xJ_HePsv>u4Uv|gDn<$uz*8iE-!an=5Lyf4+joJuA2{Et zeCfur<#VVf)~({iE?Na@b&vUN+%}i$Z+$jt37;~lqrc9KFO`LA0JT?1;R=OTi*Zzp zLS*}a=fG@fmI9_F#Wj=3sjLI$dsrn9Xy$ys%#f~Kz->R2!z#MS$HcL-^*6<-A^R-$ zL;1(A*nD8cZdMa5sMVY$z0~ad)qzkQE9U_wJXFGEM1#XN?if}_M}d*@IoTbZ#4Es4 z8)hwqy4eY}eZ1Qn@?nYTA)1c^m zEjL`w6t0a_cUjbNshL7m&}uP`K%e_|GQwenuiFy&pWqu8T0{A}`oE3-1RF@qa`f)H z>y!_#JXC7*E`JX#d6`(J55QlmMU`B>$F^6EAN%Yt=bJM7Bpmqj$Vj_dr4_B&;CNEum4!HXCs6?qvq^cK2kl4y% z9!i^vwxqHg2QC#HCsi9xjw!#>a11e5br=i=Q(EaBx*eNSiMI|z z+>KCCua6m(FN`x!)wCgf478$Y6)j17tJO!v<|ottUrM2JH8_&Y!94fup3uV6k@tk- zpW9V;PaVKvg8h_YK3^TQ1#Hwr+D&p(eX+PT_L+o~B7P_JK0OGdN~FD%ZZ7Q*eXW}Icu3VRg+mzq=OGF^_< zP32}1&IQ}Lfq1b~(=pAiQgC=h+-z<-w#Kk}c=kTc?VdmMTNZleeJE%g3}*~bi63R5 z0hT~<)&74Tb$C6xG4&!mCg(fV8c?7_&=Z#5*x5JwYk^d?EHJVChx&tj#qJ(z1l%16 zx4MCovl>jnEo=a9YLLw=yih>@p$2eGz5<7M;>k*sX7=mc`8HB9%{6=eG8;Dq69Z?u46=ooJisHCY&0s9VDR^5BI{}J5l~-bB|C7A?%57Wy zu#8OF%q5%Tm1Zxu>>~DXOg!--lFGg;Fw8b|F+ln|Tmm#3LW#Z^Z^Ks<8@OS}Vo*W( zVz)NG-H}R+m;tlZesQN4)>-8N?@jm?UJjz5SW%C`!psj(5TxeWo+%DAoZMLp8HuI zfu)Dn`Gp+FNpb^fJQ$_W^@#vMA9(rHYanmE_4uy%TELrIKu2T2!CSg(4Dw-)V=0KO z@Ux$%jw#0tcmHjBWu;rjS2WNv*QyG@w%=&tpQkFU?rR!xZ?Sy^h5sJojRS-rD(=my zG)IFHthX`))2>1M-Jrvj3rQMYKr0G7UAQ?fsEMPYwrPttS$;9%?OAve*oC62+HA50 zHD-`NRs&}7IT)X|4$O~T{5$*z&u%-O{uEUFw@sBYPjOn0qc_q&CMtgXNUGie0w%na zm56JW*=OL6ehq{}q4(EGZn0t6d#mq*783^YK#NG}Vvux>c@H%Af0%mjs3z0x{o4vS zbSa@DU_prlM4B|ES`btmjYEk96daY_OQKRG6tN&m6Hw6+g$Pm<5?UxCO&z33Xc8Et z1dsqJ&%5LKeb;*bI_u0*f$%){z4x`R>$Bm)ja8t*S>a9|>A048<*A+W>Wo^r`MSvI zb`-tt0PPX}eU?$;oA`EAtqzvbng>7sU@348ey)I|>VNZAZ#$~T5&lr&8#}+0esN?M3N?0Eq##g=>$aWKv>#KAB>OI)M-(=W?{0;Jo^9 z^Ehoi8W1DgwKNX^M5uzIfk$ogeA*H(g*UEaUG=FP#zxm;}s6-eTUUjc4jYQTm;= z@%pzuGEt#N3aUlq=Qe4?)CuK+o)d?{h&?OWWbdm-OftjYNJ%w0z5CCp`gw#l7d+oz z&iqA^(Yz&ja_YJkYM9}NEr$m5YyHUffnB6|z+$|4KCEW4S{jC6OL7yoY4hJlnA@?d z0^bN}BX|H(@ytWT4zjj_6Y?*V5#w74_eJ#~Z;M`Sy-P_=<0>l2QAbfvE3hxLS;>_O zCa3^qF@nYRkmaZ53BMFus_Uea!?ZLf4<`R%kgFr?pB;CnSQy(>cvjov!nIz5NJsI8 z$kyP55a*K~S40QD9f62Whi(@)JK~Q$Np1fJjOI@}8VG#&DL&6I+t#Wv0cI!jBsYd@N-AXWWqqHAw z#p^qM>Jgs($+q}x7Nr@J;%zH}*t@)FYE4Plg{(_Hf@t!+X$9Jp@Cnqs@M17&-H)Hf z`*1x2KFPCL*HkHkSD?+mUfaBhHjv!ZYNFEP*pDR`J$`16N*UwwA!%nXA&>uuOFOw0 z8EbtqaMQ~cTWdT(n;bZ&nbMtbRSIoPl{OP{=6D1p!+CW&fvtHS`H2i{9ADm@3t@#Z zwgsR{_fM(2{#&v<)!^%oFJ+mZCiHa_UHZ)-{PTzVymtjM*p1A-~AYI*oIow}R%&^9MBWs5; zv?P_<9{xlYp=MeTveWUnqXJCarN~G03{CHnpHCmm%IOc<6Nh!QTZ4r)?nK#ZJ5M!5 zNF|8GsO1y*5IQY9lK-14Vtote4uz>{<6v-mx(mON8;z~}n zT+-X1nvVD5oA)`M5BRWr^^fZn?chD-5JthE96_@!w;rvrB<`!SK)a1UCR-VBlfNrK zIY-a)+uPcmvCq(4P8=86Cy8$&hwaxW3?_Ynh~lZgRPJZ=LxTKvT}6w+M+{e#my+b)EX<0YN!`{0N&f=zR3@YQ=G0&K;FVBuG!A^&ZFm;g zNUsq#?_^%Tjc1EBVyR*$Kpf!i&fMU5Rc22M`O+GNK}%}#Ol0i z)7XDy?;_cuoeD#CVls8ZZqG{?kqOt6VWhkPjDcx6O#INjrU2oA#^Q4trU_y6v8z4( z1GM@S{K^k-wbgS6RH8HXZ%y*(V1AF55jk-38@wsscSmBW3wjj!B6GA06H0}$r;00s z+%fD+TOSK!<&`1G$smq?feC!s7yru6I(|(u1tgQj*0IjIP;kI$2Ts zd$oPxA8D77BpcQ8Ix{cOGxj;+Ce9zVAt3_Yd`Vb#7S9Z&kr*o5X~(9G@&rrf))K%` z`DySUv?UYd-(%dlO9iiHb;F?rdaZak_B;yjEZap$VR_oHZkhD8xq3vf}Gd?yo|5S)YV_WVvdaOA?QrzlPr#6^Y{yzFI zY2Fxsm6GP|ve!%rt@D;1y_(*w^?`pC?4b}qCPyL-CZ<6}d#!4h_;W@!m~{Ay^+v@H zX;?~X$8nm_g1u6$L^(MKJl!HiLr?=7-G+xU=q`S@AJA3(t{X4o*wnjv|3%?Qu%vFgV1DW~3*-#8iIX zZ~#U*b6YTa_fzoM>l_=R(p%u8mCEjO6#eA0EQ>j~LOxwkth9INgFW%Ay4ap|N&ipr z5?kabz3}V*Y1#tR={>Ozvw&-+#&2Vu1mqlD+`CS@7X4nM$mXi$zLi-TDR~xOIusQ# zJw*-!!iapul%5xOr&-3+pz?Lfxx)K)iDaI(dE(qG{z>)<=1{qHgd}@3mc=8oL{>t7 zkhmOk1Go)UUv&GVYy(~EAb3yowNNB6vXUDvAzeon!$JRywn*7d3rSf`w|4D*-i@uL z%j4NP=I~bMZVQX}E~_nx#%hy&Ad{E8qTU+)-}W2(M~dRsg>i#j)Eii8a>r$BvUTJT zh8o)TO%}s;Wm|B-uM4gjF?o39YU^*m1B2psJc(QBH)?tUHLP|GfZCqEXR@0ms-0A% zN^|FD56h>cT{Pe?3zZ5Iy&6-k;Y*f3&DLLo$Iz0l1YG6ex|egPjyGs zvRTdgZ9EHx_NtiS*g$PPbfhbnmE1ML3^8ag>-NKY)4jwZ6TDA-fmP8s0@x?r;(~ zn|F054kn?Dc;2~v=bc8XhjtH3FeRspX16MM0q@Fg%MJ?PqstX9S9OG6#C-Eb#KgFB zf3H@#9l3+`r~+FaKhgjSZ^bVWS|QZ!u~p$kcs>8gKUP)=vsL5%r?+Lz)(0My9YZ&PIihPS-waF~9?SysDW?ztkam}jjRHq@ zUL1e~Er1!%3x}SPdD(X@4ZUI{t2uQG-=1p>+AOoMcYlH@UV$p@v<6Rm=~dLm4+o<+ zW99=V>aewNlHw)@=f9{!abD-CulW-2g_~h?z{YuvFJr5|VPBea)IFRLcd5wYoik9T zP$DcXsD`m15F!gnau!{VvX1m^_(GetemNzBMY+gaQ{%$E0=1r(qk1dxyEk31^0@P0 zX(2IrFEu9T3UuzHos%1+255W2*6`<*`mE# zjBiTOVJYjhQEu!ixBe_#-1*85 z?V45Wq(J{;7@%zDT5ep~%JZ;C;N02Ud2zhKJzrVr7;%22nahB=>HFm7-i-ZPAg&3- zNIu}HL;|kR?O`gG!si?5jtLQv@jwdk5SS6Y!3RFUcnEa}aV&Rjj}M1zTX@-Q&n;K+ z5@dC|b7kAjmvsFiEOlsV=q?~L4ZGlN=Kl_Vbvk$pqbNYNaIDdGB z;|@wkKOA}W^@@;DU-tgSE&EUH{?n}|*3!Jb{ZrfY7mwCqXGXx|VeE30X~F%$m+nRP zr`Nd6xn5hyr5|oOtS;VBn;!B%zH?f>)sLQyVuT%8Ut7_xRb_F`ybvhC7(JbaHdj@KI}>d69#JChQP zhUv>Wb+s>YcUdAJlmX~0aBWTs?tUbH^t$|t2@}6E+k*#JVAQ=z0=7aSQ}yrl68LQu7!miqP|pe<#o$?i=%O1dh!Z;!JAna~B#zm;Kx6eaIS2Bv)b zF(}&3T({auoeT2L#zV=)2PvcHJJwjB%ljXvS(E6wYyZqQpHO?HaUtxwb!5SphN}w| z_|M6t^k?Cr`9gnBT16Df#|NG;`5zCo>;$rOC11Y!^1z%eIYb%H9>_(Xo1BW9UkSXs z88#xA$AE4a-It-ocrccQ%u`iqIfA;;cw|%9Y#%T|&H08mmI5s<;eq7!sm!Y=UNear zEcye6fI()&GEsT{j9v-HR(#wAI?mMOL&Sm8Mlxu?Qv2I_;p(_X#MuE*M>iCu!Lsi9bE=1rLF)kHB{3#28MK2;al{ls%sO-=B8LG2$i%*F5y@Qn%Gud+r0sJByJA$Mx^HXs>o2oWaXG zhae4KRx}`t%5uS$Uv5jdc;80VT#YCnk2{?dV`*m=Z6X0v@Rjhj`O&(8PDrtEb`N61 zx(ZOS!E)^%hL{YSf#5s&SN)uT{04@{Pa%hB91Txh1+oLdUp(F>5QNR6;d6E{@Yaln z^w;!qU=BXjcY{W#D3&q`W}V8eV%Ii+yyfP?+-H+oWE_n&H{=TM?b^2j4G9|O3;{lP zk|o5^oFBTVWMCTnO7}^F;V78YFi%2_o1WR4l(=@#xSPN&eX`)^XE~VV1>r_bmrlWFXv6ND{%75nM7S3mmNRBhH3L|RBm}H;yEczk^0L8t z1Ot#`U{|3`C<#jkwli(sqn&}3aI)$d2f3Ta_a)b1UmhHjsWAvndhl1NTC442%b6lg zZ|m)LLN(9Tg?sEFmBA%}9$!N~W$G$FpeHHZY{JVUia(~2rpgSl)Ue)(%V~a%Nw*F( zf*W>t;-YiP5$snnJlHW=$+6k~ zDXB5a`derCZSdF`Zv1xi5VfZ+;8aekDwVU}%4kgZeh$B73n0MGiup1Ecux#>pwFMR z8M*fW2p=mIs&tne{wA3PBYU490Ah0xR6l#-F&Udk+yS*Ep7$+@UrDaSH~B7F@UxI) z$xYf&MIMio7cElf>^*D~{*Hta5=K?;z*1r|(C1SYJSzFD_saGjIOfJ-MFsU(-7vOn zYDwtsG8V4tEJ6_3x#&pW_$%+kNsDWEUvb zgGCLYw?V*qtG;`k=Kez|1gv4Qm=E!v$q`nm5be6Yo$d=m*=4_H_zW#kcZqYV3HN>B z8zZo1;1~hN|L=Uin>k-;p?)b{FtAC1>f-4MZdr~1GpZ> z7k)9IT=hPUcI!_o3?Chw@`LxOp#NKqS9C5|B|G|tU|!s>%FkY&NlcN9qOi>MNzB~6 zn`lbRb#WZf)q?;v20SVD5aHPG6#2!+fr0Z|NyrA95ByIBa8MjUrs318D3UqZ`8l`n z9w}NxXy?s(LIR4zssH2_Mi8aBWbrT0Vc_&rh z(n`H11Dykp_GtcjdiUwp=&x@CJcFFy8+Vcv46>MyRu0h`^zp0AVEO4uxeQ<}|BV{>~TxF{kD6$tu(8knH`}qKRO^mlQhuzDpM}z=PTt<44vo#wvdd`s zbKiYCVMEVE(j>)AYS&st-dh^?`5-WpXi(^RMn>Z&R~T{i1NR;8r697A{ZiI2f6NNK zMVpHIMT&=ns}1m4N>@*+s*zS*XDi@AL~_-0eOa1CvCYMsHBUs(#!p$oXJJ zx7EC`5Ra^V==E~vIMHP>9TlKPAVr;Gh8Mw8-SGiDk$HCCnj)9@F{-)%eSGHP4aXyP zwgWQiDPj%%A|Gx0|C8uf%C}Ez{kDI+YfjeZmx`72Gf~^;Va|krZG}6xT%@5N-hIn8 zuG+o&!%A(R`{|NSqaKp*3T{r(4Pnl@RdrHRNDK37#1S$`0< zS*i6xbw)z!A zE;f@Rv3MF=AmA3wo0)1x{IX&2uSQu+|17wlTlmEo)FaT+0;qgbQsz^VV5Rcx8;z3W zGI>eApA9$SDkktX+-LE_=E``4@>4_>4uxUZ5+$EdGCGi9C-r%gjnLq7%$P2I6s8j$ zmqW-QJ$dG(G7=pKkGQQOxs?zMWRi2~)+lo-!VdXDkpHPFxAwXScz*)?&y!cbb>R_j zm{aUj*y50f{@^DHYJlc?A_;jWg=7N0PUv2UKfcd)) z^u$_~z-;g~N;Sc$(29Jt&Iq=Db*_xiF`me)pGgK7znVA;vqxQUd z^4D(;Da&@E9?xTZ_|79of)B4dFE>oY7a5gO{MOuNWzK+Z5K~ljfM)zI@%Xx9l`KYH z7tSRs?|*fl56+a}TF~b-^d`_pH?mjqLZ`?C6!gn((0vh0sSpl!&Ar#{KZAtzYkCdM zp#ER#6aMM1JX2x_yBJq4$SFSE#Y(^{)DCIbkl4J*P$;{;O73EO4WO}$Z8Weoo*KRT z?P09|c9v;_F|IT>pWq*6(2Q?)+weFmwOL9zijHHPF2Fw5d=AMV|9ifMn+1+Tx z`h04PuazK%MV9f;g;DY}(lD5;jDZvJd$`6m@#4?eGH)hO+|8n8)4OlI-t*U{4b_su z3rOQ`D_fY%`>x)Q{swy0!orL!qvL3d_DvG10ahKbl0h_L9#kFsz121%G;sYGqA5%U9WSH+o{XsiixOm)yapu^;#!HvS_n zKlgeshQBDueIdk`?_&wY|8D>(qlU*q1xqpa%Fq^$>%~kNwI4!bfgZ7CE6LXOc5Ypa zfJeu&dgI0bjD%3lj-1~=^cz^6_WB?&=M&l+Bb(tN&wAm2GH^Yf=ZhlrpG&__rMIYsFB8IaV=`f^>7N?~{!xrZ(<9ZGAst0&b8KV)SigB-AhjP&hvl9;9|C zb1OQXwvq<3AWK)Tj9({$Y1=%Qv}8e`k(l>h9- z^Nj$Tf6D2%T;l?qj0FL+0$=peDIgVC9zIh)p4EnWCcnzz`YqF*C3GDBb}>f9$~6Z9i$YB zjblILVyP6)T{vRZwv2emsX64V)Ef?NM}2*7X;TCtRe>J~zYjdOw@) zBE5qUa%3v>xnJmS_k63;{6*>*@+>3@VXNXzPoJscrk97Ly=badlsQtmrr_&~#2&NK z`pWp2e2qG(XIOmR7g?#Dh7{4Rxj)XqQh~nKD(zm3;VRj0To*;TD7tAmQ5)Vp;7d8> zViSFqi%*>z3bBgxo`T!n%d&IBjI^xEs1!YKq6dwO4JLaly6(y?Wkw>7+pnq%I@tb z6YuF75=QX|)R5oX^TyX?*mXJuFx?L!OT&4v%cHQh77vo{@uup1$p=Y^`XrVRym81-Agg)d!$dJ| zI7zhdoHi)&;-VgH%oNrHyZG#L=NRSt2Y1zY`GKjFHFP96>E;*^a@}DG7Jr8ok`(<( z4FDbIo&Fo$@2_C4Car-HHz!Bz5ydy&tnnX2`m2VLJN}M92o`;L8a|f`q?A)rncIe6Zn2$_ z{mf5M({9RQ9!K7y_5UKRd`NhPUkRcCz*qgB|59_BGI23IO_worcX0kgeA44|LU_pN z73f!AcbsmpXQQ zIr8QvG%omt7!=_8B=*aTVBsaf;`LE#)IRbOwyQ@8~Nw zq24!MBJuWo9gRAHN`=c-vLqYQ?9kFUZ*E7e)rG`^k7B+>fyTI3?0m}9@jlKF_Ok}I zixhzO6}pU(K6z@N5)5;S_fi86Uv5Y7#zS{DHlEY`_r#our0pFPVgM}Ti-I2}%F-S;3lJxL>U4kcRWKLIInHU{P)+(VLWDJr*M6qri3%`>?BkCVvk z{-y!RP#WV9Z8{U}UO+9nw>Czbr3aH%AB!{5ZmFP~zBslLMWnrZdZm1~&kFi%*`*4d zn_|Z^3=X_$b2Apz;GJ5s6FHM!)vQUBb0iQXYG9Hs2QPPXMd-Xk5S&cL09EUrxId2p z%gjp*aR=EoFU@L(bD<0TF$#~;zC4z!-R6613%vQryzw9M`~f`4(P>@hAEd?Gi;lZQ z%KOXwh71m&#g7Ivs0qLUI+IwlpW5JK>Hzh^J4T8#vtLpa5wQ0W1*^_P2BsEzVsKXX zfKu7>^WM0OX7A9CEZ>A8Q9SR{pk6ylu?N2*bXDf9y6sV$8bzw-P9-SSsHUw12YYbk z?-RPkv_Y1z!&hD(HxT@z9pVq^L_PxU@R=}<3Dw}HG6{97))e+)@Zv%#&=};w^L{VGw`dbQ zYLVGAlGw?}ZD%D@3RFb46>z#>R{+u<>ywx5aZZcT=WfP}w=e>QDG&tzVo+I5q7J< zLB6dE=8X3~{w(0-c|eU}A6d7b`g2e)PIm^($`f^_Yq@(jhY7$$@6W00;#F3Mz3qL3 zE~bm8&LgP8x0(hOU@u2#+m?u_zX^Zyks6RK41l~GxBzR%t}cwN7WQhDb*t}d8qP5* z+(z}z6U9;;=~ZZ#Ff?xI@_5I_Uagm0k)m-Fn` z(&ZySG&2Ri-2hlL2es=u3j=Au< zyuMcKpyX&|V|6~q+Rak>O66?o@B`99Uo4b_Lh_WW@E0p~k&xJKquMnIS3Li_amP9p z#2;2m-37$V_hR95tN_*m9@J0dpi{qYmBB6AY^gqpu?40O8XTWPC)C)3=Dnl>?_$Y)0gK?mfyAvTH$_t(zP*)!oY;%ET>h*dpr_a_Mo%dT=>6@2|k-(d+nU zRC;Wcd$ZY{Dg)iw@#NWRx_ZL7A{9r~Z{s6dc765j%pCtJsW##sJ zv|BTO$8e|%_PKtp)XTH2Mo}KqFSP9ntP1G^Y}jZO5x$kQT5wPl-XyjeC%)(>FR$3C zKswoXb0#@T5_BJKk?{PQD1LziDr7}}3|!KMg0IRiRcq&Oi{@{KjAk#=I>d@nBxPbC zp9&AbC)G0U2~qy|=xGAF9aY4^zUc@|q(iv!_s$01#AIm(=CRaU8qe3FkL$O@yFi?C z7k?uP)_!jDe0IZ@5U||cQ_hXmBcYH{Mipmb^<;VR1(tR5ofm)iMC#mLI>u1bJnpa6 z>Z(>BT>{P^gru7G5>=25huoxMd!4s!ViLzwNeNqfPwV$a?A1=eJTMI8$FJHDH|)uS z1u{L17sn){Ij;7AiCA8vkV6fyH7&tOeZQJ*^0Ve0-C_*f0~N^&0=Hs~ zE~9u#ZA-U&-~x>GN;=Gcsgr_^uJX8*r$V;E)>8iCoGHaoT09Kmte4I^oj`_P;t3QI zDjuDd)dkI??XGsN8VeSw>~p#wFsZ2-7?w1`gSY8K;K4c~l&4vjLD;0;fI?z1F^Ok^ zgZ+a%@kc-uW#$n<>3=Ac-5AGODUAb?5HI^@@1(I|6*<}zBzWYQVgBw?0z|u%-tS)z zyNwCH-n;L-e!g}hF^ zUd$#V>Wa7%<9joi*hyUJ;f(YfjuMv7@r|CV8CR+ z@{Ol1a#y7FIz>J+(qN}e&=${isfV+4D1CW%2w^9|wiadW6b44;ZdAs;lYI$)pT8Dz zLV+g{a`Xq&R`+RPL)pZRQ|c;KmEB3Hu2f`o|MFmZiFfzj7o^ZOucs9{qO+wrcC1xER!G86P2B%F28La{$|77gbQ8u3?J} zc)MSxZyl6j`Tem%j?B3T#0|MDV&!fNofKHT!LXKvKtR=jbY3(q>0ZysgX34Lj&~PI zJ%d)@8W9Yde*Stf@OA0)}oXT}{lXII{^B8iL%%ql0>?9^y|Co*4Bj`?ULW*O6@ z9$G5}5^pVMLs1zV#+C-H4|UtrLhA zRUiX=83J@4OQ-Kic*K4x0JB+o`QQoO_k^voHg2$?sQckmpMriDI6^RJmv!vxlw2_! zm7g)^3RCn6BV%f7;=@)$ zdK!39VDuGisx5^Z_Q(ZR{^)ebG2#cF4GTI5&dEtr)qXnPx^g-+PUJcP-}wW0DUQ_P zT_pQ!k+t{eh9*#WB$yAj!O3R^gL<3-?7&sed#j@y76GCCdS)S=TGn94R3KkOJHd+9 zW}_hiEQKyNBeQ#&Ha`Stmwo5ojr>ZVGz~ix>twg@q>E~8%Xd6`=aFF20Q_oKqoA3n zFfCA{`tZ4;)7=Z;PM>Jmq|S6*_sAQ=elWyVMFI^CvQY6qtqjW%`07@{2X;`l!Lqe! zU3`^q;q4OM9mh_4-|u+frXyt+#`S)}>HAY7(D`UMXBTPt&UFa$aJZHTO?vct4uqfQ zRL_u4ofPt`!f!uJ9S@%TVt1Uz9s;ZXnW&$UM0(DI2n3aHelvnHVBu+IU(ykXb7>uA z&{!ichAJVo*^Hrx!oZZZB^;b+Sy^!9mXARY{$ZtTJLxNR#ljw~cm)3Mr1q%X!LtiZ z2L?0MX`*_KjYseM8vo$KA}8@!a*cr-s>ZS(LVz`=u`f@L|K0P_@=T$vZF%z+y_&ee zO7A;UDGF_th3WTKZ=A`Q=V2;^MGc{JnzUd5pMvl--S5mnEY$(z_Hf1t8AVmKR)QmO zC3{H)OZb6*LiAU_9o%h(XF}dH@G`c@&{hlwQQN2~vOlPl>C|Je_2e_mw~y~NFp&Fz zqL;42)(X!tTgoZg=#O>z&li8YXjc;AGlNNw&G0OEtvE|l3i_lbSpW6k`iBH|%Y~;F z4|GQ561{a7;#NSHGzu7REWWV7ERdq+TM$OTLzRP=9RzO=_;a6;WGDYoo8gLuib%df z^}vx+*(>*%-bJ^_D#j62ARhpAUD0#mB8YQ=>e#gsD#GhrT~&3NQv&0Z9JEnLQ9vtY zzcu-U^wbwk%UDb5XWLjfLlDk{`SbAAPRm=grRywg{;T}v;g8Az>dJCT$#=PO7gHh> z?X-qvpOA^;rN7L1P|y2rXt+gVUq|5f_*8!rQqIX^G?693l_*WPAld0@iI1(McLz+cjF zFfo_SR84Q6gFfhHFyCM}&;N=dEKx=G$fc{{i?pt1NoylQ&j*WLpcpIXZ>{)V>@r&H z0*!HhY6loSv&^{TOm~6PQ48MG2ZG^XX zLtC{F1Q!3tCPT{dyv0H930&9ss1Vj%Vl;w^urlX;u?&KjkGqoa<6Wm0{T8f=e|j|P zJ;FZI{gs;+wJYgGooxIb@%kPF<_yn1^eri&48s?4=Ue`K33)Oj(zNMTh590wrCpqH*qUsxqeG$wT~W z8#)~?uK43WSWmZdj)fG!vR+{Lp3RkL_B;NpGCI~s!13;~%6Z#-34dY(`K9N@gxglH znl{B12j)xxwQDl|8CanlBCIVMv=E3FD<^ncY`noX-AR;uJ29MT=m>*nI^oe<+Mz?? z!ZXNJZbV{(I|7Yh-27x7NqQ<_J!i%J2cE^xH;Wxti>7L!T3~ks@#nM#dSxU2=Pr_$ z*Q;(G7qJ&3``^G8*=gqz&Th)8xCQ>hm-^r&3Q(Yp!C}N)`n(Y=?>zs?yhkGIv`>~val=J+bZ{T%0r3>csTod{20qMNr zg+K8kdt1gNiO-DBiyXY_mdUofp-BVRU$ELT94;;@s8nnM8ifH zt04#*3zhb_TVX=<@R&Io7rihFd{vu6UA4wIl1b9L7P*)(ODQ0I@ChHpX%g3TYc}o_m9F{ z>4R@D5YDW?)>b{kFMvt0PXPXG(AFWM6GzzfX7L|jdZ<$tTIB}mcm{a1KD9%x>rMg^gN-V zf0^usEy>Cp0~)uF*F_(Lyi!=&{39NyG4ucWenHW}gzn7!c#&_)Qw0CuLJ9`CI4RZX zsiyV27KDqi^DrE-Uw%R3d3dJN{#00o=9SFs*t=0SN+m?ZF)vhAvC5tQ9n1;Cw|=<3 zqAvu>UQ41mTN(e97aK!d%~qKY?YRq1O2;g|yg}E&vo>nUXx0Sv>QNC3zrDPmTm;zO zP$*fsJRgc1uljtY_oH-f{JiBCS>I?LnIQeJiX65I56OtCcx+21)bt5js1dysSiHL= zOgFBQ#IL0_V{2hE4yUWyz=ur8i!Q*9mc71LFK_4ZKGt7+;bFdXKs4Kuz6hgZ{-&=p zk=Q>21<2Mun|D;oVqoav`uHAx?EL!f+rPIT^z*Md&Z6)6C4LeIp!B9mzkM;82duxP z|Lt_4;klvaC0r?=%lU~|bybEuE%F?hUXgmd`I9VWJ>-BYtRN+34bekkq>vYNn{@FX z8s5Xf?y0SrMx<>!YPz><2FO;ZA9cgqX_E;V7(g>H*9980!Aoj?E%%(}zRcyV%cp|W zmAB_KKPD5Ud|@JbEnG}LLf`Ht+|N>fD-+WlOP79;;Ds2vteXt`G7{t!G=mbPaHa(nVl+ExPu~>s0;rvMz?~7lTY|usi)>P+in;myB{2+hV zo|zZ|N#=I8>3)h+{oou0n&3ATVt?*d^4%tQ$h&V#Oq3?5uSi!-UP`f1CCI-^S8CQT z0`(CF_4lG|pbE?GSNx5o>!*KMN&tcQoVt!65CJ&r8|fsOx6yYrzPp)@jPDX=O4@C6 zv)Bf~>AAH#M554!ybMt|$`cvNHO7ZPl583bJ4w&hGo8?c0&&EXZ?a+w6RHfS;9TIk z3@Ol}IGji#G-W*H7?zH1buWep)9ukKk5xdkx;eB{oyL9K`t;wV#zE#K1R3J+aHUrT z&Bq`50sn5i<$RoyHO^y%m9Hr;ItqW66-gnwV5wt)zx?F3CiQU=2M~n|6%D(R9yHr$ zY?yy7#FTUs1d;p6I@q5A2vS6SuuBX`wE|f>n$4iml7`j~ySf&ZjX(S2YjW^!8p{%D&!*;#jri8qznosO{VEdU?o zxb&?O#^K~(FGu%kchxZs}i_g9%<`n)DYtl@;_k!DSa(p-~*rn9 z>`>ZdhH$Zq3q(I~1B{6pa?nk_5-=K!%wF@#8#5jdmK83>v5H(cV1}G1b~Az|74=x# z5vH#;3BEaC#o&*)tzkL%Yzsh2w_$5rKGWQP-gwx+T9{)Jpnr-WD@I#9!_3VUZ{?#T#*8HEjJdN#w)|Xc{|LboNM~V)LH0jbMwAYN@F^Q zyE>eg#0+dWZ0(XP*!`KxcB22`2yH0BY5b&Nzjr?XB(j{fkEpN9521FXN2cnx?u7dP z&e7LB&XTxft9{iqkG90RkKhmvUu0=pPK{33z+b%z@=HyVSaHsU+{~|r4#}tU{TQ9+ z=gW5sqk8%vX+OEc%MvtsGhIvrdaKGVYLB2eYC$p&#sRYQ(z{f=a5@&rJAx2dHRH} zv?JDYPS3|+p(_O0X6cN^#>COVd2c&@=Tu~vyOWX!Q6I`MNRGGE#Ux<}T3#GhN$uKb z2m&t5G+4Ig(7}~`pIhev77+9C^%hdc>$`i^pAP%%^q=`G`dLFX7@>R1`q^gdC(Rm3 zQKi*69%1>vNZ(-->%Qbg6RZ5vS+=kjtd-3`4=R4vr2a;;H%l8ci``#RYwPqN{u>H{ z(KeV5DdW54-zBCZ$b5u6Qm#>!jWYWrivI~qaWCzDHV|Os*W{8=0OFE=E&93lD_MvSXwm025b~F0^N(o3YuP)E58b#H#G)T zEnR$}7sGZxOoT#{vltD+{>n9Q0U4 zR~>(hw-meBh7CVjekOriP^#sJJh_~~AqXm4bonCH5ZjwkUDPLiq08newKCy$v$j`xHZp`Q%pDh|lQzJMikMERb{hI&E8pi4KbEkB)niuxqQ~3!(l<)Y z9wjee*L{WRml<~bipJvoe$KWZ$}M}sxk?iG%F1GFpv3lyrmZl+4T>Of`PTMgf&Y`) zNXT$r;2AgG5j;|L0g=85PWfW%{FiP<)aw%5qf)wIIquNV3P(G(8-muWZ7ZeG zfmF0h6B!%zvyf9hE;>(!gt|}doA0{wn@aIg!D<%X)xM~ zOnU~iY?92LScz1gWHxl0Z+DTBZ{xH3b!g8uknyb}jiTzG)8)K<;$gZN5paSIw{}nE zgp>-|%}h_wCvgUK5$dBG@jko^?G3URf`KT09o^Bp@4|^etp=T*Oi#w%(%~Vmim-f} z7gl;j(j1rv#caIm_WcKb<#NV8feDXFq*nIoN!hEWz%6}aMeHV82AdTBWriP1aO%4G z?|N`C81rWyhVi$z1r@@=Th<#F#K|Fa8&@#g6z-AV)Upmctnz!M-}UIo{&S2 zK(bM9H;(=EVHH;g9>F}<@K5^zI&&s*KK~3~FiE+bHu^xZWRs^!?y1~|=0@FBqiOjP zn&*RTs7S=I`W&`{k^`A=4Ymh|WeTGbSlD8l`hO5jodBd`PB3qCIG!V-cm&UWk_lQJ zoNUO7yS>>8-*EYJdHyRWF}31kpVz=)^&6x6!|Flyn@c_1a{B|ex(#*`80J#5H%pN5 z&!iWQtiEGg!NZF%jCE_^F2XEb;k!TBDXcLX-;N_vx(WX6(yUcRI{ZM+55FIRU16aw zECr4bk#!}uMcngA>ADEe#=`1u!suGichPnbi*+4Wn_@c^ztg;@_|MMGaM#iR_-YMbmV&(fgu6Sfx!cFYTTQ@8RgLNyU>-Ioz`*#;RG~iw#8O6r8 z`H?RMh~azrmzQ>3D-`k=4S!}*VD0t7pYy$N%ig2eddsD$iT)o$Y166LTC-jF zW%%%lPQq$i%9L@4H7v;r=uFio%_lB`z(>Ap>|fU&i^5X)VDK7bJJfn}Di27{P4_z< zZ8((juSlEL8*4jeyuJo``?8YIw0G;UUeHK!q0wi()dAGaYsKhTxxYR}q?~%6;uYxl z_rM*SZT}wm(h|^pISZo|aXc-s4r8`aRrUVa`?Y88cO7%#hM)R+yUtN`>-foi;h6o$ zaIbj&XNKR~9aqvVEV`Zi{BCT9JR!wxH)O08ZHM81mX<+?pK}1qQ{U2%rw>V}`@Nvj zp64#c(zU{j9iZ=8$nFzh=Zmhcf)YIo%$d_R$l6U4?iz~)1oWf8>O&l}rNsR-$%NtK zfb1H_1p}~S)P{RQ&weYPq~btTb1uL%STz|UC%j|7GoWMT411)li4jh;qmV91$7&b_ z!+&I3Fhm!{pKk&$xQkQyWvvX;2%OhWbF2R|YzLtb+k+Z<&X5wi+rEAzA?N@3SSN60 z!vU6(L*Hfh%N;!L?yuM)cec64shlil8K`!m#_zPPNGQ@9a9vLRa@f7LI&sW4)YFSB zq)@E;f2P|Dn8H90fUVfJ%L>7=q_aN09!LEDz%f*rt>Ekd8w>>+Cf20s4C)4y6D!dp z7j8iT7cxKt&en2(Gz>IXqrC>|i(NbefDsZkuuyp^=~i^)qpIa_mD{N%%iA@UciO8_ z!%m8!aTl*`O_HCKJc(?6#lH9d5%t}HQ2+7&O({F$tO#Wkj)d$YRFu}IuH|wHWm86+ zYuIO`A!SFY&qw1@nK_(8!%813oRuT<9L~A%{yneH_xJt&SDz0$ulMWyoR5*Gi!E#5 zb?O5KluMlwOoIqhHj0ADMM1j`BUNPpUnLMIL}Grt(;7_ukvvJJ&2FD|A;(R2fn>>! zn753fh!KOvH<3WROx@<^Lkix4Lz-W>kkv(sPkJRrsxZQ0X6u;zQ)nKWlQ{#kG)`MIz;{`S++O=I5oFPCzI%in<|-*NQ(vQ z^}=ssO4)ZfEzjWh<5K8zqnzt|5|Y`TABeJr=Rv2O&*8LEOtSwFZ>s1Jb>W{E*1Et) zAN1&>4eQTGVMv5ai#c0xq%E&cG#%zSuOlSN{enWeFew}d}(0Il3Stg z7i?k}O?})lD9P{5Qt|V`GjP3FSu2rKF%yVu>i9Dd!x!H^8o?!$X50i} z{l)%e^?o=Lge9_SqkbjV^^96Ug{ zZxM7#{gZ2_WYl(?D4wcql+PnpS!?6^V6(6<{#@}X`mOFy%@qPSVS>yo(523)N}hM8 zoaQqn%^zn&E}w-{$QOhc-ge91$iRUT0N4#0OT{lAB=EFkrn@i*@Y@VwkVAz<4U^r9 zQiex4?ODEbv&agT#ijdSr}*>GZz8nzVoD2_pKc@jtys#T8O*(Et8s0Z7h1W|{_;g% zrlARjX$vRG zMZ>@`uNsEHG0_40KN-iOVWqmcbe(2)6L3NHv9)NkC^`tyf(ya)aSCOJ2AU!qzwT4$ zFsSlD4Ym{m!)wlNGl2`yU-PQy^+5INq=kf#!_|5ZPxa6Upr?0i(BXwO9IN`j_!GcGA?!a zP^smEnyJIW=WtNWM(2pglE{Hd>}I3;MARi8(pk$Aky-waJG17i2T6Do;EFrgYp93R zo9$D!krC+)Q^?W0=DENB6F)&j4!2YT zZPPk6mny409BdM8zeH=*#V*L-`eC_3UC{?oZ1T|LdbTypb8fY+J5As`zi!l8)RRIY z#0wFo-%)XD*|sYd#ydf!JLI}D-sAsjpE~(^#NEBFLc_|=j&Y0h zNG)M}*!LF^>CG)!iMmih-5+sjJ7Kov)~kcSi13sCLPc8hxo4Z9*`#-@1H>?ECYj*# z6JUUZ7Ks^dZ7~KUXTE9tGrO@0M1g)K{ti>o_|&nRbUZBVVAQ&WI;b>2---(7S1hV- zyteF6xstVv&YrLMMrQGOwc?XLe$n=X{Yd8)+;YniUBPBeT23cTXboR#8OI;x0JMVP zwn#+%+y_WHKyT7ls9rxKqezMy^l^cD*l8qtnNo};o5MYpfDH{otqiZ+K*9aw0ec1+ zQm#$e3&ah~X5v#nvS(Bahz_H$Eim3=^S&tqH>i3o3s?%<>D>?+nG;L*TE{N{Fz#s0 z;AJZcc0YXwyG)|#e#2>`u+-o1kEJQQ0UcP?P>k(X4WOSmru?}JS&~y)B2M{1IZt5R z?}^6n*tqO1t?+YAFoUiCbVYB-U$1t7zysaAF;njy0! z5R}OqG3uXzMDHm8D1a2b=E9=_5-v6)^M1X@fhgT_Sm#Wad_S^2v5%?jftXOZ%nwB5 zW9z{^0*1@@AJ*V|sQV)8B@Pm9U)OFm*A4nGkd%zV6jphj*{G2gCHalNM%=-D+{sZ& zL0%6*>Sm;pTq$#eY%%!o{i`NXD~D%P?t=KaO5vpJ+Chzo@5&c3iK2uT4bIP9-ajz0 zlK+H^Q{Mkq2|aN_1T-O!Qjh*)dmi0{O~ReKfKwJ-fCWQ^%gO`D*-ISHpPTlhz`j;c zI^{WWHT4ET3#nPSNu48I<4<6ZPFcB-?|@Q3C~$}lBH?_Pu%CVbL?B3Kg0HX*!9HZ`(p}n zw$krV3hg=#))z+8z)@S?>*T*gX6npUYEL_kK}s$k3VU84ZJTkZ@)duR!w_bTILwbD zwIAbH0iZT=Cgb0mQ9PM#c_4`s`yl1HPs1s{o3Z57YzzoD~GRHvI#ro*` z_fD>745L^8-sR1(qG0x`1f7%BKBbd4wtfEcN96C|_O_(^eRXG70>u=Yc|x5uKvw^e ztvE=!)0FBTi&_aXn5vcAVW`?FY->lpco8M1FAAIlc4ruL9SswAFt1v#x1gC}C4lN$ zsD}|_sqfdRKP!iB^auHS z`fZAA0eilg{zDFp^gtOzruD>O$f_6{UF?|h0u;i_n_+R^|9BW$>;4tEx5pz|+>WQR zbXLE}UrX?1ftf5`V9=cEtQNzL2P9c6AZ>fvj+1<|x+O3B;6-DC9egTNb`^*0CI;(& zQNF5$m&_{9&sn3sW%O!wbjGE?w!37GS4*9n=TD++$&|7!<8tU<36Yz#%=EoG(z3M( zwhkJ2RTiw@yz9{bA?WfNrP?3nod6FR0x{G>nT=e(MF6xXEaQ#eC@uKIs*)4Mc*VGhj^c$SsN3hT<~A~ zL4*OderS`K}!5yiw5Jn*@D)JG`6*=5Ys7&?)qE%nB&!EL!h=m(6eZVXgF^1rUk2 zd_pAj#E6Km%b9WQ%oFXnN%3u z8k;Z7f|}!;psGIY`M7oxiLfPRzCRCgm4Q-yYvs_xxiV~AURbfw4WOVfTSy=?K5M0k zjCAqi?MqF)V4W7PY*h}GwahWYe^9)M>8D_#_hMmh0G9fI6fp~9mgEC>^oVjv$vxbC zwlyz*c-bp9XkIXBd(uP^GaisjRej)8gywoQt88?zXz;g-KAN9$UidI!#Q->v0@|nM zQ)FDG!5L#qC31`f&u5CvyQSJH{!H*1d=LI_-6I77fIcZh3JA<~D3d-YV|Ocsw%~zZ z9NI;7&^pdYU|bzEhc^@!x7Am}wtM{|ZU#s2l${~p|9j-if_(+%o`#s17cb=*fgJlD zH02hwK7irwHd1Imu19mSK6LFQ3Y?@pJGDKk)rgr-sSE3XcG5g^#0PkTcP~8x35_>7 z5(#=cQS}g(-!7Kf4=L4-2@JA(tf0=FGzo)6>C&wk14CRk>a5E0eew7)R+9*-)>=aj zZJ(xl1`z9A@mV8F-$CE$QSatwM04uL-Jg~(R{&XYD0SU2e2f9+{Y6aGWo;#m8lu{k zav6sejM+|&oACu}M$IknY8@DN&$#e^2dDL}7A}&KzePOk>9}*F1ZuVKj~h^xy^kFC zRUzTkl%QSPi+Ocl=GH)Z6rn908M>-x{SD+I*p23Jwmn?fagm9rX#pj62%Q3O0R%s| z6<$<+R5D8SI0)tbu^NFbS}7b#ZQLt)*;8!8hd$Zs0w3TEpU)hWdfB%B6Jf#K)=2Q+ z5-iC~s)BkhR0w3yN#`8%5F!PV(p0WQU)N7i;_hvZKUXGC)R6j@H z)y^t@zMD#Je=N}1wYUG1JfAzUk>u__L|SG4|NDhCgOCNc-v4xXk3I9rdNFkJivOco z?*9xJ%=I_egZ@w7{bJWnz-B`O-rH+5etWQs=nTv#+qq=;b)o-TcAg6eIKP~ZE`hB& z5NGXa(%eVK5)(WWUF7lLxw&GpX)+5I_@$UK7&3K7S%zFawKI4=b*nHsioqYjR1c<1 zq6$YaWj5e#@>wd@BC1XWCZw&evN3JixB03a*hTr!gh&L|1wPVW&c?hcNKO`}#jyCC^gfy2+d)jm z*Ank}KIlG3<>`$owLwYSBZycVac>9q|AiNfH)?HQtq8>(KR5VDB&JHjoXQ`YePs=d zfvGyHFC2MyYjGO#Q{-6i6=H5J*&xc4r#_F1C3T8#zGkvZ@)56tPzKa}a>ZvTGOFvKTFdoOr0(V63>dOF zuax?>ca^q)0s>PMvnn;>$5c!i<0~}nJU}TZ;lqXN=|{P z@le)}RGVtKud-T0w^<8iN_8-%TDwa-(SbymUUk_30n*l!p&_;THF{FKS!X%)vMXO8 zJ%TVyOZr+z3F$k>pQ#PRJ>tWM7`a1~OAu&>bFAx)6T25KYOanzI2zrz;K6-H>t4_- zb_K@*5@cf`)oPUTB&y)#)nq4`wH-rSo@_g``U^kYx*JmAQUqJfFk*T=u}}oXuFR%| zHLIT_esh88c{#DpK||v815-1R$z~MjHMYXM2b_)kop+Mg0^J)s)YRmRqYeYK67F5dZJ;2|&JtFE!zRR2dK~`uP`TYmnDF%zb^LMfB;##q@3}+=DN5E zjPUjHgY?MDnbli9)$YR~8`MZ3KDYFV+k+dxytL6ZVgJRW+d%PMU>KP3qsXqKe4yI7 zF;8Bz+LqNIWIL$lixgP$@T|MKCvi)zMgFy-i4PIST+$!S5V@Cs^b)kyr>nv2(0UYL zJLugShEf+z=bBgSQkr$o8c7>k8YJ0OFJ%JcnC1&QWaFNIgKWwIl$KP)vQ#Z#uR_Np zfRFJ3vg|NKirGgPQ zhRr$l4>7)Xp2|xLxE*siQu(elZ1l&aaR_6$q znktDB-aE-^eHlZ|j?G^uem@3e#<&B++r0^0a6ni))`8DtpWwq`)bRh@U&&Wgr znjb)w(&-99zw|8%XWw1hDx4YtBEY#Y2~ax%+kAh@Qxu4SKOIK1R|uhFVz^RkUs)_u zRlvPM&1I56WcEOky7d+;GF$fL+{K^V$0GEDjWCj$j+rLbwKenrygWD-W~s&FJ<_44Yd;UX-h8V0 zQOn5?LrkiU3yfodk?=xkGXMiM=#!}1){`>3L;Ox`ZirtaOB;E=XM{>@Xq7`xB#;FZ zx;)Ks&t+}k6C-Q(*6YHS`DY301bM;sR<_o3JMP);;@ARtY+b7Vrc*jNPzkEEa+Qx3 zB~KxV`~DS3Cc49ae%tFPb3#KjsjQ!{rQ*nKT`apXTjK7F2x@Eu#P{eEYhlU9&(dhE zGq6v*#rA4I-m;5-u7#~9djd94x1e9jZctE+o_oxe6n}~1_mp%)E85&4gpC!@q7k?7 zTV3_Qk>EXn4}nH9p4A1ibDMr8Dj*AbWF*U%c0TN&i_0!5(qbDMoMMT2d4z_`$bUHR zqTg$v>*Jw$tX{1k?XDm8rv@cNyUSRDnZcLUlfNjPXgc8VXq;V;zvEKGqq(Cx&mnS; z_Z7G}I^4mKYn`QX@1N2KL>3p@0*bclk8N^v5To7hJ{e?89Q?TUGL9pft$WfZyznmq zea1NWf`B~E`O`mLpIrV$?3nJ{VaZe9$-c1uZ>u;_i)qz09E%Bx(Txvx+kyNuYD!89a8YX9bH$tA1S;7NA>aFV|64!6E)n-1azCA=^z%8 zB|%Gyj1<}^_D$-ap+TMfd7b}aqOk#9DzZM&@>68ptxj~qzFI1gRc`i`s0c*jK7#_vj$?MwHj2W&gqa}i^(z9w955UPReMqqwk_x9UHDg6 z36Mw_avQjo3>;$raz-53j>o01BNYcDZZE;DL70mom_9xJ`OE5kCdw>o;)5`^jazAZ zHN$b7d(!awJ&;VFT_;$G^CpNfcb4HbbE-Q%av1dDUfOq>n29aX!xo7d-l%cQIxBEt zmJ=CJ5yMS`hINwK`yr*20htWJ%$xbViW&HgdNN8Zq%8ZG~%~7{EV;f*k zGA9t%!Lq;pAwiwf+*uGH#a7DyG^7Y(Rrp#z6kus{_i?5Xn9%(l)HJLpqZZ`E=fush z0L_UKCPhiAL+9*m@eqVp#!W$ay))ISjVUXfg4q9=IxHNO1LI91iqCR2^at*WPXxyB zcygBM=vMR<4k*Wsb-S!5CaqBG3~|-*wkif~TbmJf-idFsK|ZrkQ;lhM7nLd;`HJEq zEw!s5R%?Vbk8ArX+8OBXPCj}wqtPTP+9*!cC#fqeu*zU$=$Mps0mXtmRM9rOy8Y1I z(M#4z4~~|OM=4eX;a5yIg;I(y7=A^qNX#4|K~WIi$`0}cM;6nXn zzaq&dP6IkDIW*_?f@)DeE?d&kfm~un1_Onu1yINFwRQ(a0}!t)211~9ye3}7%}xN( zXF4a71q+AsoYtzgVJbgc0T~36@rt5RHeQZDvK+IX*qE_MoR!Rj$m6#UPq#6D>X>4> zpeTB-_&D_$F4pz#W$5*MB5ep9E49a^222?LixwIVQ(>UHd-qTUm2qH!6cG+%|JDs% zK_{q*-3Uv4j#r>@y?#Qp=_@DJ$1yijU0ge?V$Xr5Q(fN0H*_pV7MC_CW#jldQ`5hQ zNbOt1Y6S!UJX{E)B@YQ?Tuv%y1ZlSl@aVPLUv6;t}2Flrk}W z%~ZZr`4XHz!VfbwvurItxTt9e-@(f=YHjCjA0jbg;*MV@&S^RrVLcON z_c;7_?U;hQm)cVFs%~;6K;aIiG>au%$D@3P<_eW+_6um6nwzQlTCZYC`Cz1nGdYD8 zYX(uG+3D5;-m=;m6rKcjNm!p@y_t%Xszp4Bsv$+G`S#tQx-ExqA}PGu^mY9yeH3K1 zTqyI}e1Mvf_i}Q5G;6$j=j%Wmo4OHzD5I08mgDOIB|WsP8D{;~8#w443u$2JJGnFn znE|TI6OcVz9GXEQTKBvera&xgU*ZEyWSbLeEK%YYkpfAkR<#J4hPWKHpBzg%NGNt} znC&LHB`qzS6ZGvbEptJDm|H{0;nIhxb+@U8^Vgiq=1EsD#m0)L7y1f{_T@@%>Mlhz@BJsOQ7E6JSsC zN&D6yD-r!M1=j0J9*W-ka3pi-g9BS^j2ZSU(}iLz-D2|Y!$e9K17sCJG!PktZj9^= z>WsCEx2a~Vdxwz^V{zspM@R%_Kt?+klq??DC2T^F3?rlc{S>g!gJC>z^;Qh|qmeb_ z%5gLM4J*_c!M?G#Gx)Z?zyhXYUDS}JgY|CF8>BNGcYjN(##l(n_@ZV~i{W0ethuZ? zf8dYEsWv6PVVEQ@`H}oTPY)Th$!p-_9AvaYxwEoC0MdQc`nSe8?g~x_-cV+G=tc;3 zXT1X6j)jnp6EL0xL@c9kftQ;F<6LG<$td8n5IbQ)md@&45t##t1_MkOP#BPX8kLG& zg#~oP(?O;?giqWsNv`_`#rIs`fhEX`A9x#GGOw0T(CW;+p4i8ee~N&OqB@QFy3B

V|sSC=MfO1Rx!f3w}nk4UYEI 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¥t?-llX>aY zP2Q%_ZK69x_lO=5{dV-E=xNcjq8CJe7QHfhee|~IJ<*4ve~A7$`nTvmqHjjukH%uT zSS_|dY%sP+Y^m4^u~lR1#5Rm=8rveaLu|L$-m$O74vQTeJ0kYY*zDMMV`s$9iCrAK zA~q*>OYH90y|G7PkHwyjy%2jX_Ezjav46+n@qD}B=4~`!Z-!pzv{QL1A$G;u_S^Ssr>*D9d=f>}gKN`O^{(St^_}lS6#gmDA zqMmRPizk*ztejXd@#)0IiOmyhC3a2hnb<$Eed68N%*0WNeWS-GPEMR|{7(`WB`!}~ zmAD~sTjCyr=foaLJdt=d@ls;L*n5dL5_3$vLF-G-iKUZHvTS_bJO`2sCzniaXvV&L za&?2d+uF%#&3ZGETPJr+?wOlDskb%j9**J52iC zi*PYsn=5Pq$255 zdXaP~J(yl9y+V4u^tANq=@|jrI=y51iR3QnJ=6Q84@`fo7-o&H|>RFirlIjeb8 z>WSoe>7S*4Jch6EHbV6 zQ_O4_TR1b2Su(>Ym(RQ$T|F}=woYc#%!bBlv28LtW%kIJnail(gPKR;dm?#w=9`&Q zGP5)9nic#}Ml1Q#%%z#jP5U{qt1{=uo=9Gwxh-=~<^j{{p3EQ2@it$3@%*`2drs_c zW4`-d2-bLY+%4Z6cZ*=3|3BbM%<4RmeBaEKlbsVwX7ky4cERkTCOs#%MDrLn3!gA0 zt7O+~Tdp>r8Y>;?SgVzNM%VgVb*<6L+Dp#o#&~zj?mej<_G`92WKtY%ykDPBJT7DR z)DiQk&!fl1bKJOUcOS+4ukoD;NBI2-x17JDIAbi1v;LRFV@G#E_Ok31V=-O(zbdv% z%pJuY^C_Ymvri=N&CW3QBYt}@`*`-O=!@BBn*F?<{Z}@VJ1bhu4dfQg?HldSEuQ;C z&fLf3Hq33DTPL@9E+5}Mw@Yr%+&1x&E1^4Eq71u z<><@0cQg4@HZ=qP7iZv!+%vhen)md&ub-&Bn46rvo}04&O*6nw{+G^c*}i-t4=yzQ z#b&oGmapX(Xrg8FtBjTUcmF5z8<_kJ&2y9dX8G;%yX3!=-*2quLHQH&J4H{;pP4^5 ze`E6S{IU7T?VcBN*Osm=yTnMk2Y3se6ev}?#bYx8{4Jh26`k4GMl z?3g_>Yjd8=zTZr*ojW{tL+<_D+WEutH{{>QtKL9ilfvVX1I-gVXI=_?mBD{6EL(g$ zvU<_-t(TtZNxQjIsi_(GzcK^YPI3o3=Do9t+uOy7w^hrxixa)>&98QsBfp(@3g(@JLa|USe8i+aR@gVXVQjP5GA6xz zVfDgBh4oBoGxOZmlwkgIv(ToQOOl(+o?pEB_;3J9$7r$LRt$0$i?U}{%i>3Hw#T$yhjNe|o zY98O5*l&vu8#E{OWbwIqxx#-hzS+!wzZfg!N^@chlxn4Yqsx{SGe_4pjJ+IP#h2rj z*%@5BrF_fMcBN^h8Kpf-yR?)A+lS%SRp~89S76!9(ov=3OZ%Hqxpwk6B5_+yG0e|HBTwbZ)8AwM#c9&uubnkiW#t)pey?OLI%V?7$fwDY;^Np!ECFQ_c2& z_04_vSmt+)SH{`@TN500`x*Jqd}nOmS6B%%nkZ+>)pA&Qw>cKQk|9+wxB3FO>HxA5cEDe02G9^7$H zl)qheD&wg?zw3Gxku;HP7#pY*=VL@mR+g`1&J63kB z9G=;$vai9)Th+|>!IdK_$5du{TKQM!d(F1~y!PnG^bg1C^B16V4X=8-#5{jlIZ}Tg zie6W_wKCV_A7Rk*^RCbHd)8gP2P#^D$C}4Ev8RoHVJz)knGY_#bMqa!*FyVzrxK~o z-=62!yRymo99O$h7Upw5_4&-#E^hKSHG8;ojSr%9$T!C2&AsY}Y2nvL8_`F7vD#eS z$GZysAW|zRM+r{E-_d%p%%^1ed95uf}+|7oJ znq}?k+43;&w(*xnn|%JfFcfz_T(f&a@hYuHbZoA5R-V*5Cf`C0di${;1kP z8{bOW9VixB(zD%_-M#Hk?R5543%G)jeK6SeKT$v4@rKnO_UtviIUZK$gUjp0+HgE(UnTr%~fn+<0EFRPOP~G?EKcFV^&GMPG*eW2-~N%wLEhLn3l^LE z)3T4x_tGPETE}YVuovGhDsih!vl_M+v|62Fgg4o-PN(+tpKPv#`AUbeV5Hk!g{rN!BSx!ZVm05ShF8@ zysAUbc-06#6c-O7@z)3&ujYb&nG@UI^{NpZuPvpQ;E3!v@WE2B|ETdYD#mO1?Mlhp z_^h{eY;R(O)z%Fguig#uKm2oqVuR!LkAz-qzd;`?1$%SVf9v{cT#8(MYn>TqFgmsM zKGb`s@#s2V-L{$Q6_3(EA8m-_gX#f+I6^ zjkh*vQvL_Z@va-?HdtIqDus{fF&uyF;xHj>6(@@#xU$TB)p+Nb_zrDxdsc_XuP*4b-z_3(~7n0Bv{_MHxw zGguegnJ>JJKiBciljh1lbCkPtZD&?~Zq)?cDO7b$3>GN2;a2 zzOb9uTCUpN%KePvtM76LSvq4y%IbRe0_jY@{(d>ypNWn{XGce)nV7jorbn|Qh0)ST zb+kS*I66GC;Ov>==-$8G)m~3aj^6d@mR1Yzd#b{fz>0JpcUY-L9hUFU%l1&m-$F=d zIUcQL%3;Q5rRJv6>0phqh8^3hjk^Y{sK1>>LH020?g-n;^}=E&H&qO*K1Vb26UzTI<@q+FGI9)J{*}%w{m;m z?4N&sPeT53As)77FRyf3=R{{O@0rfd1!G5B{#KpF*rW*J|pU=Xm&ob;J1k%_s4^7Hs1!Q`#+Wo!`FZ9NSOEww7xJYpInaE~5L7EzpYpZ!{57)kK0Bd%LHjuhuOIE>ufX2db$rf3uTi4rbFE?KGE~ef zEoe{2QbFT<-Wi z9G#A?l7lJx_2Kx~SAm1&7I$KI@6{sa%I`keCBtU-*!|*uqO`Ah&!By!GUiH0SBv^A zvhE~QbM`8kRYz8xz4GkUGpl6Q$gG`Ne`J-BY36UTYmZJFoiRJ6dg>P=WqY-Kh}qWi zell5YX2s^l((&o>S>_iC(~0ScS&6xcbaHxfZfW|0>C>mr>{dQ~=JeBN%~TI_<8w>1 zPMO=m*{RV~COwjF zJ>QKc!p?%DiC$ZW)eDQKQ=WI;TK7z+mMRO|6=8YZc!K5KIjkPSeArC)niq`3Vt1a@ zql?Cq3X8S3_F*mC<@LrGtYz7P`MqMbS6w?_?RgJ>1v2@CDzW8ZT}amCbLBMPt^TvwQbU z%EfkmFK#yy+6-8hV~WHu&EbwrpN4BdA-_svC@@hPR+C# zk11+Jr&p>{=6KqA>+0{Ww72sRRD`#7w=^8xYN?zZGQ0W7tdV%w+PLxfQ{C9ZxO&fX z92=ASSE12F@9l@3;NM=&E4lP&I+GbOzuP^U$z(^ev$Lb-H$_KsvvZ@lOujq!NPc#H zG@mJq6lNDj3z_0badvUEm?@2vW|u}w?tB~@chlod-5win3vc~#_MGsxZI?clh{oz3 zJJZyg#Q4<9u^syj&Va@=ZIV5jJ`cUUW3TN-Z}X>V+0I8a z^w`5Xm9{I>icB-JcYBW`)=W>EIW2vA*2_4p;6)wN@fa2udB-+^y3=}yb!=zPYZ=77 z_c!sD^l@xrTFa*xZ12a$ZjYJyaLjRDq!Ueb(tuXDXB$sl59_fLY-i&NYNMA`wr#C% zp20jZ+59l?&bgZktEar~HA2oIJ;q`Cyxp^_gL7f)bn{-0Zgp+>w2pg^`+{!QPs`Qa zhu=l{`Th4ILfv@n9eTHV?f#D0+GBW*eFZjNue(3pNp@+CJDr^1wrQ5~zxVwBID;eBir81d*1I{~cBL)1eBg4Jt8KTwJC)o1gWkS2?Bu)T(|U|&TpELSJbd=WyO#PcY-^lh{kyfo&eygVdE2Y? zt+NQ1t0c>%Nlce&1_ZbmuvdyU%&;yS{qRY}?xH z{XmC0-u6m^y~p;v;U)gPY4=0WyS3bs-tP{&-L1Kt?NZ^f_nND3C3Smr<5K%hb-M8f z%iD3;`y$TG?T_|4f!904{&()%x1>aWL#UWf9o1XjX}0e?iy2<}P+j{eCHFeT`_kSv z`c1;h*kATkkKcN+<9Em1c|P5G?NVaYr=t8kz2j!n=I4tB%$>FFNcD|(_ivKAriMNE z?37!|>`e4`8{JQkxf<)9vcJ2?`q)(pn<@W&LRgLNdAdrstL2~lcC~DNueGVyt+rOj zGKYDUn}2(G?a0iLqehM&IeFytk)MoQG;;aKwX)-kvs?1TD<1;5`PS5-#bJ1M$d8skW&NaUhFEgKNS^gQ;?`!?9lJ(s&t1nZ0k>#S_+TSkkmZ!|yor@vlKU(nX^`flea%QF$Le!AWN z+IKeE`EK#GE4O28#~aMI^@DuDaoc*<2g`%l*7JM+HQrwa3i5Qq_AINGt?xG2obl~d z^{4&C-$(UVPW{fv?AE_e&D()t5$a6g`3tLIVRZIr%bMTHYxZGF+WD|vTJyX!A|}oP z8bfQ{_BkfHW=x~z_e6-t)m!^kttIYQ8czEw*XYdAqehP(J$dx>(VvW7GgU?0X+O;n?Ggg||y2HsXa`_dReYpG5 zJ7ZyI2e&;b|F56~OT#g}`g;nm8J?^5cK_J*53d=_wd0*wd$+YxHhzDui~JF~`QfQx zq?|3o>xSh9uOs0&tR;ED>rFWJw`bRwZ~L1wvejefUjt~-^U6A}%wFASecmqyjLhtI zt@cMD#5eqUd#AE>rj=uLkGE@!xBYb*V>qjutM}xB?=16|sbbfir2bu|b}1VrzS|u7 zS=`aPG1|QFdnY?X{$5?==Wj)@x8{#8hZzjhin|wVr1o!!oYlhShrg0gzqdI2t7>PA z_vEeq+g;)KeT|Z%`|xuARm9(- z6?wiv#cKwp??_I50dv?d# zOUm|VcZkL9ygvfFo0O|r5T@7Gku%0_<8L3cJ4c;T-S|7TRayAB85^UtVQxtyS%ClCVUNG-HdcH&I-i`aO zHf|ijZ=L$TgX-mK{S=WW$9#9y-;y%&X5BpN7B8mmbn|W3>CJDurW5+c>vZ#-SImux zR;o8kqcXiHXO>1fO~<+Bmm4v6MB_`@_ThefT&f+mk1dP#Xtzgr9PSw1T@cRIslCd& zJ-W4b`&Y^;+WnOl`x!9hggwIN$DHZRFQR1*oqcHLu-S*TJKKiE=JpXRbxXXd)?Xmu z$~C^DmoY4DXUWb+m=9~$dtPv~F7A!Pt=}oto=dGJ^9b+NWehKG?KP~PSoCX=+Mo6p z7+mJ@rTl+Of!Uwe4Y^l-YI=8?jm~(1fo5pwR&0B6;dh^<+$3HJNqVct)b}!fV zPQ3cRd|~I3Uh~4=2kM*~{@zb`ZYL&xi}3G=c52_Q%+K2!;@4sLjT(D&y?XL~rj?#8 zGv61r2p>KgeHON}Sr&hf+5y3K!JKwITE=i6?8ogz{5;$|YKJqC>#y4xb>eAP)|t_M zLYdZKv(~M>egUOj-|h4LZMydntl@9pz8{tN>js&E7_ML&zSG>xIimAjw|&=SY@>uY zd+zPc+p}_~+P04MVZV82ejtV>Vf<z5ZgJ?!|$bI)tr$lLecxEr(BTf?noQ)=UVxQO&?hYiFm`_tHA7j%8{svn6r0( zwYvFq=o{-g&U)!g8+$4C zM(n*%$JACEpBJt6F=diO0ShhYBOqoOwOqNCHZ3V_2d?{cTD;}$wVrZ-J!Nat&rNg_T?UI zw^}3hwc6Ke3#ICr1v86hK9Tum?d!EAQp=@QOPyFdwYF|*cI`8%M+Vl&t(sXUv!VI5 zmE#&~Wj~dDrT$pvj|1!HHqLFH+dj8`Vg17I8&5P2${wDbF|hT(k%NomcO1Aq``hg9 z12@GVk1kT!HCJf7RZlejQ$M@$gT~H{7czZiEY|e7@@G@E@|LO3nd28yUrv23wODz9 z^0MWxr@m=^C-9Wik5a3Y*Dg;h&nW*iwRQRPJOEtDu1s0t#ViSAC-Sp9xdNj{!{t+@~h>y%T6U( zDOLt5C)fX4Uu0nC!6hrpRaUF4TUogBnab()v+L*A{B~jelKO?lep#PW|8@P=`rP`x z#_n$(e{YVB#_t+S4Q!d&KC^S?OPPH#hcpJW3uK>de5q-#W%g^7vez_r&%Tq1WFy(H z3|!b)VPMPb*4f{rE~{Nu8%ciC=YE$;Va|RA9E!0@3 zaY}W{re@WbjiO2?FLuZ_+ZtEC^TEs*}pz@Y&zc99KW#`JbD;HEQtXxw$sq)#%jPz-htzX!?Y7qq==9&K6SFs~*glngDnF~dR9U9FPxWWj zm#RzF_N;xs_E4=_->Uxo`a|_GUb zKXg?3=CqTUkzX&fUiv8W{91m!G^YzR(&2Jko(U6^z`BCPq%(jisHtx^7 zpN-^V^RCai+|>iM+!}?)Yv-gdOutpQAoHEZNcQpQtF>op&)1e~{5*4YW`oj3r7MQE zDV#GjYTk{*?jH);g@s=ft|{2^8#A|L&dUuBzfyS6v^l!-bl6a-uv&3e;X8#F4gbl-(~GwZ z{h+W<;j4wi3dhWg|Bm4shgU3pvb6s28pAtzdS7aIq2dz7<%+Kjy)g9q!qTNSWPGmRxY%&Rq4Yuuf=!6*;gtiEmi&h!rT z-=%+_ek#3H{jcd)(r=}=ukTt{$(HpU>buo9uWx7WM*f{%qP|>x)%x1?rRyu!*Ql>o zk7qWjpEcasP8$C1@JYj`5C5sSoF@v~`{aGLwAu&4+k0edCe|&kFg(pXXB4+6Ze#57 z;x$X12 z=J(1!l>0+&zrjD}zBKr^+{?K)bMNP(`E0&4&u$*PYw+g5dj}sGJZJEagMTsUmk0kj z`2JvQ=wg#j4qY*L?O<`JKJ>kzGlpgjEjYCJ&?kmg9f}OEGqmB*0r^AoXAH`Y&d(W| zGqh9Ti-pbdoBOQywVgjTpB{4Ucjmlt_3+P!pZA@`C)dvz`E&9Y=dZ}m$={N{D}PV( zuYq31&4)K0-lJoGiwqZ9%3m$MS$w}3Eq$c)(Mg}>b{%eSdyJJGQ9P<820My-hd)f) ztn|q6cx<~#&zBvy^!iyQ=ix+H2wc)IQWlthT_1YPk<}^y>V>9sdHg|K6E4yr&OBVdLQp zSH*uX_rtu>tMBWgvaj_8?cly6`wlhsjh2#NP2qDAKQf=ZIwY}g;>+ffScfO}OdM#? z_YxEU-SNBzSa-D{TFhM>9h9Tc`2LIi$AvS-PqNMISD5|C-JMqTd|j8v-`5~llrbt zJQwSaU!HhBmWsa^dolJ}?D)R7%qQ<&HffbVACtWs`$3;;wYZzMDSuu(?!~ouAzn82 z{XVQmZ}~v{WAO#& z^3MQ$R?~krvw2o&i*0$(Z=RJ+&&g&Ovq$-p%qK}PrToud_bnU$ zbzdjzR^F-YulsK7$n9-=TFTm1*{!mV^abs=eO{Z}H@EK=V=KjPG5M>;?=w%Cyy~qH zf3R7uI=A%Q*|)s;^sVeRle(qvuC&We4IR%;ot^q|>J0PTHrvhCihsDaZhYPN8%Z7C zN{*WUNa(jzb|~k!t@GG+`2}*a4dNTb?@e!-ZD(s0)+p%t=e`&FnMEUhaFM&*^{4JY^||r_=vd-$v$>&Ydmg_{+ucR-d(L@ox4;pTCA}`Id>e-#p^Y znELzQ?K?NMU1sad`^I~p&-Xpo*Y2tI@AkdXm&imjTV!_3?vULjtK(+5Et_^lYO8p; zzt&%Fn)S-LA|`CR7bsf$v2hSi_Hc{VEbDrT?$L0+Y{hSvx4gZPTn zrDok|YyI}QZE{NgF#m(Rea_9?nd$VrGk;rN&+E+Jv^qT(GVjB^Q~qapZuQQp_nCD* z)<1sBI$39l{(+_qH;-9o!T!nHBK=us@8p#!@qfSi{pw|vg7dLdH~W09eT}92TkXs| zd8?YTWt-(|^e>UxIk#JG=Ul<@+gkk-F_(kZEA=nm@8)?^U&vyYSAI~PR*-FA?8~|R zlV8p5XKW9Tty{46mE`Pd+1WGqwdBp^ZTokaXWRDoW*Zf(9h?kn@uK;*h1dR_mhF+< zC%ad6_nd1tl;f#Z+q{3%{*nHT`ghIjnt8s-{{<7*j$;-EHvQ zshV>`>UXJ|&2u6)Gb_6z)!BZN3bUH|e<8FVHUC|BqIOTAyFHqkfA(-H%)Xe>ciG$7 zQ~6f=bAGb+NIq!K<)6zxX6%Xli}~mCrHHi$8$nyU&uiUYBL5-%hxC)iUk-P*6+ zz!vKZw{GoMDtEGP+n;=COY_fKtGyk;-mAUWb^SN0b+#4F-|#zG+rY*OE-~LTlbMeY zhFZ7wx8`om-PE*ObANPNty}w*`?hX$vTp4kX*|+cug^Uyr5tPB+IK2nB(;dS<(<5V zr}Z1LIRGo~8lRIB}}GOJnUGR&#F=|!B6IoI{yZR}&t@B01r zF;k`->;0uJ3bwSZPR`moVz|LDU1#j>=JC4ztqRJ$yZ@dh|2@Xv+)OFgn(Ev11N{$} zG>lsnXnjY2tNo_`ej~gzTQcC}^U-oD-ciV!kE&uRXO>f>3&g^{iLyCME`{ssZoXJ|DC|&B&a3^c=GG*&W5I8SHZG|4Mf;-5I?1TtY>xH*QWu4n zdvlj{mUYg^{y5tgeWyQW`g*6I9))72XC2?^f3IKlTzjYgoj^`;8lbvM=St){rbYAUal1KvM2OO$@xMD%Rx@umq8<6lkQUz?^J*M4Tc;Sw~J zisNZtO}EXe&MMK#*}|s%iqVBVws>?^2U{Sz<~&;^x_Wd`k1cG{OGTFpv1Ovm%ww=j zpz;gs8h^)Y=-(W+sO9qt@1G zM)c`ut0|@#(HYUJD_2)+d=vFMrewP`k4mlOkmJpBOT$vOzV*AL-bu|Y%q*pRnH;tNVzjW&F=DC(*+ma{LF7visKFyit+-iOc#+vY& z>2)SxtDA36Zsf>5oes10(=tkaVZM3kwGqc_yQf|IOfx+_9kdxH=kvyPPVbrCCcULe zZEsR%XE${=b#_a)n)0okn{72)CVxo!ko24Bx6_BG|B*h-q>oB}C;iRz_nNkEdUNO7 z=~mm^aqR^2P0;a}+mcjk+XK>P6x>>ylselXQNJA)^_#bJD`zXmTPo}=S6Vf^&tSQ? zz0$#QFAn2x-=0|9@&gR_0mk+n>myjcuPL!*irZhlmE$kBak>1I+je459k={I)Av@+ z-kGm7?cBn)&Pi45n^D*9jUJiV!P&u?6~8xX?V;#jq7Oy?6#YZ=#Q13RIP*(gvQhK< zVA%c9XQKBRZrtX^g8uKJEnH+wVM&i)a_-i)4?J}-T&`EK8A^KXx_Q*#%aZyLy+DemHQ zvc+Pu%hJEhUsS->Esxem>tArNE92NT<~Pi&tq@xw_K7jOHZQwso(-0EuV8;I%l54N zt^7B0ytaz{x+*)Sf$iaJ7qfPC`s(yv&Uo!}u`t`m>DBH}kKgulY@3IAZ2eGrKPTLN zZ@$mft9{jJwVBQfiDweQ=QD}FnA~2T&zO4t_T<=Hi~f>WHoI(grZdxdKl#4-MY%hZ zFC|_{ES>$jV=a=LnB89#!x2v4<*@sL*ONNJxi5KN^1%-FOnQ8FU`2McV=b4Qs4bUU zF83|{4BRB_Th0sVc6OX2d&PY3ud}V1rCffN6SS|DI@{4H>_jKro-cK_tIV$@x^}V? zZa7gGecjOEE=HczE8>u-yR-)(DK!(dz6+QPwj(wWYtQ7o9! z(X|_6H^y$sd?qKZ#geNfS8hH>vLo3wbF1f;Ok$r*%C<;uZGMgNG-tcy=aOGC_Sxiy z$@S(vKb8DcawlWEHjg`*dOIaINp5U%Pjj#bV^75%jNO)bFm{GRTG)L)WqyP6k=SD< zC(J9)n{ToF8O|BbeX&Ioizn7htdm&4_{9@vJF!G^%wma{!9Q-X+taddrT!EDbL`Kt zvz-}HE!ZYWhtaz1w=3_O^D$ zYd?3q$fniWrpM#g%lzC?+n+n~99>UIFfz-pNZe>{&MM!I&* zIqiD1jNv}mkC%_}kFTFga+l=7qIG%0Q$)9#Z|!c$-IpOwvrk&m3P;!Iw zT;{pV4NkZ{ke#Ug*8GC)&CYMKvfquFo4(n>RN|Hk-O)5#es`AC!`X+k_k`G^+3xlm z=Qoa9OQ_ZEtM+DhICnU`)pTo3q>WmuUHjfzOQ;`ye8~JZmMpx~&HYa{-0pV5^TTs{ ztxdgdweNO1*HHOnE%ZY<;UCrUVw+U>b8d$9Uo_1MO-ji;T< z&99P#+3FGO_qp-dy}5gH4;i~R_pI}*bARss+@FfrU!8DUE8E$ASMb^+)%NyS^>2=~ z;~W1ef3$R8{=WPRxxeJ}{7ddhkA1wfWJ%A(ns$5T*2>=I-=?yCILu}1o{`OfyQTqk?Sc{?{5d&kM;BTakH zk$=yzMs8%DDBm+RW!8ttbzWU>ndSR;PG(UwZ(bPr%$8W6&bwC37foGTg8xXq)mA92 zQ2LL9xupx`Wx^cY5}UGZ z%NMYBtBXd$Y}G<{TRhU(!6qjn+GR0P-4!o-u zTW!svYcqy@yL1Ae{I+NBwh z8IcW3ooq&=^IzNjrJF@s?MtOz?Te+)mh|-6mXYmByPBL`n@4Yn>bjNb(f>X+5GiMV!*`Ckg1?9kGorEipuEgjjkV@umd{C0e)n_W{rsdSxrVzW!K zlS+T7zfj*fvUB8!@fKrTwR!Ft8K2!& zx~(*~bYtn3(o;=)tn^svKJ&E4KbM{;Jy`m3YyB!#jy<2+UW6hsk;m23H9uJ8e5@~)tzw92fP_9A^5RtrH@$u+rAN9m}${$|pp2uIy3X+5BF9t0{kv^5-k9 z_LBL1dwM$|vRh@hK#eb$HeV>~xLakfa$%sIS%%5`YGwR3t9*Fnu*&~L+S#|v|9A`9 zaVJ8Udf9erj zB{^>UiKYHk`B!ts+qJIvE_GvXcA2-Nisq@WF_Dun|Ig;~NZ6k-($#v?E{}xU9ktH( z(Q242R2?+7kg+9=eYComv4yH1ss1Vww2xQEXIDqCH|uZK)l$BbsdlIG)vDI!M8a&f z>dN!M!kE2zE13VXD*I$x+oby0>K4X6Tix2&deu)=|5bmxX&cn8k6a(wu-a5nBy^Fjl;!J?sp_{|BYyk2c^&xk@@ZqQ5U())it?4sqtcg__c#9? zw$*m6?p@VWN7uem{bJSqB?nTSe(m6{$X$_XHESa^;hdA0^Vte#4CG5>9O$J!pXy#n_8h~Mn*j0)YOxnn0S?vpIMt}{@=7xxrUC`_G{*Wj-D5v zZS~cf*Qn*@SPs8Gt=8TC6lq`Qdo$b2Xc*iN8}%o$7?}*wB|L{@!Qk2 z*Ny$P_G<0TNSOVt)@t5*@6;w^Z%1NvYyYVw=cR34tlk%5Zt1@w=1-)PuzyE7f4bCP z+A#l12OIlitocK$emiFsW2@Jfs++IEx7c##f8_)%+P9Rc?OL?S(&<-t+%mTZ^4719 z*AjhRn_lm3{$GIlOdTV4_j)IrQQz6vj4>( ztPeKYn_U9E=^(zzTBYyH_1>(~7iRm`!_98n@KQI|*0bI%aZ|QT-pwWDEek6T))x-8 znFv0hepLOC`hoRt8#~NA2mAbXc)iuUHU6jGYA4i#_L07D`(FLyjq%$;eX@@G4Y;;K z-y#F9{Xf>u2EMAJ%>Q#k-bezu34u^Wy)9vjEoxfPVx?|E!b?g5DG6^CB?$>hNJ!GW z&_G#D6)oLG#Y$VYqDDorWmi^NjVrEQMMcFG7484~JTr67$t!{U z?|goDe&?BIo|!Xe&YU^VId^UWe5kbom4rEj-8}P!&c@*UFO1moc0%hTF|T#wakzIQ z*|)N>tas&)m3r;8b@?`|*7&vgug`xiVO{?Gq_IM{a@(i!ZTM)ugb(I_Si@aOK71m7 zc<^b5^AG1gGc4SlG+cHq$v5(k4GMQBMYq3^{{>1pLpYiL6~f&~!^6Mi4-a3;A1hcJ z=ktG<|C2F-tV$OKyJB6qJrXNo4ZBc&>&%j*iG;E0CTUBOmL&aW{^(&z(ti(0wcGYv zat{vA=8qQ2lExEc!O&ml|D0fE{xaV!aXgbhK$!W*{NLwa&j0fWp*-o2`Q=HM!NkMZ zZx4s5E0b&(w5ZkaWv)h*`24rc94)L$8c%r1%<+WPNuz~zNfQel`Glm=!$hp#%=(G{ zlQI7A+N9y(Y}|&P+`*wMuQq>Zczx2u!>h7J3ca}!YLjY{8mC@=kbDyjWtrC#>XU|s z^2{3#jY*A3Z_6ET*pf6-_z3^*exqS)($=Jl@#aa*lX@mSl+`=wMnVs{2ZtW4Nob$+ ztN7Eoy_0^K{_FJCNv)GE#=n~T)!c_B4GvPK}Y19aG+z{x?%TH%&sg z>d=j`jmZ+ya(vj3Jn;}+hOJKR+fpX--ICmpJW(`YLqb#XrpX7g4`ja&+=xxd=OJsH zL_@gViDl6=;X~8crmjuBKlSnC&8eFRHK|`t{&Mo)1mW?F=G6BmKb*QN^`DZPQx7H| zOnyB12w`pN@#N1Xzb^G1$!{e*8iYNL^(CK5{#x=s6M9nrA^9W8ovH1qt*LKF-JkqW z>O-mjh=tzNUX35aqJ&Q;zc=~a$vZROo$=m`{VsH6+OR$IP}YaC9-Xph%C^isd`pn6 zJySX||CIcv#nc zf3K-mlHaFsEaj$@52Q+ZvdcdMo{_?zo@@9A{^$H-S?`|mWad+ZeVOlc;i=3gU3fc^ z{ZkH4{lwG{WzWcwa47Xdsk2gE6oe0@9wK}w^+hQkPaQeTO|ju)sl&r9DPi#Is`&W! zl=%d^bw|qW%5Eo?Akt5!elpc_pJ#9^tF_qmT8^f^G(`{%V#V9@c5cV2l^w|#8s3vR za`=4eT`8YW{e0@(DR&V(3%5nKB&9^tM8j%%UD3DvZuA5`oJhTgt$R}L3G&z!Yr&Re zxh>g$M@tTMJsTc>(be6TD;mP@O1V4bi>Y6vPTun1*jtix(T~PHZE$S&RIHCIw^Feq zVX)57t)VuCreAw|q;f)8k(S?|IeI8d`E*8EN*GqBtV$7tlCqSqrbf5QQofegj~GVF z?X^cs_wsY8V~56+#uTsd(ahoD2dO_u-IDVC)M(h6vNdH3p~D5y5&k39m6R3)+1c49VN*g)&^r7)@sr8$%a3S?)soSahFJMyZ3o5^qdOYKJ#%D5zhGQyu|CHBH zeM`#t!tRu|X%cp)3=Ut)dwa@LDQ_p(w5Qm5VA=!I`cwMR+^5>|?Gfg-X?}aSWl7oR zEO;%6|BxEp3QMq3u@lORU@D!_d;lyFGM$ zr0d-dS4XnzF8S?i*%`XR(olU#m$jNk3%(q0$LEjAqx>W-E$b$E{qeSs)f;>)W$W6< zXzUWihF#q$TnlRGw$%|kR>#+6Y|DdFy$xTQPZjyZgRHSNu@F5c#^xiJ^Gu2jpUjr< zmAq*9){Jk>xIO(2!aanSrq3Ax=XE`)=sHqE*O&5ZQAOom=Ht=w`}FINzn(h2@O0|L z!?#mM4*xoeT(pPJmIh1wyyQmXtEm$UxmoW_|GV_v>2FVeOL~sHRyia*iFBf2U;4iE z{In0Je>D9Q>EB8Fue6it-%EQ>`cvtG52p7kgnu{f6Dsp*5`QZF3+cxQFGyP-2~}z1 z3klX5dtO>`S}7}?t%-!nwDAR-|J7;Jv%Z`*@z9#ZguB_~#@qN}qVRCH)qxSjhMAFf?6qgqqv(w&jiV6eTJf zt>27Sekj+5`*H_|c~f4VHCFh~^y>-d(H4v+j8*E(vxfGM>)U?Cl-EuEYZqRn@qPNe zaPqRrD}r#}5=p>^`aLi^;2 zh2F_G9y%v?PJU1WLE{o=EwU_YH3SU%w9Uc;g$*C(HUgk!=_E$qD$|vePrJ zPPQQv_E5HjtCOFboX%^F4`=Tsh~$avLCe#)#c1*}^5jv0hRCu(y6~;oe1d!u#6mRv zM)=@=lNj&+OAO96eCyhF#`~`lqv^dYW3(_YxEWy9pwwc1~q<=1Q#uj?i9d+;2geK_&-!H6d#8*P?EmBN z4>`l0&3z{GXx89xaLQ|^9-Lys`-ueyr+h4XQSPGLf1KjOr>7j5@{OrBe0kazv%fs; zYVOtCpJ!e>JfGKEJ-!wHX8fz!C$fK;Id=GU=ETC~%*!KM_yir>vV8bi z*5{^-9R6vDJhVBSg{2Hn`z_^42y1_1?EkWS_(PTiza{bUDPeeKYBYQ|{@wV~*%Gd1 zO)T8l`s87*Yt0L-t9HKaIKG^|e!{O}(D*Z&Pjf_iP{hn$R~I`*omi zG=AySiG;aRZ@-}smU-9I(Zl?ygTozD@1FXj?C)p)Ec;xx6=$h2!Q%hVN zN+fmc5M7V@M)>vr3S)4Nw@e*7`1SNhi~Xo(PD6?F)t;Bkzt#4a2MhXvM z!TP`7l^upRp!=@uM@9&-oLJ6Z;(v#?k#LsoZB*OIWsnqENAZK zrHhsM@36N@Ukvc7ktmp z`R2555xyCO?@as7w4dkwkZ?ZF_ZJ^0#h=T5PJ5oL+Wx&6`aSKt(|(!vOIB(h4xjHv z<8=D*;1F68mP5#ozhD9(Uu{@BmOn54<7oo~vC4vA!@~be3xi+3{6^z&CGzpH*Tf|h z>vw6qG`@6#LDo7SDOAPpjjxZd88K}n{n2DOOb1%x4e^oC6#w7&1`T!b|D85CY>aP= z*TvgL%r}y)(PWdRo9Tj7!jEVC@3aS5uYJb^g5)15JQ@!}U)+Z`$0ht%e9xd&-lHqN zd;Zq=@DN(OHXFVU{Pjt$wF>&R(!b``G5_8u>zVuX(cY(x3CG zYlP1XN z=SIWj90}uJ?R#WRoo32Z^9I9hxg&*_1kzh`B|P5+;Wy{LFt>m(ot3%^b7vB64YWtH zHC!gveF-nmomhBPu7p==@RnZbY>Hgq<<}Qmt3JC$OSZ#aajRa;hZ-RnpX&N05#i$~YmGi|)#(P@uHbUl~Y z!&`bh(6cFC*QZBgu^NVG%1Aua4B1F}Ru<|EW-pxn!s(;u8gI(2({Co+IxN)ZONd&z zbwZ`xI(@Lcuyvzlc<$@uYbN_Db(HkSraeyBKSP*oKR&H+`b#v`)>*!X?~j#u`=iIU z_8bvYms|Bn(fx(KSqbz9;ja%-@&)s~NwW7KYzU3qvR! ziM?uiOjisaysG&1Y`rvZV!^M*eWUR`dH3X%u}b#DLK!y7urxH3jj)Dw$92i<+2_y0 z=y~V4qzyj5>^U}49)C95JYu0RIA7mA``ysKJ|ruVUHtdlr)`hjcwJIT>e(my`^vn~u>&-i+`{c6NMJ{_!2>?LEz zel_A7jW4kh@mS#((FPpy>=`sk(!x5*R@E)?`!89TVu45m`Kt&6$F?A>5YQAX=DpKeT!>1_|UJe%5gQ(wAS50Xr}SwNghd{f^flhv1GZZUK8 zyV`6w51Ee$2O_)4B%2IgD2SWs@aLHqnc1emJZhfo8&MvSitf#-eK-2=G=Fd2Yx+k_ zFEmk&4AYBVhFML?cbjeGxS!Gw_QlOc>hYewY_kcgkM_+rjb@gakH#$1!t0Ya_1$J} zH}lL(`krs@@5{i#qu@y}oqAJiVc;g@DYR0q$ul#|i$mU*BfKw19>F_U3t6Mq8Rv&_oAyUdEdmzg_Em3-5NX?>4U*GKx~STy7vay3@E1h* ziy}M`;kQKi>BJ@IKtl);ct%cT@n742!CsYKN8`)BmB__|GNm^6X9=Ho{;axcPQ7d z#=Q~#&Io@j!rv9)k4N|u5&mR^?~m}mkMO4={6K`iFT&p+;UA3fgAx9r2>)<|eW zMfgV}{2x3YFpVFJ@WY;h%}{&qnyM2>)D!e?G#G zNB9>b{7Vu3jPR#Dryc$!!cRr`*CYHJ5&q2xKkYg8za8Oc zBK%)Hr>uXA@Us#A?-BkV5q>Vh|1-kB7vbNJ@beM=UlIO;2>)S(4@CHnBK*H2{KuZN zj~6^=Uw#td{}bUqjqqn9{C^|-XA%DM2)`KNzliW(M)2_V*%eE;il5b`%;aU>psr5_Th4THLvck<8B|V{EYS=;nX?H^c^)B*Zv@|ms&LE37gl|!OCqNlH;LG<<6#ZXH&Ve8S=`Qa%bQ3V#>0dwq+kZm;H_B zgk>prWhr-MDR(w4w{|=iJK4FR9p%oBa%V@mvtzln^P*{CUga*Ya+g=R+h5D=aa8VX zdM^8GdBnauzO(bfvXndf%AFn0#g66Hj_0z!1=B-2p4Za%9L^`$L}z1iB4K5rbK9O1D6mCt-$Sgvwcu5xEnxwC1xwc~jb z_LV#PR&MQQy#V{}ybJjpllwv^Pnn(Mc_QWIj-N^se$!uB9lhQ;uGhOj&bWOmI_^5+ zxn2tbd8O6SKFOFba^-W3nG5HFli2;vkoSEhX5}*jd5kuX$@~F*;Yks$a|5+Q-ZaVhXc7W#jaeDR|Y)EamH}uMXH|)&on2L+qs9$8_Ywr z4(Q8u)^Tr#J~Pks6{uWzQeQ!i+pnU;kxi~X=|$2eF|8-wmzwbqY&_fxk&>X;pOmG zj>zL859)ANL?_?_#soYO5BWgA`xo~;Ci1|}0<}Ybpgxw{b`JQFh#dQYoO^+QQ&zx_ zL^$Po`Kpjh9VS&$uImHSg!}m(oVq2aaC}vcPK^1R=SdNs0>3F@$K2=JgyRzM;#iXK z7*lQfu;nMxk|R7V!lOEqk;hh%SFabGU#sCdmi{P~B;4Cn?rb`)HXT=+j*HF4HRPqa z^^=s8ldLw2je#Re*7L=2c@m&<#{Z;2ywb|E7>DCdNBeM;7jeI)HaVt@w*jZ02Ry<3 zT~baWlGpMY?(fJ;`)4QTa(`#J-cLEM*Q`L!I4~)qFNOSY$nEtpN$zVnb{tdkT7FlAFI6trN_*W* z3h&d=*K6fG&Qmxw3G7%d*Iz5w>*kBK{#=hJ%W>&@HwkxrfGer?Pwj^R$4B2WhZV&@eR{>s5Ts3&sA8IvPA0Uuxt z59AS@0p)=mbOJjIR6p5{;XZG|G_Fu?^s^?Sb6c_=N4?&ywLC-G6V7+C@LZ8|yfTu1 z?D#3=GrTqZoj2ylym4)++Ru@>U%&?9m8JC&Nz&-+w1IL@wteH4Hdy6>!=o;IvP`X`g@} ziSXj2P@aejw`0P0)uxUE3mFHHD=)H~eYEpuDDO3J*++Cdk43mKRY@w>`_0)g&tqnGY{p-^ymAgY z9*c03Rh6W2$(!Z$;W2nhk;^ORb+P410YAm{_s1L^M%wF`( zoW4n03jQjloOxFUeeaQb?sexBb^?waIQ9#~ClGQg$0l;@qXTE$*k#^k^HRM5&(X2m z&V>>&(Xo6WF5KG>d2wv7*wJ(0T_)r|rX7&G^K|cP;K}&avl6jK{`y{R6WS`a7j9%e z$$mYy2(E27U_8&JK97}Jx%6Al1fqd_4LY_SNL?BO(@aJbCx7ViFy6lj@E*|pQoRBxoqQ>T*vU)=K1%b1DE@tM(KbYVEN#mPZ&2IDtGn2_4&wMJ9sYhcI8fAdA)5P ztFt$$&g;1Ps9brG&8xgJ!XJ+CBLNq`Q<%3nCY&nM53P>nUdQgQ>Z>nwiOrkbr#^Wr zr~k0;o{PU1zh6SyMD8i@?IdUp?DLM$a^-yOjWw1>ctwP7g}XLvY>V)%Nn%Gojcp;% zy*ES4`bzR|W1jygc~X*DV{S&7ayzI)lH=U>CF9l5W2evKlj%$4!cXm{V z`WSrjo)^vWociDcw{p3TTW;H-)MUPhvYZ{^zTHAzqLk1Oa0ivxz82f$rEz**W-f!IgWog=nwdTL;K9u zgR<_3@K;9oT_Jzzt3p1l63#w~Uy(6T?AYfZsY!0^sx(Gtf_>{>*P3 zm+OActF2t;t_$IPvX2AC2sbgSe-E7bMiO)2loGhMGxOmkBDeG57cUFt%5D3{UR;J; z+ik#Xn^P3@;gEmU%k>yBw+Zx_O9W#`+pH7FIR|-W%{Y8Vf;zbO1RS4Z8t=oC9hX)y z=7sCvuAeJ+ePhacf(wt+8m{*Re0uQ~bt8d0%P@`>33H>az@yE2nNXQU~{}M>sF;%k!X|*Js?}k44T# z;r5<|>)oApfAu|zJEbhCCvE8D`mRNw!}TkWhkTA)o1A>MTss2JbHjjhzTD~k%)%4e zZa2&M#SR6}=FkbwHRaaFDEgtC!>H%rO)s|g^&OSl#J<#D&%ryT$>dz-SrWWY=bXY5 z{us^k`Y6Krw#UeEZFAwiodZrgzcf;xmqmD?+APpx4acVCuZYNB8Igxvo@KawXYT@z zg^^Y}gYdi}U^ z+vakwcPICf$%cEtw^gYQeR6;{c~fv+Fb)*iKEvENCFIO?i^!?x1!F>>6LK9lR4&gu z7zc_BANM{|k?&(FcjKXQH@9^9YCquk0hGHw!+h11J6qlb3OEjufb)(`P?mBx|K$Cd zK(5@456Yc=-hm11@a~G#U+WX{ni%hp6d6~4yG_jJN-zdCB>cerw8{`P>@P1`5EGpx_lp`81psnkd1a2cO(is&fUdnhM& z`d+T%d6$-D+a%<1(;e2~jvil!+2)RIA%8`$)}MM78R52X&o(dL9`ZYPz}=idxjUvW zdnnW~J4MI#2gVS0to2!&<2s&%I)8(XpF`f2A#$mIA--0}2MRgIg(r)j1mB}_nO}J> z=RUs2KnGu+a_0|pyf}93!6N0-XTC5ZFA^U`pu;&{9Gv3;*Yh`!b6z{H_oRWGYkeTc zr%`O&HB`ClZ_2f;j>tGr?E9hes9bqvjC0x9)OYOy&UqJb?g5L9)i=x~0=ehe_#C*; z3d&Nh`g$)G=yN`b9ov@zUc_@iYg76vb9h%)jl7FeoCxO$PM(l?La{&BIA=qfca6y9 zn(lN4;+&^p-pz1dpMXEi^~KAJW1L@Fe|PSC^e1a#zog7ume7ERp+bsQKHlKCk{e z&--GQ+c8tQ@-0iz^cT6p}$8_P|u%4dFImK8P*bg~l-CY^3KkJz0_&_0J zm-Yu4yLdiQ9NcTH6mIV|%sZ`4-1M1{KOEtYMEH>izZ7zLFV5SM=X##Yb3M;_w)NPX z?$!Dj>SNyA7wilETjcgQG9FgiW2F8-$8|gmd#DT(8Ts&DzI8xpLQ+gvW)`=2mXoQ@Pt;z5Hw5g?-m= zmAg79cV&gV$OzYR>Hk)4%T@0Bw&&t+R9@Pr_t#c#`@HAkuNIC?oj>2SkNRl+=??*? z-5y8o=D_zq0oS@!8s%<(gkU{nLpo0pGlVSU*)b``l`#TbLsp1v1ZO3*kL{#aIVFH zKJQ}(a^=pxa%Z1+qyru0PABA*G38F5>-&ASJrnXA!SSL9*XJ5R9q`jS`|7{F&-Po# z>t)P$T+8hfzb-ayKMADNM<>b^M;ClVKFUi+g6W2|!byDi~9Z~A+~x@~%&%C!!{y-nrLrgAq{JAJJ~$d8)ze)7_pWWSWV z{Z;Ocg>u*aA)jsaRnB!v?6~^3zaOsW?-NG3+h66beJr=_Bi!%f$`6p&9XsW&KFXaP z`q5BdxzjQK;N=5`#Wb9K_~!KcICO5T@Vr>wpK# z+jF+i{DX4(&p_d)KTvcZy;=JbbFIMsuG{;9I`b?(7}L`GL(Vm5l|Np}UHe#W+Xvsy zD$2!vP0T#s^MpM6b9r^FUM1tU8>?3tH*WKr6y(^kzfVyvze(X)+bYH%t+Q~|k@4p? zZ=ZK#0#3OvvGP>u?1jn;44iS;ztQ^( zE9Y9ncqsc$S=^uQgKOS7GM8{|k}z*L40nA)x$FPRT^)qe$Jk$|@A}5vfAltIn=K!Q zYu>lUl)Jnkck-G(y|$`cZT4AxcYdkd9ShIpdTKexg8fo1V~gXq|L=;u`G~J)krD2X zi<9g4^QKQCcXdW!cEb$e?}xz^2bXGi3= zZhcnA*-?ENW3j0`YSaCWtm~M!|AbLqFUQ((cYIau_E9-?mfvPtx!p(Mejjr`hfS%2 zoP&%NTK@uU->PVZNgs~=mrJJ*!Eb4|JHC(2#BDR+HFxobDeZCiOR_aMT3yDk0aus$Jw zvk7@g%zV|>a}wt@@0n{~()Y~oQqH)6wSW&qcwFAKc4G_vD98Kdw=<>Ij^^$1I@tMY zMDDo0Pwu$BPww~>DOWh}lbdATCwF{Ggd>mho~pLFzNdN@T*tbBLbJg0cp=xIRsI^p zvk$oQA#{a0xkup~JGFCC<@nXvU&qD28sUX`5qZwn#HM{V-TR3my>>`{R_^-4c9q-l zQ@J~i`#*)gJH8(nkypn4=`-lKc@*!DS2b&VwgJ#l)Ldkxzktfj)n4~J{>=;+#Z+AQ@#$fP4U;^&W>`oU&@_L;l4grZm&nmU0Ie} z`%d3pPrnhCWlqD@=72G0JWt5^>*RV~D|hEO?M6G;^IEw($Gx0mogw;ij0!`}Ieu3} zzF;_KEcz7hkhtUWW9pzfw0XRcbJ^8_{uA=Tyl*;vo~zFAJd3=ieO}6a#&hZu@Q8d> zgqwjQUPtQV`H3?4x4a$n9ao)iN92x+Jm)*e-8l2u$$Pc_j01(N3sFn^uwOOes}Zi( z8lFo!dBX5p>{>mqxpwos!*Z?{A=h)EHsQ_%=A2GP=b4VrG5FF0Ide;~FULjhyB#l5 zZtu+t<=hF%;(Q76hMe~#Mb5lJ?y0#KuJwIYxw{T3cjpNAdVvn-m+qtfZuc3>r9Mgj z3U}92<^CD5$o;tYZ>E--({AVsN1j5PY&(mNJ6}APcWafq`Y6}DMONFR9W znixlOlYIy2o#L+xI6l=5qx+@r-*))@LSML^n_NSkjy|spc)@h!uJ0*#?Sub6kaKMf z_{}rnu1$DXGq6KFUAcN6>Ns^SRJlE8LoV+Ei4O7s@gH{h{=@rhflaQVj_WnlabB2g z_ww2DJkiStrar)qxN<9p&y)967(;@( zgf0NhAxlFq@OqfS6z?~iCt}Ny5y!Kq4=_q&OhLziKL%ADo z-}95urgCRfxvQse>ZaEbmAkT(JNs5{?K^$F7QFL+Li@^{edYCi+CIwNIj-Ewohf!n&D1hWx#M3hSfX z)knFjk8;xdqjTZi$5%Kc@yRZaW3Fy03HNM8+flsg^a-p>2~>~-E6Q?C8fajjdQmAkP>b@Vto9kI!{Byw-_ zz+ZeFW}A?|Il@a~sn2O}0SJJXz!g(r-(+wSJkoa zFbj9>K>rMMl)H9jZV<>nk`^1x-T9?*_bgbsZNr%5b}Ulvjz!4lm_zBIP379(p0ILv zTvYCki|}}a8`lq2$BieJ(+|0KcKUi8(xotP)Zoe$I`z0KG-LH>jQ?A>ukk1hx zm#Z6^Co`0*-}o8J4Za%sv&wbM|8_*4lIije82YN`(r*L(r!wL8Iv#r}4(EPW)(vH{`om$I(~83eEd|C8F;kGeEC~{I|$$Uc9Yq2rpes& z?@i{r;6z0CQ>1l}_W0Q*^99oGgJ*xI$sB;+{~t}Jr@L$ZD=Fi->-nH=t0>Sf2X{)d8Y;NdchVZMyrkHZuzTRy9@9Adq@Tq3=u77DZapEsvqZ@fW zI-AkC|7f#$)n}T`uZa6T+iW&|x!Jtsi_NC`Tg~R9@HJm)Hd)}6KddurPdA%Y8O`SO zv1aog(*6xw$H?>CGtK5F;57IW=tOT3N1(yf@-H9>Q^t{KV7r#Momf7NowXfJ4O=+^ z#yr^GSub&G9j=7#&gM-Vlh*e3E=lZaXzOlh+oXD;BcC5nZ8p=go6QFgY%vAI+rV-5 z=flJ!_3`nvan_~7<`I|wC-u$deYMTz%*JN(nVM$vTekm)_$|PIWVX9DH=D+~X7d!d zcT=;OGpD$`thmZ_w70iP9p}uctnH-kWnHV<+u0w#EotQ|ONz^-kCm)0Ev_z>c%u^1 zgjbhUEWUr`ip3k3l$9^8+E`jfA8csbDBUmex$?%y#>g~9KEsnzCJp|C8crSxhB8qw zlZHyeZB5tB5y}nJd@-03YkctuzD6@Yn%tWW(vv1Jy>OqDk%tyd9U&<-Z3N*^k+awYD%2;FV8)fjqFALMP;cb7KVR1WuS>AO-kagbkft&Vvmx4 zeb^jmZ#M6JfH47MKSBDJ=bn2+uxMquS+r`AsVH7zR+N>Ps@1DZk~8b$uAYvLR>p+3 z?%LMU+HOW=V@i5DIgK`LuV@&uUE9Gpy`*?`d9|rrwRrLBRV$5tk!NF=Psc-Vqq4Q9 zv$nO%EM~z%PAOBos)8e6bai?efS#rO;Z**<+KnpdUdsu*1FwvZG~?|f9n>2?pE?q z_pUbTMg6{M50r|IeDtEjgLQyE2Gf9o-#UO;0_b{2tni zT`)ac>r4;!dUhDIjcda;+IU;TCeUHFQNL~Ut8H61n{BkqHU|7{9N=v|ZRSDt?ZMgx z&_Vk!uSi7auf- zLH|7m%^`3E9FrK?DdMBV=ZFWuv)~xpSBTAP4w`fj2Q$HOxgSW6X*cF zpbrd?wwHJxxB%}bJ_L?{qu@Ar7WqYR37lv90=NvnOneoXQtHHZ7I7Y!1q#4CFdtkc zt%!ITs07u(+;-5^6Ssn7_)g+oU=P>_4uFH;FgOa1ffFDd-801JKoAw)e?4aX;}Pa0K+Ry$hUzp8@B<0N9Oe54Zw1%jjG1ePAYhKk)(34;HXp1P;Ov zfy3YkI0{;kcY|Z_J!l2p;2iQ@#OH|zzybIL;={zx5+5hNNPG#Lfu92dk_Ij# zyFzU4rB8r3mny;ikiK5z&e z1;@Z?a1LAqS3n^);wz~GNPzib6Rd+*zU@iVO}vopB2WqrvV9Dk1n0np+IO30iI{aRHbMn%G`O z+)CU;+(EpT_yE{RJ&q7}BRfMp0D9q9C5;Zda8~JXqPqrln z`@sRw4-SGu;4nA>j)G%gKl%s2CHPg4UPXBz0s4_21c$&pwhO_0umCIsMW7TMCjAIF z3QoL$_64WFF}BYTp9SZ@akdADPY_=qeimE=m%wFk1zZK@h4f2s61{ZdEN}`QC(Z+> z;j@Snpa9GT^S~M8^NAOLg`fzOg0slWiO&(A2kYP)zyQ3SxCyj^4sZckFY&X)eZ&`u zFM&Pqz2Gu@AMq991H@N}4-y{&hk=<#-N8}#F>oB504G5@^3%jw#Ak@lf^*i+FM(O`E5uhp0-pRLY=A5f2L;G_H@)A?gwFzV*)EV6%!3ya&j*F@g~UamRAg+I z6E7gHCSC_NfQ4+=6BiM;5+CJQl){&RUbf4L`-pdeO86e)y`UPtpZEai2kY2AM0^+= z0Y||xumSlA;*+2Tewz3UI1A2!^I!nflhy<-!Y_eV_!Z)-z%XA*2I-&!c{hl|^T13X z9~tZAx*>LYfgC^i)H3g@t!pv0Od4x(Jk_?;np)b5NOw)|+N*G}pD8 z=H_P8+|gp1>*3sJG&AvUZs{>wI@<8TZ8I(8Z)tBcEzK>ar3c>;_c$%gk6W6y5+iT# zB<=xSq{F#)+9a~(PSZ->*6tmql}USR^H$J?teqHnPaS-l*~&g_fTc}?bx?Q-wx@e;=Twz_c+)s(T zm3t=IxQlk}q7A#)&o1t%yE?ho>w1uF?*FjW#qsRo2BVw)(M^BpZfxOxiEY}Wo12#I zMr7Qub<oB504KpIa2lKe zXTdpe9t?mB;8}1HTmqND6>t@pJ2(fyflobU(uuP`9OQwSU>2DFo_>=cE&y}EJWvSc zg9TtAC;~@k^qW%RWuP2Xf@-i1YydUF^EsD^n?Nh*0NtP$>;!#a7uXH9oCW8=c`yJjfM>x)a0y%nSHM+Z z?xbx%I>-WXkOyXhSs(!lzy|6tmv|m11T}2WCtd&+f+A1~mVt6mPkJSBHCP8WfErK_ znm{Y)0NtP$>;!#a7uXHyX54u4w*a`Z;F0dQy0eitdupb-%{oo)t1P+5E;1tL9DDg3H9Bjz%Hz$Zsf>Yo$ zI0MdtbKpD}02jcs;3BvLE`uxJDlqeD1JJ~AN+-?&agYZ(kj*5X1rneD?7oNkf_>ls zI0z1dqu@9=2~LBv;5?Ae1>%d~GPnx5DL45wlm+s@EKmUCQ(OubgC$@oCZ_J`%z;l*G*jR*(Mc7z`jYZ1EFsSl@+@V)mQs(UhZz<23ma;EPv9%OiOR=?-IxVF>OR38;>@7oY8T-8qon@piBfSi}W!Npl zP8sQCq?b`<8MfrPK^eC0CH-E~?nS;FzMS%xQ~q+wUygh^d6vtwF3MU?S%h4;R{BrD-V-J_BDW~jm+N&J>3Un*btDr6w*sow8D=4FaGW=)dKCU}Jp4l8E z{t>9aW(D=Gpbiz(p@RBVP>%}gUO`zElvP1l6_iy$Sryc;f@4!5Wm3l#l(~ZPR#4sw z%3DD_S72`iHdc^-1^HH>w-Wo6)UguXN^~pHt)y<1lwXN{C1qElUrBkDlvhbPm6UNG zc~+69`6cxYn`?WRA+SvySE08G+pEy4LZ^y$s-iAc?0*&dRoJh>eiikpqAyfYP8H=; zQI9I}S5a0KHmcaCD)y&}vZ|wg%Z6Z0_Zp-4BNP_f8-a|K1r8_3vF`dnEr}f^&S~t|tTk zULV`n^6#C+mlyT#U1r<+_tNpL#lcLF0CPbh80z1vMmCy%Z#QY)zqcPgl7H_c^3&if z@czAv@Th-p)+e4E)xVebp8jF}y$$%|ynnA7K3@OcDRjMmZvZa-y-Ps+dj|hnGROk^ zTAm!_-z$>qH1hHI_jaM@{d))C2Z8waj)I~7z4OS_zlVMC?_B`~-Z#lN=)>;vN8I|#(TcNB6AJ@Aa|05A=hf{=Eyx#J{)iT~CT~jAnM;+z_$4J)&cSFozHmRF#p~OJ<^i`Z!AnM;MXL|!^0=-}XecSu@_ON|D{=EV8FM^T$d!-+F!W2}|f52G&y=9~y zdjb6uME!fG*^c`6&a*B4y_t;R93gGb<(iUJQm<5LV_X?5C2MfSL;Qf2c z;N_qaRD*S31E>K*{d?WWdcjW62X=woU=P>}PA`7H`uFz34}g9U_3s^FdmeQ?N_-3) z2Pc5|_f7%v?=Af1lf(Rb1IRCcXMy+cU4~x)SAoH|l?;wD30niT) zfW8gSA0ZxKb;50Y`&VqB`JQx5Mz_Z{YxCAbPE8r@K`u8ds2ea_$4fXF0 zeSSL6`Tf=~=Uc z&3fi=wfNEQXRcPe*_iv8ztwK${W|8BwT%y$VzGlyXpz`y;hseDx3rig%o}T4cJLkr zG5)n`=DfA|ZPu4c+-=s2d@J^tCr0nzx?e+k1G$geMZ5>>1O9&Q0Q?{rdS55=_*(pi zrDDI0cQ2S@;?^|Fn19xGZZa#FtJdNlT%~clS#YeagYaQfdViO6oLhy z2rL7YU>&FdO`rqxf;?NlKR5)AfMehUI0eptb6@~G3oe4o;3`OFPL>7oz${Pz z=7ITOAt(jqpc-rd^`I4WgPouc>;`+me$WpNfg|7;H~~(9GvFK;07p4~7l|)}j*j

<7oNe~|bvI0}w~li)Ns3(kWJ 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

lQ|bt8s;p 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

HEH>VeYUmVb}Ppe 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�@O{FQ%4u~aesv`u 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� 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 -f " + echo "for example: -ip 127.0.0.1 -f /var/tmp/userToAdd.txt" + exit +} + +function check_file_existance () +{ +echo "check_file_existance $1" +if [ $1 == "" ]; then + echo "Please provide full path to user file" + exit; +elif [ -f $1 ]; then + source $1 + USERS=("${USER_LIST[@]}") + echo "file exist" $1 +else + echo "Provided user file does not exist" + exit +fi +} + +function check_ip_existance () +{ +if [ $1 == "" ]; then + echo "Please provide ip address" + exit; +fi +} + +function addUser () +{ + #for user in "${USER_LIST[@]}"; do + for user in "${USERS[@]}"; do + PING=`ping -c 1 $IP > /var/tmp/ping.log` + pattern1='100% packet loss' + pattern2='Host Unreachable' + COUNT=`egrep -c "$pattern1|$pattern2" /var/tmp/ping.log` + if [ $COUNT -eq 0 ]; then + # curl -i -X post -d '{ "userId" : "kk1123", "role" : "ADMIN" }' -H "Content-Type: application/json" -H "USER_ID: jh0003" http://192.168.111.9:8080/sdc2/rest/v1/user + userId=`echo $user|awk '{print $1}'` + role=`echo $user|awk '{print $2}'` + curl -i -X post -d '{ "userId" : "'${userId}'", "role" : "'${role}'" }' -H "Content-Type: application/json" -H "USER_ID: jh0003" http://${IP}:8080/sdc2/rest/v1/user + else + echo "Host" $IP "Is Unreachable" + fi + done +} + +#main +[ $# -eq 0 ] && help_usage +while [ $# -ne 0 ]; do + case $1 in + "-f") + USER_FILE=$2 + shift 1 + shift 1 + ;; + -ip) + IP=$2 + shift 1 + shift 1 + ;; + *) +# help_usage + ;; + esac +done + +check_file_existance $USER_FILE +check_ip_existance $IP +addUser diff --git a/ui-ci/src/main/resources/ci/scripts/copyToStorage.sh b/ui-ci/src/main/resources/ci/scripts/copyToStorage.sh new file mode 100644 index 0000000000..396c1aa0ac --- /dev/null +++ b/ui-ci/src/main/resources/ci/scripts/copyToStorage.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +REPORT_NAME=$1 +VERSION=$2 +ENV=$3 +IP=$3 + +if [ -z "$REPORT_NAME" ] + then + source ExtentReport/versions.info + now=$(date +'%Y-%m-%d_%H_%M') + REPORT_NAME="${now}" + VERSION="${osVersion}" + if [[ $env == *"DEV20"* ]] + then + ENV="Nightly" + else + ENV="" + fi + + fi + +/usr/bin/expect << EOF +spawn ssh admin@${IP} mkdir -p -m 775 /home/admin/reports/${ENV}/${VERSION}/UI/ + +expect { + -re ".*es.*o.*" { + exp_send "yes\r" + exp_continue + } + -re ".*sword.*" { + exp_send "Aa123456\r" + } +} + +expect eof + +spawn scp -pr ExtentReport admin@{IP}:/home/admin/reports/${ENV}/${VERSION}/UI/${REPORT_NAME}/ + +expect { + -re ".*es.*o.*" { + exp_send "yes\r" + exp_continue + } + -re ".*sword.*" { + exp_send "Aa123456\r" + } +} + +expect eof +EOF diff --git a/ui-ci/src/main/resources/ci/scripts/sendMail.sh b/ui-ci/src/main/resources/ci/scripts/sendMail.sh new file mode 100644 index 0000000000..794534fc8a --- /dev/null +++ b/ui-ci/src/main/resources/ci/scripts/sendMail.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +now=$(date +'%Y%-m%d%H%M') + +REPORT_NAME=$1 +VERSION=$2 +ENV=$3 + +RECIPIENTS1="dl-sdcqa@intl.att.com,ml636r@intl.att.com,bl5783intl.att.com,ak314p@intl.att.com,el489u@intl.att.com,hk096q@intl.att.com,bs5719@intl.att.com" +RECIPIENTS2="dl-asdcqa@intl.att.com" + +source ExtentReport/versions.info +if [ -z "$REPORT_NAME" ] + then + source ExtentReport/versions.info + now=$(date +'%Y-%m-%d_%H_%M') + REPORT_NAME="${now}" + VERSION="${osVersion}" + + +fi + +if [[ $env == *"DEV20"* ]] + then + ENV="Nightly" + RECIPIENTS=$RECIPIENTS1 + else + ENV="" + RECIPIENTS=$RECIPIENTS2 +fi + +#REPORT_ZIP_FILE=ExtentReport_${now}.zip +REPORT_FOLDER='ExtentReport' +REPORT_HTML_FILE=${REPORT_FOLDER}/*Report.html +BODY_MESSAGE='Hello, \n\n Please find automation results on following link: \n\n http://asdc-srv-210-45.tlv.intl.att.com/'${ENV}'/'${VERSION}'/UI/'${REPORT_NAME}'/SDC_UI_Extent_Report.html \n\nThanks, \nASDC QA Team\n\n ' + +#OLD_FILE=$(find ./ -type f -name ${REPORT_ZIP_FILE} -print) +#if [ ! -z ${OLD_FILE} ] +#then +# rm -f ${REPORT_ZIP_FILE} +# echo "Removing old zip file............" +#fi + +#echo "Creating new zip file" +#zip -r ${REPORT_ZIP_FILE} ./${REPORT_FOLDER} + + + +echo -e ${BODY_MESSAGE} | mail -s 'E2E Automation '$ENV' results - SDC '$VERSION -r 'ASDC@Automation.team' $RECIPIENTS diff --git a/ui-ci/src/main/resources/ci/scripts/startTest.sh b/ui-ci/src/main/resources/ci/scripts/startTest.sh new file mode 100644 index 0000000000..737b538b01 --- /dev/null +++ b/ui-ci/src/main/resources/ci/scripts/startTest.sh @@ -0,0 +1,155 @@ +#!/bin/bash +REMOTE_DEBUG=false +RERUN=true +JAVA_OPTION="" +debug_port=8000 +TEST_SUITES=testSuites +fileName=testng-failed.xml + +function help_usage () +{ + echo + echo "$0 ( ) [-r/rerun -d/debug ]" + echo "nohup ./startTest.sh ui-ci-1707.0.5-SNAPSHOT-jar-with-dependencies.jar extendedSanity.xml -r false -d true &" + echo "by default rerun is true and remote debug is false." + echo + exit 2 +} + +function isBoolean () +{ + PARAM_NAME=$1 + VALUE=$2 + if [[ ${VALUE} != "true" ]] && [[ ${VALUE} != "false" ]]; then + echo "Valid parameter" ${PARAM_NAME} "values are: true/false" + help_usage + fi +} + +function prepareFailedXmlFile () +{ + echo "1="$1 "2="$2 "fileName="${fileName} + PATTERN=`grep -w "test name=" ${FULL_PATH}/${TEST_SUITES}/$2 | awk -F'"' '{print $2}'` + sed '/ ${FULL_PATH}/${TEST_SUITES}/${fileName} + sed -i 's/thread-count="[0-9]\+"/thread-count="1"/g' ${FULL_PATH}/${TEST_SUITES}/${fileName} +} + +#main +[ $# -lt 2 ] && help_usage + +JAR_FILE=$1 +SUITE_FILE=$2 + +while [ $# -ne 0 ]; do + case $1 in + -r|rerun) + RERUN=$2 + isBoolean $1 ${RERUN} + shift 1 + shift 1 + ;; + -d|debug) + REMOTE_DEBUG=$2 + isBoolean $1 ${REMOTE_DEBUG} + shift 1 + shift 1 + ;; + *) + shift 1 + ;; + esac +done + +CURRENT_DIR=`pwd` +BASEDIR=$(dirname $0) + +if [ ${BASEDIR:0:1} = "/" ] +then + FULL_PATH=$BASEDIR +else + FULL_PATH=$CURRENT_DIR/$BASEDIR +fi +LOGS_PROP_FILE=file:${FULL_PATH}/conf/log4j.properties +############################################# +TARGET_DIR=${FULL_PATH}/target +CONF_FILE=${FULL_PATH}/conf/attsdc.yaml + +DEBUG=true +MainClass=org.openecomp.sdc.ci.tests.run.StartTest + +TESTS_DIR=/opt/app/sdc/ci/resources/tests +COMPONENTS_DIR=/opt/app/sdc/ci/resources/components + + +TARGET_LOG_DIR="${TARGET_DIR}/" + + +######ADD USERS################ + +BE_IP=`cat conf/attsdc.yaml | grep catalogBeHost| awk '{print $2}'` + +ADD_USERS_SCRIPT="addUsersFromList_new.sh" +USER_LIST="userList.txt" +chmod +x ${ADD_USERS_SCRIPT} +echo "add users..." +`./${ADD_USERS_SCRIPT} -ip ${BE_IP} -f ${USER_LIST}` + + + + +if [ ${REMOTE_DEBUG} == "true" ]; then + echo "Debug mode, Listen on port $debug_port"; + JAVA_OPTION="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${debug_port}" ; +fi + +cmd="java -Xmx2048m -Xms1024m $JAVA_OPTION -DdisplayException=true -Dtargetlog=${TARGET_LOG_DIR} -Dfilepath=${FILES_TEST} -Dconfig.resource=${CONF_FILE} -Ddebug=${DEBUG} -Dlog4j.configuration=${LOGS_PROP_FILE} -cp $JAR_FILE ${MainClass} $SUITE_FILE &" + + +if [ $DEBUG == "true" ] +then + $cmd +else + $cmd >> /dev/null +fi + +if [ ${RERUN} == "true" ]; then + if [ -f ${TARGET_DIR}/${fileName} ]; then + echo "Prepare" ${TARGET_DIR}/${fileName} "file to rerun all failed tests ..."; + prepareFailedXmlFile ${TARGET_DIR}/${fileName} $SUITE_FILE; + SUITE_FILE=${fileName}; + cmd="java -Xmx2048m -Xms1024m $JAVA_OPTION -DdisplayException=true -Dtargetlog=${TARGET_LOG_DIR} -Dfilepath=${FILES_TEST} -Dconfig.resource=${CONF_FILE} -Ddebug=${DEBUG} -Dlog4j.configuration=${LOGS_PROP_FILE} -cp $JAR_FILE ${MainClass} $SUITE_FILE &" + $cmd; + fi +fi + +status=`echo $?` + +source ExtentReport/versions.info +now=$(date +'%Y-%m-%d_%H_%M') +REPORT_NAME=${now} +VERSION=${osVersion} + +if [[ $env == *"DEV20"* ]] +then + MYENV="Nightly" +else + MYENV="" +fi + +COPY_REPORT_SCRIPT="copyToStorage.sh" +chmod +x ${COPY_REPORT_SCRIPT} +echo "copy report to storage..." +sh ./${COPY_REPORT_SCRIPT} ${REPORT_NAME} ${VERSION} ${MYENV} + + +MAILING_SCRIPT_NAME="sendMail.sh" +chmod +x ${MAILING_SCRIPT_NAME} +echo "Sending report via mail..." +`./${MAILING_SCRIPT_NAME} ${REPORT_NAME} ${VERSION} ${MYENV}` + + +echo "##################################################" +echo "################# status is ${status} #################" +echo "##################################################" + +exit $status diff --git a/ui-ci/src/main/resources/ci/scripts/userList.txt b/ui-ci/src/main/resources/ci/scripts/userList.txt new file mode 100644 index 0000000000..a1326599dc --- /dev/null +++ b/ui-ci/src/main/resources/ci/scripts/userList.txt @@ -0,0 +1 @@ +export USER_LIST=( "m99121 DESIGNER" "cs0008 DESIGNER" "kb0004 TESTER" "af0006 OPS" "ah0002 GOVERNOR" "m08740 DESIGNER" "m99124 TESTER" "m08743 TESTER" "m99123 OPS" "m08742 OPS" "m99125 GOVERNOR" "m08744 GOVERNOR" "m99122 ADMIN" "m08741 ADMIN" "m99126 PRODUCT_STRATEGIST" "m08745 PRODUCT_STRATEGIST" "m99127 PRODUCT_MANAGER" "m08746 PRODUCT_MANAGER" "md9897 DESIGNER" "m08748 DESIGNER" "m08749 TESTER" "be0695 DESIGNER" "er434w DESIGNER" "ya107f DESIGNER" "ds200p DESIGNER" "ak0333 ADMIN" "th0695 DESIGNER" "al714h DESIGNER" "ys9693 DESIGNER" "ss8214 DESIGNER" "bt750h DESIGNER" "rp955r DESIGNER" "ez6451 DESIGNER" "ia901h DESIGNER" "ah7840 DESIGNER" "ea394r DESIGNER" "ms656r DESIGNER" "ml636r DESIGNER" "it1721 DESIGNER" "sg473v DESIGNER" "sa997j DESIGNER" "az2497 DESIGNER" "ys189e DESIGNER" "ig642y DESIGNER" ) diff --git a/ui-ci/src/main/resources/ci/testSuites/andreyPara.xml b/ui-ci/src/main/resources/ci/testSuites/andreyPara.xml new file mode 100644 index 0000000000..f4f99db3a1 --- /dev/null +++ b/ui-ci/src/main/resources/ci/testSuites/andreyPara.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/testSuites/devOnboardSanity.xml b/ui-ci/src/main/resources/ci/testSuites/devOnboardSanity.xml new file mode 100644 index 0000000000..5b44e68375 --- /dev/null +++ b/ui-ci/src/main/resources/ci/testSuites/devOnboardSanity.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/testSuites/devSanity.xml b/ui-ci/src/main/resources/ci/testSuites/devSanity.xml new file mode 100644 index 0000000000..6c4ba547b1 --- /dev/null +++ b/ui-ci/src/main/resources/ci/testSuites/devSanity.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/testSuites/extendedSanity.xml b/ui-ci/src/main/resources/ci/testSuites/extendedSanity.xml new file mode 100644 index 0000000000..a8dcf84c73 --- /dev/null +++ b/ui-ci/src/main/resources/ci/testSuites/extendedSanity.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/testSuites/fullCI.xml b/ui-ci/src/main/resources/ci/testSuites/fullCI.xml new file mode 100644 index 0000000000..940026d30c --- /dev/null +++ b/ui-ci/src/main/resources/ci/testSuites/fullCI.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/testSuites/onboardingVNFs.xml b/ui-ci/src/main/resources/ci/testSuites/onboardingVNFs.xml new file mode 100644 index 0000000000..e263a4a3f4 --- /dev/null +++ b/ui-ci/src/main/resources/ci/testSuites/onboardingVNFs.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui-ci/src/main/resources/ci/testSuites/sanity.xml b/ui-ci/src/main/resources/ci/testSuites/sanity.xml new file mode 100644 index 0000000000..c8fd8f14b1 --- /dev/null +++ b/ui-ci/src/main/resources/ci/testSuites/sanity.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui-ci/src/main/resources/images/gizmorambo.jpg b/ui-ci/src/main/resources/images/gizmorambo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c9a8fe8a646eadd42bdf645449a5bef231a25e1e GIT binary patch literal 16605 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 literal 0 HcmV?d00001 diff --git a/ui-ci/src/test/Completetheform.js b/ui-ci/src/test/Completetheform.js new file mode 100644 index 0000000000..7e8b7572cc --- /dev/null +++ b/ui-ci/src/test/Completetheform.js @@ -0,0 +1,3 @@ +/** + * New node file + */ diff --git a/ui-ci/tarball.xml b/ui-ci/tarball.xml new file mode 100644 index 0000000000..9d7d4c1022 --- /dev/null +++ b/ui-ci/tarball.xml @@ -0,0 +1,70 @@ + + bin + + tar + + + + ${project.build.directory}/${project.artifactId}-${project.version}-jar-with-dependencies.jar + ./ + ${project.artifactId}-${project.version}-jar-with-dependencies.jar + + + src/main/resources/ci/scripts/startTest.sh + ./ + startTest.sh + + + + src/main/resources/ci/conf/attsdc.yaml + conf + attsdc.yaml + + + src/main/resources/ci/conf/attsdc-packages.yaml + conf + attsdc-packages.yaml + + + ../catalog-be/src/main/resources/config/error-configuration.yaml + conf + error-configuration.yaml + + + ../asdc-tests/src/main/resources/ci/conf/log4j.properties + conf + log4j.properties + + + src/main/resources/ci/conf/credentials.yaml + conf + credentials.yaml + + + src/main/resources/ci/drivers/chromedriver.exe/ + drivers + chromedriver.exe + + + + + + + src/test/resources + ./ + + + src/main/resources/ci/testSuites + ./testSuites + + + src/main/resources/Files + ./Files + + + + diff --git a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/Login.java b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/Login.java index bc6dee0ce4..db4853a8f1 100644 --- a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/Login.java +++ b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/Login.java @@ -12,6 +12,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.openecomp.sdc.webseal.simulator.User; import org.openecomp.sdc.webseal.simulator.conf.Conf; public class Login extends HttpServlet { @@ -94,11 +95,12 @@ public class Login extends HttpServlet { } writer.println(""); - writer.println("
"); + writer.println("
Create All"); + writer.println("
"); writer.println(""); writer.println(""); - + } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { diff --git a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/RequestsClient.java b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/RequestsClient.java index 5f4cfa93d2..a5e4a8a0eb 100644 --- a/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/RequestsClient.java +++ b/utils/webseal-simulator/src/main/java/org/openecomp/sdc/webseal/simulator/RequestsClient.java @@ -17,29 +17,51 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; +import org.openecomp.sdc.webseal.simulator.conf.Conf; public class RequestsClient extends HttpServlet { private static final long serialVersionUID = 1L; @Override - protected void doGet(final HttpServletRequest request, final HttpServletResponse response) - throws ServletException, IOException { + protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { + + String hostname = request.getParameter("hostname") != null ? request.getParameter("hostname") : "127.0.0.1"; + String port = request.getParameter("port") != null ? request.getParameter("port") : "8080"; + String adminId = request.getParameter("adminId") != null ? request.getParameter("adminId") : "jh0003"; + + String createAll = request.getParameter("all"); - String userId = request.getParameter("userId"); - String role = request.getParameter("role"); - String firstName = request.getParameter("firstName"); - String lastName = request.getParameter("lastName"); - String email = request.getParameter("email"); + PrintWriter writer = response.getWriter(); - String hostname = request.getParameter("hostname") != null?request.getParameter("hostname"):"127.0.0.1"; - String port = request.getParameter("port") != null?request.getParameter("port"):"8080"; - String adminId = request.getParameter("adminId") != null?request.getParameter("adminId"):"jh0003"; + int resultCode; + + if ("true".equals(createAll)) { + Map users = Conf.getInstance().getUsers(); + for (User user : users.values()) { + resultCode = createUser(response, user.getUserId(), user.getRole().toUpperCase(), user.getFirstName(), user.getLastName(), user.getEmail(), hostname, port, adminId); + writer.println("User "+ user.getFirstName() + " " + user.getLastName() + getResultMessage(resultCode) + "
"); + } + } else { + String userId = request.getParameter("userId"); + String role = request.getParameter("role").toUpperCase(); + String firstName = request.getParameter("firstName"); + String lastName = request.getParameter("lastName"); + String email = request.getParameter("email"); + resultCode = createUser(response, userId, role, firstName, lastName, email, hostname, port, adminId); + writer.println("User "+ firstName + " " + lastName +getResultMessage(resultCode)); + } + + + } + + private String getResultMessage(int resultCode){ + return 201 == resultCode? " created successfuly":" not created ("+ resultCode +")"; + } + + private int createUser(final HttpServletResponse response, String userId, String role, String firstName, String lastName, String email, String hostname, String port, String adminId) throws IOException { response.setContentType("text/html"); - PrintWriter writer = response.getWriter(); - writer.println("userId: " + userId); - writer.println("role: " + role); // Fill the data of the request String url = "http://" + hostname + ":" + port + "/sdc2/rest/v1/user"; @@ -47,13 +69,12 @@ public class RequestsClient extends HttpServlet { HashMap headers = new HashMap(); headers.put("Content-Type", "application/json"); headers.put("USER_ID", adminId); - sendHttpPost(url, body, headers); - + return sendHttpPost(url, body, headers); } - - private String sendHttpPost(String url, String body, Map headers) throws IOException { - - String responseString=""; + + private int sendHttpPost(String url, String body, Map headers) throws IOException { + + String responseString = ""; URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); @@ -79,8 +100,8 @@ public class RequestsClient extends HttpServlet { } int responseCode = con.getResponseCode(); - //logger.debug("Send POST http request, url: {}", url); - //logger.debug("Response Code: {}", responseCode); + // logger.debug("Send POST http request, url: {}", url); + // logger.debug("Response Code: {}", responseCode); StringBuffer response = new StringBuffer(); try { @@ -91,7 +112,7 @@ public class RequestsClient extends HttpServlet { } in.close(); } catch (Exception e) { - //logger.debug("response body is null"); + // logger.debug("response body is null"); } String result; @@ -103,18 +124,18 @@ public class RequestsClient extends HttpServlet { } catch (Exception e2) { result = null; } - //logger.debug("Response body: {}", response); + // logger.debug("Response body: {}", response); if (response != null) { responseString = response.toString(); } - //Map> headerFields = con.getHeaderFields(); - //String responseMessage = con.getResponseMessage(); + // Map> headerFields = con.getHeaderFields(); + // String responseMessage = con.getResponseMessage(); con.disconnect(); - return responseString; + return responseCode; } - + } diff --git a/utils/webseal-simulator/src/main/resources/webseal.conf b/utils/webseal-simulator/src/main/resources/webseal.conf index 869b17bebc..a7026e39fa 100644 --- a/utils/webseal-simulator/src/main/resources/webseal.conf +++ b/utils/webseal-simulator/src/main/resources/webseal.conf @@ -7,7 +7,7 @@ password="123123a" firstName="Carlos" lastName="Santana" - role="Desiner" + role="Designer" email="csantana@sdc.com" }, { @@ -41,22 +41,6 @@ lastName="Shadmi" role="Governor" email="governor@sdc.com" - }, - { - userId="pm0001" - password="123123a" - firstName="Teddy" - lastName="Isashar" - role="Product Manager" - email="pm1@sdc.com" - }, - { - userId="ps0001" - password="123123a" - firstName="Eden" - lastName="Rozin" - role="Product Strategist" - email="ps1@sdc.com" } ] } -- 2.16.6

3XPl@(7Vv~h?hw=WAFYIBXgQLW(|4e$>-$h=(J ziS#f9zmOi%>e!3;$@J4mH`nwfrhl!+jl)rBvkqbZ&-l3sHF6I&=yn`#(k0_ce9+B8 znA2cRhoSK7g*g}I88DqNC&4(rz^D9S+k%`&d;;v{FjTB)_)R~KeHkbGV;; ziD~b~yvV(a;bhu;-o@zrF6i(_$^%Sa`-#%GUQZcISFV}Ig!FZ6ePN`2*FnKPNTHs?>q@m+%H4E)F=q($-=ZMxkzZMx6s!+-cY ze*KmYIt`V0D}?=$=>&HtgqG4cPwkS$#T4zxnCVUDe);|bYhi16)T{QH)?RJx_13Q4 zy>j#EKmN`+ONa~p)qlfB`i{wbXfN{QX7 z-6H!}hfU^hfSWgiRwfSP9t!NBqjI%w-3TtIFYM6cANpJ&QU>AWLcTv49ESG|mBwti zR)BJof3(AI`i1imbccVGwfq};%&qHsKcV%W{w!qwud(O-$A`@{?8{2Jvvpl`&BZ!7 zydv7^KDN7$3-sf%K1{1uSCVF^B=-xfzj@Qdthb=>t?t{ryLdX zSoGRj#sfi>;oVrot5kYU0DbaJkllH#rxkdI$xunhUY&r~oOYw>y#A=E{U`Vb-|Ppc zVDG>+_!ZRW8ng|8#yeF685RMCMR5C#!DP{9H}|qM^K8sAZI^g#Q``}b32I!VmB%|M zyuU_vt3`ZwL&i17&!_tK3r^Id)p7R;S{-{z+3F&S z+Q7*A$%rmBJb-ZrMk9U2fz5bxDZM?`t;6M9jG_a?)cmwPaF3?V&5kA8#Ko3F$!zD4 zjTiTD>@$MrE+U*ztByr@02Qm!+NwQE+SSu#^L!)>4kKVcf-Nu+5G$y^u(yC?N;v$V zEUgWlD9l#^C)l1;F>G+>kc@5Bcgz0ywsmH*^Q#aEZRt_Vk&B#WiL=E;YSZpY6MQYM z9qnsbmmS1btQqol|hZzkq^{@Z+yn z&pp-dP^bI9X8TCmv2XOLO}G87(T3rleotL+qx5g%TW&Nm|A;wj>Mps9ZWLR_r7y#n z4dGds225rv^cuVc$g!}@aYN2V&rw|`dkNyX^`Pe>5BQI7yHVDICU(FLLmg|r<4ulr zsOL0oe#>9I7ivS(9KYPbd|tsSKL-kV9K0)d-KUlb$6OP)YunXcjDF|Xl{#KW+tvOY zZTZn_O!QK1!_13rG^H0J&P%L5n0QA~;qW@%B6v{G;~&4N#*I!3;~Ka$<76~1X#-B*BYtnBY$o18GbqYoY2g$+bh zel6lNZ+!UemIF-Lx8GLBkqECpuO@N6HyYp3W}x zpJD1B1nV!Sc zlX%0Rfp7D4%+r7KM%c9Qk{ey}$QttU2-w^dPj6UDcso6-+E*?N6>cW@eiI z+RR#P2b0{-^0_lpL|M*_V8{nsEu}b~T3X9ox#wZ;Zsw}_hvx~ImU}@sjVZIIm=4v$ zZoDNp+(;(TB#2+QFho}#u?<9KRvF#&-1$R0_E8yoSM}YS?y9a4Is4Q#lXrjnbLZUi zl7Uk;LC$Xae&ai^jro3Kx0Stg@vpY&SO4`&3A=OKr#6i}aQ!`WKXcW`?!G_D-t)5? zPm%Bk{hqCII9Wmqo4!(eyfEgP;xDpq%<9Zi#ba;EOhV?S8ne{$^ zy1|rSA{f5CmpKJ#QP0WKjtKqMVUIuJh?#=PKJth;Uv}B=bnn0j9e19JI0%zBN_I8h zWYM=v0yozjn!BZRTc@l;h@@#A57Pj|T?^G053uvjvjM9WBuF;+)&hM;m#5tyvhBB(w&4 z;(J3Z5UeI8pg^_3N8Ifxajh4(X@wcCKN6f!u&HqZF$BJ)%rFpTa{n2(yJLmkX3#xz z`CGQPFNd3doVVa|oWghR381AXf|i=E&*9F5 zRTwAoS;Xh9b{}ip$6EbpuG3EW8JY~$dw zM9rxTju@fCS+~HJ-GaKJ4E~|5R}&YCk=0$;9xI0p(DFQcK#A2e65%-;*nFLdR?{18 zr5qDK9ERyD`(Wv}jaSLNhOxet@>`0H7p`zF>WVa9@dsH85llBP?>A~F+=}0&6FQ<4bcxzE< zK(_bWl}_1jj{n%>3!W(NZB(OgF7mJpcK!3H18AhX2N!?KTa4D97#4p#*2g&9+mFrh z%b>;R0rBp$NLud6Kk7*ADy2N8ZN_gBpTu`B0LJ2LO=Kq}Qp(-p$V=}+fhsn}JFSJb zcqT&OSV4hJfL273P72-~HVO#OM$xlD*uq}fi9=4PwQWmD{BVJjSh8^_ZFfg+g5gEyZQ2+eOL-xKuqI$(AaL!*j~^vzU!dt&OJwr z^iPn|)&E{}3V)~Lch|{#@Ou(|pF3&% zq$}`y>PbIY^ua}ciC=NimPKda*|e#J_u=;s3tzTyc;WR6pR;hy!lx~K#KPY$_#uA( zy5M6A?pW~F1#evN@&&gnIJn?X7F@qz$AWDOHZEAZVEKYG7d&}E=Ymrgm<7M-_)W)j z#{(VT?)X~A7dt-P@zIWY$DJMT>3CPiKX&|G$D2A{*YV1Zmv_9lwmK<4GNl?|5v-A9Osb;}IQ8I!^64xnmJFrDMqX|HI#G0f&8$|IeND-;Mw2 z|26mzso&ARga4^b`Y*=l{~uE6|6k`p|D^u^9rT}sU%6lL-yZ&#rSLzwf3E!Rxc~nx z|10cH_BrgU^rQTv^i%mq>F4F2O24H1bJA}v^3TCf>G%Ia{yE5LQ}UDd9sG{^o%E;t zSLyHMzmxuP`S0MT^q)=shw!WP|DTor9{wcsA@AHb*9yP( ze*aVbpT~O~_k=!_{f_!)?)|m@Pr}dMzg_>|4u04B|9AKQiggFOQoh%Gl=l_;>C`_z z?Wa}$nGJrY{rq?7Kc4Cx-#h4AvG2Ga6ZWG0IqGla{+XqJsQ=9sey{zVSpAPs>yH|* z!tQ844f|g9&(8g`X}{Ee=MTTveout{t5CcD+2^-HpX7ay{W$ffbN}qp??h<-4_E(> zL$0us^8KhM9QQcvhq6CO{b|x~N1M@49Q!9~^fRCFk7C^8U15(yuaeJ6eusU>{b_w) zyRlz#^cRQUjr~sS=x^rnpQCs7c5&F9&KE-O^d86iam|lo-w^xlbssnSO^4t2{U^Tn zOOAgP?l|n!_d@7Z?knv(?1y@PsQHBO>&U*^h^e!tDMh-W7IAJyO2MeVq2aU3nfsdm?AJpk3Ay6kVZJ@| zPV#x|$7el~vacQW&))Yxyt%)*&Hg=PIIed;QoN^no#~;}YsI}n@8>+dL6 z{yt;~ZTKVB6?TVt2ffbqDfEu>TW7pO$sfmleBN8JKNI!OweNrUbKeh{-&^<<>NME3 zzh{p}sTV@;IN#B}AM?$G{dCP|ChDKh$aj8o|AgN|&UrnZ+f$C$QLdx=bm&`Y-;eob z#(tdp=cf72Z{$1s+6UoxPmsXhkvj6&wbu!{v%(v_C@#|#2)8U zR@OVbE7$uTuNC)>^BwJnBmS`8Ph!7y&c79Yr}xjL@0&mO|JD%N@W(YxUDxyy&tcw= zbVJHl=$+j6wC~qDXU2Y-?3+pU&#mv98~6X#IC#BHxK-Lw+AHj&d+qPp759$w(`aAU`(3{m=l!%5|8%{7HtL`2 zx<6$f;dd}Qe0#_p%`5B<^Yei|jrJY<+V3T?pEl}ix94GY>Yr)f1L6Oz`HfLrhZxsh zPWe3@c53?VaPN9OC-*(=hdTev*mr$jocG($ddyD!t@}P4{Djv32(^ctJ)Pn`qOJfeNX%0TK{a=kHhbFyv#J~H5cmFeJ>7v2XP#3g*+X0Vtzi*d%5pv zKd$w~C4VdS+sVF}G@qGgeI4|_F{JSDM~ug@?l@lOHyreDl)X*uaPK(ZkM_OX_p~3^ z`jWigiv4!7Z{|HuX}g{r{J%C1UT3p+*B>Rl!cJ-Lc-~>&ukEYM4=Fzhz2kgO`{7Q9 z`D4HRoZrl|KFPlCH|E#ILF;XWJA}L)?0#*(6?!N49OtLeetfnw-tQ-|@3=p{->vhYb)=kVZWX1ORo5N+5ao^3)2d-hg-4U ziuVw9(!J_>)OJG3k3;V`KaKW7$rsM{&5r%Fp09n+AJ=?H{l72{)5_u0=~S;Hy@!xH znpd88nD<<-x*q#`<@=eT_v0N;`=R8E>-@=nzZLuGdSCmV-*NvhjDt9Y+C#3~-X3;G z_a6FFWnZ^K@A^E&z3cNm=es>#FAw&3hmtS8(wpRcC;P*_-s!u&!~NcI>Yp}>=MdZ6 zv*_Sf$W_v(Q9XIy(Y@+=;jVU-dg;)6&i8WP(|)|)i_dl@u^+x zDckkOU5mPN(NVmodB^i1^h)=0gWmUgj`P!LKR)7%YkjTQPwV;G%Rc4)Y2)CHL+v3~ ztj`R4oa?o}Z^gZn`VM->`Cjg~qy2EiH#_#zd%iT;H*Fp?4$saew)MyU&Gm8G$H(#R z=-y-AbNy`4w{m_u?T3;tKHrg){H@qe*ZX|W{|iI-9kkANP%Fl@e^>2J`#Gg~2fM?( zr+do0cF;Si@1S>_?{yw8_e0tbC13KCOH%TuVLwgp`vv+w!tddAUxZnIgj;bw8|=h9 z>0Tv1HQi9^DdoqZcbxyi=Gh*v^LV)*NYP>v(tWD>v4LIuJp_W`;>iz-$5GM4r+(<5bKWLy}TpUJIs5!C)dvn z_fGCP&iA7|FZV;*4<%pxgkw_cn;rW?Iy$<_7G7i$XO`S%6l<*F6-^;mPUSVfn7nk>5=26dY z<@-4FNxA1a-|IYH?uU{u-tWcNIp>1?9~lQ{+*YWQkSo?b?Cmh`>0U=U)O16sH#g{g zujh3hPy6j9UsC69mHZz2KQtcF@QZ!A{>bN!*A;Tl?;+kP?;OvwxASzbdcNv<+T*Fr zSIUp$-pRc*&i8V^9qq@*`$?@YDfxe7eq?^g3%F8$akxXsTWMaUy@Ot1kJJ6k&?lw7 zgFcP(z1$CJKa_m&^W6`bq}CT={|CmwnY5|P>W})o;yje|j^E?3JItrieLLLG27Mam zd$}LZ^T+$W_=qnZ`wG8t#>qa13wD)rK!cT(SJJigC& z(9cf$q2x=B_f_k2(0|uBm>sm`R$;0eZKGY zyv`HSemK(^V*gh%*X<>rhd&Kog`DG8{ZYm_Ij4|2{U$E!T|Xbf9_M-;<*24R8}v@@ zwf6abwCCl1*z32Kd`awo*Ces*V0M)5;SM2JIUlF_H0V|05%ZqwA0G5h?)hHNkM=^j z?`hxjKG!+?h>y5e-Usy?4{r!@h;IkC;yi@h_3Mz8&sej~~aq~e6RC_wC`7Wre&_rLr=+1>`xg7YaHGXYA4?vuPfwU&U?JGr*qPtJ$)SWp6+#o ztD_w1dU2_zxStLBG|o?_eNum#_o6ITBt#QI~uu6?_X<{ZV(47Pw{ zlkPp&d)&8&KH29bp-XA6+^0j|D)-Vj-|IXf?T3<2dH-AHo5n%vY|^*?k2>myWhgH8Eydl)-kSo^b2D`(&r+bxoD)BkW z3Hd&b``Msx<@|KokN10|{coDDn>f6l!sGaM7*|dYAy+w{qve>yqnvioyB@zC^uEt`(9cf$iv6#d5LW$m5U0WIAP-@ucH{ZI9qbPCp6)%@KOE?t z+-v20-|P8aKh${H?>p$fX5!F>m=5u+BUozlA>@kn`N2-id%E{rKR4XFJ}(Jz`Ks+`kEeVehu%s3 z_HxhndS2&=(>~#kL#r3%NIyB@zC^iJ-1 z&iB2Z*LfW6f5m*+csTu+gLo#mmEINWUbo|z&g0#UZ9?d^r>DeAqx+e0pANkn=eNo| z&-q^8cao2|C;V|(;}FO3?fASEa>e@Wush6qd7sAh?I=GEz3cOm&^x)8#`&S#C;VSF zUo;A1{C`rn|B=e|$5D(M$%OQ-kk5?w5O!idPWPd%Lz&mg_YV*HG|pGKPv{B1htq#K zc;iqzT8~5Sv97YNmF6k$9P~={gxz7@bG>SMD)DuMt9ribdfMYD-^X#El=`i5FOBmR z`(H3|Se?sZ+GATsuaxeN+C!{+IZyq@^Lq%p<9P@D3b~`0nD<*s=dr|-mZ@1%aK+)Ly9F9Q0{8xLjp7eWf8wF%Xh(6coKNUKYeG1~Z$j&S3Ue#mA-yZs zXM&ybu07^G-FvQo__%jczg6zB&sWYT{GTxn#-#0GZV$I|dI-7acGt`4s4fY6I_5py zd#;}k(~WgEtPf!+0F$A?(!bysS&ddtBNRc49t_?p4#%{!Zt%bd;kb zeC_X5>cydVeV&v0X`D~!KWXA{dY8jC2M?&0I!N&TeU`;=h+6UIT< zYCDK&JE$GL9o(&uE5*+rc4FSkdr$YC>mLr~C!yCqUpfDi<`d@QCWJEn?O|@kw~k*O zrz_4w$T^}>tjB3Sqr~N6shoA2lArURA3e$L@Ngxz62PWMT!pFi}j$8QJyM@<~c(B<%~HuV_&apda8 z?oOi%AyYBb z?(`eQJ9~Ktd&u*xnD<)r`9_#IBK9qMM z^a?w9o|yM^pXB=aL$BKIC#=+W(BEg`FveZllezz?zv_?kH9BWQxI+oAkSo@`oR9N+ zJJ=oOy~K<6^+~Ru5ANGRf1h#CrP&VNIMj~P9o!+Ohmb49&mZ4pEJAE z^;GJ`p;x*0Ve?^gpSjn>VT`*Rp5xd~!rhAV5OSy2ruTC?s`dT6gWX}?)4h)Gk}^+q z9WV8CO=IrR*G(M8q)X{Lq;jXrxPHyaI5&n3VW&p#`#5U0zK>@wPgx&Qy@OsgT*6Mw zd%E{rA8L9!yP+do9p%gw_jOY@A%v~ps=Ij&&iChDx;q&cLatbUIIyQ<-qXG3dXM|B z+L^uiL4PlxzsH0Swtg$T?tg{3731w7_mXaIcn@K3#k}w9lUzR^+~05cUZKC+IM~u{ z4{-=}65}f4LYyn)O7Szn9`9KD7s?^>Jx$ocO{N4_Bhxxd~OQZWx(^FkX$M-tMQ%zU39hLcU=nJ6ANE$vd%E{BPxah~3;kUt4q?*e@Epf>JGeu7SFC#}@8x_t z-kr49lUWXS@;ou`<-MnS&-D)<`nyaV!d4fl+x@gZbA1|n^f<odX5agBqW zJzYA_6Z2l)d%90@{d_3@E_0Xp7vo@SXM31El{=_)wu-&_%#d?DqgZ!6yvn+nU{A+< z8r`?{_8j4ceD8EUmHEo|9~9{CG$DLx-->1TKOxqiLhayghjWGecwl#!pPBAMJvSWR zbA&$=^miHuSv%Xo8;3dxxAM88cBS_u);XGMhxd@`+habB?!ClUEq{K{-(lkLwYnUh zLn?RkR9?2HL7v3=d|^+=yqEW$?mgGf7y1vFIDD-x!s>t8pS6d(mEINWUbl(Mx^{RE zVfUjO!cK|j<-Mo-WN+V&@>S~HY3?+4m=ECRVN3t=5Qk8Ee226imvSNGUebB(rakP0 zUT3o$?Ck3t^g6mrqx(?isjkBjE=M_(dDM22(7)fr;cInql;(dNuj!97HTomevq7#{ zp9yx?%g>Jandv^%^k#?teWvxVw%M54=AKbw#&17jvYQT?sh1rw(+}NXdY2zIjbk^M zM(!$;eZf&Ph4Ajmg(myrBj$A2ov^3B+-JsLUoedq9Wk93TwJz}PicH)&s%p}4~ zFuASB^D{S?`cEn*LLTFnmQ9Xn9~v@K+YXxEmmDz@ccAR&9yAvh2MhUfw6&b?FBS%? zru3>?&G?@kF^%UPG&}Zds0)m`jHy)fg$(+0D+0khR;=S!YFCFWzzSr9F5M|%qS>TtQR#F(Id zE27MbXchivMaipK)Mo;9DZxbhMy8RZDog6W?q67KrMOoHA z({)thPkaM3^>N6Nn?}qez8f&pFqh=3<>Dyl>EO`7aJ4uzh%}8apv@b3rj*q0Q!vD#HhwEiI4$7;SQfua5eLhRXej0f323pmJ#i za7x;~^`>Xcn4Uv0BgX6*7|K_p{Sx__rTy12VqZ^r@9yZV4N+fDo_JI@oCEm-r7m%y zydJh-4~u1WmLnMD>}PywXL_<+P!010Z81}qi8^gAaO8;x+KjGX0b3LFHx;(Ft9RdUxeNx%4pnwFX{K45 z_VI!!N<-zLq3V{)4i?JKM{O%Nl&f7~&S%*|g+7M|wR&vUOQjul^&e6gS9dL~Eb9VY zt@QbIv&zc?H)r8se@2+%d%$`Ht(MGWAx#ylMRHbw! zJnFMTb3$s9rR6`DQmKi#k`|@StL6M)g%yRU6$!J<)~H8_oAHz$Dv;L2!MzvdDTR03 zFr24w-Vk*~T|pK-qYx4?cQ*t^EXG(O##ndMeHJMMvaJas;c2s~xRZZh|L=EY6ZNVvnW%%Pi1?W;GL z%%^WM(ezEm{2br#i@tV~nTB5pekJ(5cl0JR{tJX5uf~^QK7sI`sJjGr3GRk<=e}~2 z$$j!B)A>^kpMZM;?n$^WMdyg#GP)|N76;gK0%G(F0KL%PgSr>iUAz0*-NVI!{%b1( z`GbXP`}UQGfYWjjQFe_K2cP9a%YD~Y_Z7?iyGqbl$F8mHFXpeUz_V|tT!0HWhT^-s zSUr$0m5QYT-93G!63SqEOuikkj-y^MQ+J~c{snHp$FS&5)cvif``h6D5W)~1AuL-Q zEeu4JpJ9iKUiMq+$G)nBvL;`MHn<(ey2s(p!tL;MbsIdfojNCx{?(}0YXM6g z^}XvRQwO{Z%l#9+UkCg3fDd8gLD=LwknS%4%PWxX9>hc2yL8dJkngJy4pT!|6r{`k zGxB=_!v6|oqJ1Y3#`a}-Q}0IHH^UF6hOmrndxq8Di*$bj|G!0Cgw=wuY2YCH7UcK$ zuz>>uTst~2cOcJyK;AIp2?8sAlSgz|ck zU*mh~?)?Jl_))+Jcl~BHoi_o#TTss%5eI&~H8lAW2F4j9;(vu`jF{G!WlHjQ_b z%q09Xdu}t?!fmE;{cUFaYS>rbZ0dctndk+YPv%26o9t1*yV=x=s0&POAMD|q&G=!Y8N1m`jv$}6!~GKYzYp$rBHec?CfA32 zmS1IZ71;ldVZj3xGyNvSxd-V!i1;6Yecw(~s{?FYL(=4^&sO3+UNf8fN>& z()E|~BUubspf|IBTm*AcY8;NOE3Ij_W5kvgf4c^>l(j_zTKq3Nm}lKv{Le4IVPNo&4W7Rrpv!DCDPcNRud+Z$s68ETMZ8uMN7Y8aR1=Y$Y502m+vo> zql5W!k$e&{O>|(WzqqGZC_~XYzWPwl(z<9lD8}kmm`2D`vqP24KzR9g#@-|2@xG-ppRj93HNUs8w4bid2NX|Dya9i1?yMJKIT*@~(vKi( zeg=H}9C8oeb$r(l_RB?QZ_1urGnt1V?|uh7FRGczg*DT8_>k!}HJO*qT~alfY*q5* zJPOMqEo3gP8m686J<|Or@<-a~4o%y64CTT-Q(E&Y)DPv>Q10|?hfMvJLsD)%rQG_9 z5C+*7EB9&0|0y+7T8eVd)N*rC%}jK|{baZi&bCO_c^q|~LRjYXn#uk#%+odPiG$v8>^r19w=5Zm9{I7>6bODg?efkz_J!~UR}dX zGU|Vx*13M}>~+o{Z3bx@uxlF;-=@tyyESdHtypg7*+{Kn*~0vK|WV&xw+@VeeKM2CG?E6naj~uh+DU5OIOW3 zZR4_d+S-+KNP8jhf^w&~!+@TrUSQkmX7JMT!!ce+w$(V&W>CiT4o&NL!OS5o7Mhyl z+iV_fy&o_aDD;?aZZQ**_`O_Mc{!%`o?_9Pf4G7;XLY(^hx*|x6dPe z3jdVmnLhL4<7hvWpGp;0h2uI#on|H?MokLzOZ;laD@{V?hz6%IYMjiR*SPpdm4nVU2W)TekoO|0K z#$v^OtUOZNxk!{9hMyR{xQYP`6!qQtYTv#+Lxa`6eBVBueTTQs zrydpDO@H>VnRx!~X6nk@P3fxJjl(JXr|fmN8v|2XihT%(Pg8?2PlG|9$oU|*c9?nA zQCU0er42IyQ-{H-;hy5&h>M4qxz@Eqt}oQq9+kGQ9w^zBf^a>kuTUItO9Wgz!`j-i zX!Y4=W63T$OFy`-qDyZaBiOZD%-#=`(-X=Ha3-@VB?Cz>g`Bs6YY5RME*D@;VTJs< zqjl;IYjxJFwX*QcA>UZ7=a8`*zx6d6H5w|Nu<=>}B-U50fHaXmaOX?W5FNyks>mk` zNnJ4fJ4G$|pMH*(*zZIa9Br;OWPf|O`OPpFZ+bImVhiX8V=Ky$EZpSvPWZ{16Wk?y zlV=^T=WP5fI@be2lVvC6apq^`h#G^m5F< z9>!c4!Vwl-fjZ!u@?;$LW=<{b05A3x2R08BO9b?~716fM>!PLoE28Z?X~S>gxkpU~ z@iWL{8hPYw9+R+9&%S)Q-?+#*)TV(wEnOpDjveaI)v`e9pQkGrF|2B0B&4 zbyChnc?_caqv}x9SH?yG4B!g~u-1?-k72c>G!_l*iTVqbYH<*w?V&-0j&d_W4|Wsi z--(f9d$|OQc?4_<+FPg&l?Jef!4C9oImeD2GZ${(e%W@dCl=PCind~e$smY5Zi48E zwqOP>!u(vRgmEM*d1C5kkVmPb)!mo?!lVfPHV+LC^vmc~*43)f!D3+q16pi$ zkT!CBhWQIjjBs{D0Xi}D+FO=!NQJa}R8o4s$BZ0{l;Tek#l&{J+SYg#S-6 zC*%K^yciRKCT{|V-CFr5f}0?gy2 zJ}2S-lTZfha0>oE1^J$eIz1Bqv)m=9$D{E-%VM2R#{VZvijxp)k-)W@DU3!b@eeLZSuVb&yC(+-&PGw-}ewBgdROn*&L8jb^Jv*G! zv31YEuLe_sDGp*1w5S_(ii0WCq6!M5e~W7R*X!w3u3^hKs>S8y}SSixvdU)yCHBAxq)h<`*orX zqUUf+MT9@EKLI9Nh)>^a!RF?hcpBYtz&#xSY(U3~=5DqC3(Y)GeG5A&gvikiT20F8 zA&UBkuoK67jbe*mlc0!lD0SX_DA_)eGn!_uS$kTvc?TXXnWO%aKQ@n9LZY*K*<1_r zgl!88JQ9V)@XS(xVUM$BsL-*KA5*8?Vj7=^p8k53ACvcc`Oym*QBRQ{lqV`bE*wB9 zm4e;MR~)o%Zi6ivV_g?gl*D3U9zGsZczSijtty3n%?+r=hA3#ox}QwxzX~-40YrBg zcSS5^H`oURYWJq?#hzOvS>2Oa7AA2yYrc%M3%T07>0A-J%QyP3!%r-RR zb+NTc$;%`o><3#e2!Pj^^@6}k{>2iFwI&+tVOOT~>#^bJ2@KGdo_y>k?hw5_?po;2 z@?=W082Tlf>nyq{7 zZs@Nc^>sI>djt5*`~c%-$NSCNQ~!o;{y$k??B6d8ZMn+P2OU?dL)xzsZA$YbYcR=b zD9fH>4QaV7lhR|O)tS%t!xapE27JX^Zhtq^Zya|Ch%1icmMx{ zE$l`F1VyKnhKyZr!0%{ePy3`Gos&&PsYSn7m z+Sa!E6kBVxwQaO&{aM@6r}n9>O8)Q9%sF=n(8uTX_`LoX-uZs#oH=u5pE+}8=D3Xd z<&?8Z)fHilb7|_29UicUT#4Iz0)8Fp{JrNS{D|)RI}dXX=D;xL@0DI9;Ky@WEK*;= zqo@2kKCm(r^8#Z{R3Z&5o|3*WsoU)HC5?AvhRd&@(t<|fW%1Okr*dg}=GGIpG(Ds1 z30<1T!@FS8h=HE8^%UO4tYnBJ;KoRJlwp;LX5H`%4z!7)5TqxMr~0aPQ;p-2t}>U*nmxR`FBsT z^KaW+{DqfS6j;yIB$O){I~22dypZ-c$`P%|H%~#{|BxYg=@kMib&_r zFT1>k7|7G4w^&BX>t6r!eBHy2Fu5Gw(~cx5uWP(XqfIW)cW11s7suSVl}4?kX&g$U zP|`Gpr4cM?-8tVIQ!ncu=f3kCF`y#go?E>c`qqy#DCN za?L>g4X~QV_cXSr@xB~J^!j5uF4^bT7}ddY>PE(_?EKOdnDxF-V^rvC%gEau#;EKZ zEZX!)gYwgSI~o;fuKucU)Lh7UU0V=5XBV$WXgu8lW_8gz?DgT2?dfU|__sq=E$o-g4MpyPQx{AT!3 zeP8F=MC-VoJ3O~!H^ZMvyCv3cN%9#bYM0q@U;8LcNRp4#o?E;@Y%H>mzFJS?tlK3k zSlo<#?}(PDaAa%pnPan7krnw15uN*3_ncFtI=|Wl8G3WeiYXgJZ|Fm>-?juj>tkF9 zGah^OZZpkidI)uXv8lIpvt0z^?on%3vSoUvIny)vC(S3m>c#|0(!A81>7|lPFPYSM zitmJC+OF*^4AoUNX~rV&E&O3II{sQ3)YE%j+?2m1qE(81+*EH`V%HAOw&QIbLNSMi zF)fPS!lnSfYU_+kQa!Z0W6mXxW;(;&+Vj@a>VQ^szfH@l zp}J-spH$vmE36nia=*TC)@b)oroUqXMYHBuM#G6qUK#SW|6XN$d+ z&L4pg{W)~sA8l*#2j;e_OIgR#(6KvU{qbeDTXdF=)Mc^$%&l|&H0v)ldFZ}BTO*g6 z+zmV<)pzh`8L!jz!hW2%-9759|TwplvzLDHnrJZHyz{d1hs__mNM)Yw~^C%L=WM$WahA@9AHoo1E1r+2La zmb|TB(YxznT5O*A?h4ymJwIjyn6S8ODx--+wEnP*)Ggs!22Imq$-l<;U;4FU18H|x zKgPDf9l|Z6OBw4rFIRLA?^bEi;Q6gCyzcPeY&lYJGUF}NUny6dw>tPKEk3u>U=v(Y z!nwy3io+tt_ibjxWZpk{-B|LHAA~O$CtK3vWb@&1;>Ug3J&q9Z&Og=7US9M(?cQf} z2)|7eWyT5I+RvCuc&_$JiOrf`ocQ-Y{HESLxA^(rr4t(%q?H>l58Hbt@5Ozqx2P0Y zUwDP?NcYT4S7k9joL+hK6X&S+RB=m&(=UIF@*h2(4^KcpoPHhP<;SDm(}mM3>l3!P za8BZ;er8LSML%xS($*_S{uyd3Zf8yQe&w}xAiS2P*9`CQUM$)W)?}kZZ8#9BWKx7% zvdxH(`+Yg}dum=96ONeZVW+9tmMYh)(+{TA>1(OW_j+}@9S)_R8LD%&y5=9Y-9me| zPj&hx2CO5Iv(9F{pekznz+<<%aCP7+a*sWsTEo4w^siY`v7$gBR1QkNQ0bj+ws~Lf zC{g?j=pMWDM%!7J^E~_b$zy%W3N0Jcp}NhX=D3E^;&#)R09(VTu@1V{T7Gc(LuVsZ z5&wPXD(iUiy{WUKw>I88(WxY?d&!Q?Rq1U(V`D73WsRP8@OIMGu{`85py+Kt;5%fm zV*!2g3Kxf4Y+iBq^m9`3ov89t>Wa*2twWhlT{G_AT%++3!)Ql)dru}p9m&*-b6Mcd z`6k8PoGtfD*x$j;DgCUp<9pC=+T_l?l%}_&*-yVV-OWUr{Rh+Z3vkbO^XW8qoDVh9 z(}U?;nI?_dct6f%no=R_)jK_$DU;mnNxv)QX3C_vOWDjc>5iIT=B~>$b;`KTH@%h? z9@($<%(r$pUgDXZ%SxY=A2Ll!F_9L^q)EOdIz0bnnsg08_ReLRWHWUx(`0QX^OA4U zC|~NAX)=uAX(Z8&s{7;Syg|w8)VWL7ZrO-VnlqdBYh!NY#h86*T7E)5lzI1ienkJe zo#!Whx$n|PeVP91OVn9EcE@r)VqW&a9j2^}xniC@rLI38SMP0byZsoXLa5P59wS?0Y9 zT9{`Kn}{b5zTnJG9x1%7S=&q=ad5z}w-vg6c`e&aYj@_2U%bt%?dpylDPH!-zT%H- zbG&Ph6jv?S*$c__4OuQ_>}JYRJu^efm@vrf3mwu=W@po$Cn-tGmW4X?Mg1$gflCN0 ztlhTF9E7$D24>@Kg8+`~bcK--f5* zad-sohp)q(a4Xyh*TPk>8@9v6a6W8;jZgJ6e3H%NI3?INd z@EiCgyb3>oA3!TS15d!i@C~>dZi5@)8n^;>z{SuEaj1tH2*EjU1}uYxPzZBjI!uCb zFal17LC_C+Lsw}3BYuUy!AI~uw85M3b9e=Q0Il#0JPr@RJ+K#UhU?%;xC}0aEf9kZ z5Qg*MOjr(!pb+N5X)qB+!!S4z`a>V+2JIhGmf^4PA^aZRg4f|c;D^u(--5^B0oVt( z!3}UV?1UC*h8V1eDp(B_PzuFxI!uRL7!AW24cf5a1f1n@{N zC*fhZ2kw9y;cD0k7sF#O6b3?H=mv*ApiID@;5~Q?UW1q6 zd+;ng2KU3Aa5L z79NHB;10L}u7qu{6&j%i&V>qC1of-nM3fE>t%&)+AG;r~G!ybdqJcj0Mx81})} zU=Qqo^I;>@z`3vjO5k*u0%PE0=np-h{XObS_z->vufdPu1$Y9!0k^|-up2IdIMl*w zSPsQ78**VJ42HhY8UFDuc?8u=iIe+w_eGjK0_6)uHFI2RVdbQl50 z!lAdQe&G#x5gvux;d0mnm9PwE!>P~@4*i-qg4f|Y@F3g-+n@o?h9Z~vLLAP9c`y=s!NJ!F8$1Vh!ey`l%3vA{hC{y~ufY%C0k{fcuo7m% zNnqgjuVDx7gDapO%3w0|hrj=v_87heUxV{uHOz&R;Ly)VQ+OV3hl}7`mBK-q_TU>mH3IWP!5{wZ+`55i8Ugt;&X{`Mb~Z@3pOfmJXS`oR0I z5QlIhL}398h5ve)YhWLo56j_H`1~id<8U8b2rFO|eEMVhgm4#Zf`xD*{P{bCT*I&Xvuo;SB0KEG{$_QKn%itvV@CWq6U^|q-5ctFQsr%qUSOCYuuV2KkPzTfC z^Y4*A;R;v*gW$K{r7r}v5QM*er@j4~umxtp=dGj-v_KxPSh>CR1U&0jl?KeqR$b~nbz>hErUVfam3I@Q_kCC?U*`xHiVGjIiKjDM^u>TR-XL#>n z;tmGDgAdVu!s`!G$HS)&P?lf_Ja9kxAHM$$;vRl=A8805-pf7V@AuFTf=|EBvkH8= z4>SDzZt5ube|J$o!!Pfo?+Y*N#s9GP4)QZ>y&b>Y*51App175=2p8T$SieTzg|FR= zTQ_kYzJ4S9h8u7PZu=_r-1W2@&~hDR@>9 z?ZM^k?ZaWgZo;~YxZO#fxr}t$LD|_(v$Ku5?NaPr(vHKVKODMxi2$ZF&{? zsFM4wr5vxJT%SumSxwrnqCbBY`SncdpEIbt%ZZ!iw1dlt_fq0xF)So*7qqwkY(DjG zA@xW;`E?$3z#Q7gS=2`}=toT>k4_;UP6ouo3hcF@Eh{@r-#~~|Hq;B$lng}Jb0*m*@uVPcf5C~eNWpV+J{5! zLta1Be$#npL3}Fjj}`Slja|4e|N^A_TP^?)IRj&L+#s-ImG=B z@eKSq?cnF_J$~{z<>B-8+&e#Se{=We?fV)(Cw@L}zjylQ?ZwA`-hSY3pHW|Z*1rGF z&)Q$w_*whhIiGR;XOzKDNrz9{A3N?-{PVB&D<}MmeDzQIHlJ|*6TTj42 zV&_9-8?=Icc@QvXoG}2IV_tr_x4HlRp61#S8oB9iHV(-)>(+HMiC4Q~r>j}|Q5UoD z+AgN3NTWhs%=f<6+03}AGwX~yn<-N|o7~==%`+c#GH1Wk33ob~)mL{ir*7)RzJQ&~ zh=rZZKc;pv!-sb=+jBZ`eJ69l!7TIk+gawM*RsrzA7+`KK9gleKayom*q3E)zB$X> zdUci=bQyEoF3d9LCbG=Hx-2ukI?LR&It%|~ne&!rnTHo-F^@6J95*}544al^YA0ry zcgJKAhAh)KG|QZSLY8@SK$bc7*er8n?<`Z$J2l)oU zpBRVw(3tPOZ_HJ{H>Rq&URn1PQOGk(7@OCILk>w|{)G3JB&mZM>K1&3E9Z+Zd_6)iBqMtr2cE=7}4PS#|?kgkI0`tLqHuV9e)x zjCuNMW42sn%-pY#VpkgT#^uI5yxW*vyYTx?_D{den5jFA8MfV+ehm9)8eOML2!0DO za4}J37*e-n61XFZpO_m#@x8sm~U+|=C@7QgUJbFLafKSHbz`*BnLMd zGXoM#&wISVn7`K>GYeYkjQQ~fV+KIgdi)+?{148lHRiDz;se&LGv<3?V}`@FYGeLT zMclw+mByS1mxT!HT4UD2fi=eD!xQK6T?Dw}T;dk?ti~&Hcc_Dr@Vf%?22?-}yqr%yf@0_b-_0}T637Ds zt@H3B6hLSA!Rdq#7Q->{^SNxX3+KXc_+Sos3z}dKbcUbsM&^204I|+%v&b{B4VJ=S zcy}go4;R2f7zn?gVa%g&F_gj(_~UeAo`KzPHjIUToyI-jHfVr6=m+mjGv+C{9L|GD z&=r0)6+gl@I17T%8Qz>?%pKtN32#rvziA85z61BdS0DkaARk755~ek=mdX0g**e_hezRdxEwY?B`kwEFd7CxC-}>7$}#*1o`kz$4_pKr;A|*{ zsW2RlfzOAL@8L~&37&*~a4lQ{Q8*7uVK$6~!O$K45g=Uf3wRM8hr8igxD+-*2+AN2 zav=aYVBp|TdIN9(T46uj3D>|S5Q8cxha#8;BViz9!zU-R)h_%BUWRYO!*B;&1D8Sq z!f+;(z$_RKC&Mw21%Eq<@(jO(AH#F-FzkhEVFzr6^{^V2K|V}{Q(-XlhV~(pF?bK& zfS3Sc^ng8=l09`N}I_!IsBzlHD%44|8EEjE50$A{+<3pcDLSAn61j!rSmB zyb3>p@4&a@BdmuiSPkm(FNFn=2Qy(ZjD-F;Ujnteg|*BtMFs^9()^~gh${Ta2MPHUxlk+7hD2cAp!MJ18ZRwltU>L zLmte6DG-EHApj>pf9M0*kOiL}M;?Jc!w2vVyam62pTdved+=>|3Lb?A;OlS)+zi*j zS70Yx0_Q^$L?HrIa4wt)D_{u}Lmte6X)qDSz$tJt41#{p2eKgxKI=!i!a?{Wya#RY zEBFQc6n+FR!t?Mgcmf`VZ@}GfJKO}(>EwNM4;!C6oaOJN}t!s##* zrou!R3nO4CoB#tL2YNv_$b!#~rH+BW!bk82cn5w1Z@|ytr|@I=KD5HK@FYA655m20 z7u*gv!}V}ATn;@C3Sl11f@v@b#>1&_3Y-ilzyLTF zdP6pJhC?~zZ}>a>6+VIw;9d9~{2E?|pTR5eBlteF!gKHxJPwb*{csQ51-HS?@Kx9Y zSHdpX4j04uuo>de0PA5LRKj_1Hk<*=p%fOve8`76FaxGSE{uoKFaiQF1O`EW$bsI_ z9l8LUVvmgTbt`%T=DmT+c0?^*r=8w5o1K|@ILA4Ri#>JfOPcSUnh&TQ>bx+g%?hM1#di<)zsQ`5SC|h1 z9lx!peV$sr!(0mpz<%)eHC&4>4D3xi?z@?L%68K_e0zqQjhOcbwws(>zOBF<^Rju{ z?HqG`Z?P3!-?Pgp*lzejU(kM{j}@l&8-2-d+Xb{BE>IC|s;XtRk>W~em^%~q=5JTp zY7*n*;_|XkEL3mvgC-@)p3=aRTP1stuxz%ZFVQu!-8!EvaOpqA&V+7e7e&oCw9|gK zc!n`bp7bl2?wD!DWhJqnkyvl1dDhH;Pj;ce`mR z-tPN%i$bNiv^Sry#pYDcugtu3dEA|APCutTSGd-Cc5I;8%*zw|nVn-aS)K#kpYO=VZ#Lf=P^WtS~TD-J*d9CG(#LL148!d{H*4f)lAQdOX ze_EW#|K5TI?UbUDynmw0=ecS3Zt?EjO1k`;eD2-VrA6aZ%1mK;{w`!gz;H}y<;9cM z3u>1rKTDBT8Tn1=kbcgl$OM;Ez8f|?)yZTaHMJp^mq6|YN=Ge)>}lG(u;rzNZ7+I& zaFyl%+pr~bn&PzOwCyIhD4EZy!-PwIJ^I~k)E>ppx;i7=UYPuBlXgCpcL>sEn|bWL z(=yQUPc5Hu{8O*axNhlo^L>x+ym5gM2QceL^J9O#`Fm#milqyeE|?Wqm)v;L?cbQ( z&au+&Ppj_&u>BF+deyUU?u0<0RDUx778&yKExW*{U?k9qoEeu}NJ` zCCfgyo>{w~S?5@^teMo)#>}p%TjMXBcK4de0;Ud?seSvQteS5oUdzL!q8QN>iYoA9xM>~Q! z_gfBmIKQBg&G zHf`S0yft^yE-F7bCTc)n>tKS*5d zLEl5XcwpLL^AP)iYqe%sT{JOkR#PKi!>z7}DiPS_S3dFgIPEC+bA8Tq;^8#%6|xMe zy}S)F&pY0N-0K~0X=$MZUzFGOt%TXXggnNc%))+acq!LF8R*zrr1q!KTU(x9x-bJO z!=%~!?p$Zy>}HzM_Hb3O1KQn%q4qE7d7&mIN8P?!a{C& zB;!x}pQj(st>48U@h-bB`oS~Y^(qHBSMB0^AMUtsKj+z9rsZkuKLxG3SSwqGFIL!{ znec^ED(u$Dbnmr4@vK?ek4VX=82qC4sqXD1U(~)Vd!NGM9_7(>iOqcEH03wGZ9Xg7 zpk0}C43AWK@q}Cu)750Mq>r`Tba_*3U8qVKZ*ADw-Mfx51

t1s1`-NwTaB%(p?$!kI~`&nbq|5XKI!bfSQi-nIul)kB)`mY0pcG5 z5I2XyUuQ5#jtEHl0ZG3C$)pQ|M9p7(F^T>f0u|#l0U3X%7=ojhX7mcKh-Lcqo~}`z z*wNJd1476%dSlohkD4s>G1Z=)YPByv)WsG`-JY@h&?xNHU;w;u1Zl30{d!3*h}D=A z&qm)%QTIium7e-#GZH(I8ae zer7%1~!CMYG>|m%Sw3Slfk`w*=_)^1~if z4?s?XCE7JAV^2m0?Wi#?i|$OtvJ*@-8Xr1;Ow@P;xw=)BCglW<<05Kw*yLfdR%NmX zZM!A3_TYL>Vl@GMGxK1g3{+bBTQae{`+uB-pEOn zmLUnT6JBFuq~EJbOv^t2>*uXj=||I<6_SP32M!CY+4zUpyJ=oXH_N9#G2(^(t5uao3G!wd0> zitY05iM{8Qx8td?chfUICKoH`yJ@lGX-rstq{i5BZ^p+p<^+tV*-OS!qYngAU~&z0 zt4ea=bdj3=Fxa|BKH)?dZocaBLW1EvlH(k~r;E%tD=2-fz^ue*ctIdgmSw%k=o;Hz zm(e{QJ!}a5sy>PT3aeU{KQ-P1gZ&9eDjxfxP8v96eS0|l408+ue4b}nKfeF>#SUdH zKP+=rlH5T*9Q0!4{~8#Ou`mBj?C2#IMf#sr+;!Q><%ea`d+V_82Ud*op4hvo8K=E! z({Lh9iU=0Gs;5H%t9NgWd9n494ErDejXHnO6XU(C4xO6J-Xb>MB4P{Jvr;W~urMY8 z>kVVuq_Y-_#ATeHI1EM2fN99@pryhyfxWSh{oW2S2fCQ)%oyg!Vu!(8cKPp)%0DZJ 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�`^vLC;k<;i=x~u59{6_b1x(&4I-b-p#Kl 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�NfV018?h864z65Jscy#)58v1 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%0DrJ)Pj-G^HaVRfuq||AoqY%oP(j!4;%o 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 U!+Cykm)zov5ikzdGG`=Zk`>KIQ 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 z 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 YGq`GimD?|a#(#W<5s?PcLW<6K`{4GBh(!yMT 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%0D^9+uU= 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 <(6xx# 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

l^YS{@AC1VvcUUac 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¥7{?n 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